diff options
-rw-r--r-- | src/libsystemd-network/dhcp6-network.c | 22 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp6-client.c | 19 | ||||
-rw-r--r-- | src/libsystemd-network/sd-ndisc.c | 2 | ||||
-rw-r--r-- | src/libsystemd-network/test-dhcp6-client.c | 6 | ||||
-rw-r--r-- | src/network/networkd-address.c | 6 | ||||
-rw-r--r-- | src/network/networkd-dhcp6.c | 3 | ||||
-rw-r--r-- | src/network/networkd-link.c | 20 | ||||
-rw-r--r-- | src/network/networkd-link.h | 4 | ||||
-rw-r--r-- | src/network/networkd-ndisc.c | 6 | ||||
-rw-r--r-- | src/systemd/sd-dhcp6-client.h | 1 |
10 files changed, 58 insertions, 31 deletions
diff --git a/src/libsystemd-network/dhcp6-network.c b/src/libsystemd-network/dhcp6-network.c index 318ee9c4b4..fd2d60c9d5 100644 --- a/src/libsystemd-network/dhcp6-network.c +++ b/src/libsystemd-network/dhcp6-network.c @@ -33,36 +33,32 @@ #include "socket-util.h" int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { - struct in6_pktinfo pktinfo = { - .ipi6_ifindex = index, - }; union sockaddr_union src = { .in6.sin6_family = AF_INET6, .in6.sin6_port = htobe16(DHCP6_PORT_CLIENT), - .in6.sin6_addr = IN6ADDR_ANY_INIT, + .in6.sin6_scope_id = index, }; _cleanup_close_ int s = -1; int r, off = 0, on = 1; - if (local_address) - memcpy(&src.in6.sin6_addr, local_address, - sizeof(src.in6.sin6_addr)); + assert(index > 0); + assert(local_address); + + src.in6.sin6_addr = *local_address; - s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - IPPROTO_UDP); + s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_UDP); if (s < 0) return -errno; - r = setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &pktinfo, - sizeof(pktinfo)); + r = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); if (r < 0) return -errno; - r = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); + r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off)); if (r < 0) return -errno; - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off)); + r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (r < 0) return -errno; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index a443bb3a7a..801331d270 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -32,6 +32,7 @@ #include "dhcp6-lease-internal.h" #include "dhcp6-protocol.h" #include "fd-util.h" +#include "in-addr-util.h" #include "network-internal.h" #include "random-util.h" #include "string-table.h" @@ -46,6 +47,7 @@ struct sd_dhcp6_client { sd_event *event; int event_priority; int index; + struct in6_addr local_address; uint8_t mac_addr[MAX_MAC_ADDR_LEN]; size_t mac_addr_len; uint16_t arp_type; @@ -133,6 +135,18 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) { return 0; } +int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address) { + assert_return(client, -EINVAL); + assert_return(local_address, -EINVAL); + assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0, -EINVAL); + + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + + client->local_address = *local_address; + + return 0; +} + int sd_dhcp6_client_set_mac( sd_dhcp6_client *client, const uint8_t *addr, size_t addr_len, @@ -1135,9 +1149,10 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { assert_return(client, -EINVAL); assert_return(client->event, -EINVAL); assert_return(client->index > 0, -EINVAL); + assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0, -EINVAL); if (!IN_SET(client->state, DHCP6_STATE_STOPPED)) - return -EALREADY; + return -EBUSY; r = client_reset(client); if (r < 0) @@ -1151,7 +1166,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { if (r < 0) return r; - r = dhcp6_network_bind_udp_socket(client->index, NULL); + r = dhcp6_network_bind_udp_socket(client->index, &client->local_address); if (r < 0) return r; diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 0881973e7f..6703d87bc4 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -628,7 +628,7 @@ int sd_ndisc_router_discovery_start(sd_ndisc *nd) { assert(nd->event); if (nd->state != NDISC_STATE_IDLE) - return -EINVAL; + return -EBUSY; if (nd->index < 1) return -EINVAL; diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index 17ed6d58f3..9e05fde8f6 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -562,6 +562,7 @@ static void test_client_information_cb(sd_dhcp6_client *client, int event, sd_event *e = userdata; sd_dhcp6_lease *lease; struct in6_addr *addrs; + struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } }; char **domains; assert_se(e); @@ -590,6 +591,8 @@ static void test_client_information_cb(sd_dhcp6_client *client, int event, assert_se(sd_dhcp6_client_set_callback(client, test_client_solicit_cb, e) >= 0); + assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0); + assert_se(sd_dhcp6_client_start(client) >= 0); } @@ -701,6 +704,7 @@ int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { static int test_client_solicit(sd_event *e) { sd_dhcp6_client *client; usec_t time_now = now(clock_boottime_or_monotonic()); + struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } }; int val = true; if (verbose) @@ -729,6 +733,8 @@ static int test_client_solicit(sd_event *e) { time_now + 2 * USEC_PER_SEC, 0, test_hangcheck, NULL) >= 0); + assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0); + assert_se(sd_dhcp6_client_start(client) >= 0); sd_event_loop(e); diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index c0562e5788..1ce1f4d8d6 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -347,9 +347,9 @@ int address_update(Address *address, unsigned char flags, unsigned char scope, s link_check_ready(address->link); if (address->family == AF_INET6 && - in_addr_is_link_local(AF_INET6, &address->in_addr) && - !address->link->ipv6ll_address) { - r = link_ipv6ll_gained(address->link); + in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 && + in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) { + r = link_ipv6ll_gained(address->link, &address->in_addr.in6); if (r < 0) return r; } diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index f83ff54369..e67e51f7ef 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -211,6 +211,9 @@ int dhcp6_configure(Link *link) { assert(link); + if (link->dhcp6_client) + return 0; + r = sd_dhcp6_client_new(&client); if (r < 0) return r; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index a415035887..01d5942ce5 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -615,7 +615,7 @@ void link_check_ready(Link *link) { return; if (link_ipv6ll_enabled(link)) - if (!link->ipv6ll_address) + if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) > 0) return; if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) && @@ -1260,11 +1260,16 @@ static int link_acquire_ipv6_conf(Link *link) { if (link_dhcp6_enabled(link)) { assert(link->dhcp6_client); + assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0); log_link_debug(link, "Acquiring DHCPv6 lease"); + r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address); + if (r < 0 && r != -EBUSY) + return log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m"); + r = sd_dhcp6_client_start(link->dhcp6_client); - if (r < 0) + if (r < 0 && r != -EBUSY) return log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease: %m"); } @@ -1274,7 +1279,7 @@ static int link_acquire_ipv6_conf(Link *link) { log_link_debug(link, "Discovering IPv6 routers"); r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery); - if (r < 0) + if (r < 0 && r != -EBUSY) return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m"); } @@ -2089,7 +2094,8 @@ static int link_configure(Link *link) { return r; } - if (link_dhcp6_enabled(link)) { + if (link_dhcp6_enabled(link) || + link_ipv6_accept_ra_enabled(link)) { r = dhcp6_configure(link); if (r < 0) return r; @@ -2121,7 +2127,7 @@ static int link_configure(Link *link) { if (r < 0) return r; - if (link->ipv6ll_address) { + if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) == 0) { r = link_acquire_ipv6_conf(link); if (r < 0) return r; @@ -2472,14 +2478,14 @@ failed: return r; } -int link_ipv6ll_gained(Link *link) { +int link_ipv6ll_gained(Link *link, const struct in6_addr *address) { int r; assert(link); log_link_info(link, "Gained IPv6LL"); - link->ipv6ll_address = true; + link->ipv6ll_address = *address; link_check_ready(link); if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) { diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index b564bcbca0..aa2235b11d 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -69,6 +69,7 @@ struct Link { char *ifname; char *state_file; struct ether_addr mac; + struct in6_addr ipv6ll_address; uint32_t mtu; struct udev_device *udev_device; @@ -101,7 +102,6 @@ struct Link { sd_ipv4ll *ipv4ll; bool ipv4ll_address:1; bool ipv4ll_route:1; - bool ipv6ll_address:1; bool static_configured; @@ -144,7 +144,7 @@ int link_save(Link *link); int link_carrier_reset(Link *link); bool link_has_carrier(Link *link); -int link_ipv6ll_gained(Link *link); +int link_ipv6ll_gained(Link *link, const struct in6_addr *address); int link_set_mtu(Link *link, uint32_t mtu); int link_set_hostname(Link *link, const char *hostname); diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 2ff87c32eb..ce9e513ceb 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -75,7 +75,7 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr address->family = AF_INET6; address->in_addr.in6 = *prefix; if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0) - memcpy(&address->in_addr.in6 + 8, &link->network->ipv6_token + 8, 8); + memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8); else { /* see RFC4291 section 2.5.1 */ address->in_addr.in6.__in6_u.__u6_addr8[8] = link->mac.ether_addr_octet[0]; @@ -159,7 +159,7 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a dhcp6_request_address(link); r = sd_dhcp6_client_start(link->dhcp6_client); - if (r < 0 && r != -EALREADY) + if (r < 0 && r != -EBUSY) log_link_warning_errno(link, r, "Starting DHCPv6 client on NDisc request failed: %m"); } @@ -205,7 +205,7 @@ static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { dhcp6_request_address(link); r = sd_dhcp6_client_start(link->dhcp6_client); - if (r < 0 && r != -EALREADY) + if (r < 0 && r != -EBUSY) log_link_warning_errno(link, r, "Starting DHCPv6 client after NDisc timeout failed: %m"); link->ndisc_configured = true; diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 9f0e92806e..0ca6c07de4 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -49,6 +49,7 @@ int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_cb_t cb, void *userdata); int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); +int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address); int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, |