Try DHCPv6 if router solicitation times out as a link without routers may use DHCPv6 according to RFC 4862 section 5.5.2. --- src/libsystemd-network/sd-dhcp6-client.c | 70 +++++++++++++++++++++++++++++++- src/systemd/sd-dhcp6-client.h | 1 + 2 files changed, 69 insertions(+), 2 deletions(-)
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 5063d4a..fbf3211 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -27,6 +27,8 @@ #include "sd-dhcp6-client.h" #include "dhcp6-protocol.h" +#include "dhcp6-internal.h" +#include "icmp6-nd.h" struct sd_dhcp6_client { RefCount n_ref; @@ -36,6 +38,7 @@ struct sd_dhcp6_client { int event_priority; int index; struct ether_addr mac_addr; + icmp6_nd *ra; sd_dhcp6_client_cb_t cb; void *userdata; }; @@ -103,6 +106,30 @@ static sd_dhcp6_client *client_stop(sd_dhcp6_client *client, int error) { return client; } +static void dhcp6_receive_router_advertisment(icmp6_nd *nd, int event, + void *userdata) +{ + sd_dhcp6_client *client = userdata; + + if (event < 0) { + log_dhcp6_client(client, "Router Advertisment failed with " + "%d %s", event, strerror(-event)); + client_notify(client, event); + return; + } + + switch (event) { + case ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE: + case ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER: + client_stop(client, DHCP6_EVENT_NO_STATEFUL_CONFIGURATION); + return; + + case ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT: + case ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED: + break; + } +} + int sd_dhcp6_client_stop(sd_dhcp6_client *client) { client_stop(client, DHCP6_EVENT_STOP); @@ -112,13 +139,50 @@ int sd_dhcp6_client_stop(sd_dhcp6_client *client) int sd_dhcp6_client_start(sd_dhcp6_client *client) { - int r = 0; + _cleanup_icmp6_nd_free_ icmp6_nd *nd = NULL; + int r; + struct ether_addr *mac_addr = NULL; + struct ether_addr unset = { }; assert_return(client, -EINVAL); assert_return(client->event, -EINVAL); assert_return(client->index > 0, -EINVAL); - return r; + r = icmp6_nd_new(&nd); + if (r < 0) + return r; + + r = icmp6_nd_attach_event(nd, client->event, client->event_priority); + if (r < 0) + return r; + + r = icmp6_nd_set_index(nd, client->index); + if (r < 0) + return r; + + if (memcmp(&client->mac_addr, &unset, sizeof(unset))) + mac_addr = &client->mac_addr; + + r = icmp6_nd_set_mac(nd, mac_addr); + if (r < 0) + return r; + + r = icmp6_nd_set_callback(nd, dhcp6_receive_router_advertisment, + client); + if (r < 0) + return r; + + r = icmp6_router_solicitation_start(nd); + if (r < 0) + return r; + + client->ra = icmp6_nd_unref(client->ra); + client->ra = nd; + nd = NULL; + + client->state = DHCP6_STATE_RS; + + return 0; } int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, @@ -171,6 +235,8 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) { sd_dhcp6_client_detach_event(client); + client->ra = icmp6_nd_unref(client->ra); + free(client); return NULL; diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 4965011..c64ad16 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -28,6 +28,7 @@ enum { DHCP6_EVENT_STOP = 0, + DHCP6_EVENT_NO_STATEFUL_CONFIGURATION = 10, }; typedef struct sd_dhcp6_client sd_dhcp6_client; -- 1.9.1 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel