From 18df6cca092743a07be8e0f05d0a9ef941957b66 Mon Sep 17 00:00:00 2001 From: Hans Dedecker Date: Thu, 29 Jun 2017 15:35:21 +0200 Subject: [PATCH] treewide: rework logic to retrieve IPv6 interface addresses Retrieve IPv6 interface addresses when the interface gets created; this allows to get rid of the IPv6 address dump logic in ndp.c. Add IPv4 address support in odhcp_ipaddr struct. Signed-off-by: Hans Dedecker --- src/config.c | 13 +++++++++++-- src/dhcpv6-ia.c | 13 +++++++------ src/dhcpv6.c | 36 +++++++++++++++++++++++++++--------- src/dhcpv6.h | 2 +- src/ndp.c | 53 ++++++++--------------------------------------------- src/odhcpd.c | 41 +++++++++++++++++++++++++++++++++++------ src/odhcpd.h | 13 ++++++++----- src/router.c | 31 ++++++++++++++++--------------- 8 files changed, 113 insertions(+), 89 deletions(-) diff --git a/src/config.c b/src/config.c index 1276b6f..e6f2382 100644 --- a/src/config.c +++ b/src/config.c @@ -388,6 +388,8 @@ err: int config_parse_interface(void *data, size_t len, const char *name, bool overwrite) { struct blob_attr *tb[IFACE_ATTR_MAX], *c; + bool get_addrs = false; + blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, data, len); if (tb[IFACE_ATTR_INTERFACE]) @@ -409,7 +411,7 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr set_interface_defaults(iface); list_add(&iface->head, &interfaces); - overwrite = true; + get_addrs = overwrite = true; } const char *ifname = NULL; @@ -439,6 +441,14 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr if ((iface->ifindex = if_nametoindex(iface->ifname)) <= 0) goto err; + if (get_addrs) { + ssize_t len = odhcpd_get_interface_addresses(iface->ifindex, + true, &iface->ia_addr); + + if (len > 0) + iface->ia_addr_len = len; + } + iface->inuse = true; if ((c = tb[IFACE_ATTR_DYNAMICDHCP])) @@ -823,7 +833,6 @@ void odhcpd_reload(void) close_interface(i); } - ndp_handle_addr6_dump(); uci_unload(uci, dhcp); uci_free_context(uci); } diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c index c2221d8..502373f 100644 --- a/src/dhcpv6-ia.c +++ b/src/dhcpv6-ia.c @@ -248,7 +248,7 @@ void dhcpv6_enum_ia_addrs(struct interface *iface, struct dhcpv6_assignment *c, if (!valid_addr(&addrs[i], now)) continue; - addr = addrs[i].addr; + addr = addrs[i].addr.in6; pref = addrs[i].preferred; valid = addrs[i].valid; if (prefix == 128) { @@ -444,7 +444,7 @@ static void apply_lease(struct interface *iface, struct dhcpv6_assignment *a, bo size_t addrlen = (a->managed) ? (size_t)a->managed_size : iface->ia_addr_len; for (size_t i = 0; i < addrlen; ++i) { - struct in6_addr prefix = addrs[i].addr; + struct in6_addr prefix = addrs[i].addr.in6; prefix.s6_addr32[1] |= htonl(a->assigned); prefix.s6_addr32[2] = prefix.s6_addr32[3] = 0; odhcpd_setup_route(&prefix, (a->managed_size) ? addrs[i].prefix : a->length, @@ -661,11 +661,12 @@ void dhcpv6_ia_preupdate(struct interface *iface) apply_lease(iface, c, false); } -void dhcpv6_ia_postupdate(struct interface *iface, time_t now) +void dhcpv6_ia_postupdate(struct interface *iface) { if (iface->dhcpv6 != RELAYD_SERVER) return; + time_t now = odhcpd_time(); int minprefix = -1; for (size_t i = 0; i < iface->ia_addr_len; ++i) { if (iface->ia_addr[i].preferred > (uint32_t)now && @@ -802,7 +803,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, .preferred = htonl(prefix_pref), .valid = htonl(prefix_valid), .prefix = (a->managed_size) ? addrs[i].prefix : a->length, - .addr = addrs[i].addr + .addr = addrs[i].addr.in6, }; p.addr.s6_addr32[1] |= htonl(a->assigned); p.addr.s6_addr32[2] = p.addr.s6_addr32[3] = 0; @@ -820,7 +821,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, struct dhcpv6_ia_addr n = { .type = htons(DHCPV6_OPT_IA_ADDR), .len = htons(sizeof(n) - 4), - .addr = addrs[i].addr, + .addr = addrs[i].addr.in6, .preferred = htonl(prefix_pref), .valid = htonl(prefix_valid) }; @@ -879,7 +880,7 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status, if (!valid_addr(&addrs[i], now)) continue; - struct in6_addr addr = addrs[i].addr; + struct in6_addr addr = addrs[i].addr.in6; if (ia->type == htons(DHCPV6_OPT_IA_PD)) { addr.s6_addr32[1] |= htonl(a->assigned); addr.s6_addr32[2] = addr.s6_addr32[3] = 0; diff --git a/src/dhcpv6.c b/src/dhcpv6.c index 3128968..4ecb54a 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -90,9 +90,6 @@ int setup_dhcpv6_interface(struct interface *iface, bool enable) if (iface->dhcpv6 == RELAYD_SERVER) setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &server, sizeof(server)); - if (iface->dhcpv6 != RELAYD_RELAY || !iface->master) - ndp_rqs_addr6_dump(); - iface->dhcpv6_event.uloop.fd = sock; iface->dhcpv6_event.handle_dgram = handle_dhcpv6; odhcpd_register(&iface->dhcpv6_event); @@ -336,7 +333,7 @@ static void handle_client_request(void *addr, void *data, size_t len, if (IN6_IS_ADDR_UNSPECIFIED(&cerid.addr)) { struct odhcpd_ipaddr *addrs; - ssize_t len = odhcpd_get_interface_addresses(0, &addrs); + ssize_t len = odhcpd_get_interface_addresses(0, true, &addrs); for (ssize_t i = 0; i < len; ++i) if (IN6_IS_ADDR_UNSPECIFIED(&cerid.addr) @@ -483,6 +480,26 @@ static void relay_server_response(uint8_t *data, size_t len) odhcpd_send(iface->dhcpv6_event.uloop.fd, &target, &iov, 1, iface); } +static struct odhcpd_ipaddr *relay_link_address(struct interface *iface) +{ + struct odhcpd_ipaddr *addr = NULL; + time_t now = odhcpd_time(); + + for (size_t i = 0; i < iface->ia_addr_len; i++) { + if (iface->ia_addr[i].valid <= (uint32_t)now) + continue; + + if (iface->ia_addr[i].preferred > (uint32_t)now) { + addr = &iface->ia_addr[i]; + break; + } + + if (!addr || (iface->ia_addr[i].valid > addr->valid)) + addr = &iface->ia_addr[i]; + } + + return addr; +} // Relay client request (regular DHCPv6-relay) static void relay_client_request(struct sockaddr_in6 *source, @@ -522,18 +539,19 @@ static void relay_client_request(struct sockaddr_in6 *source, memcpy(&hdr.interface_id_data, &ifindex, sizeof(ifindex)); // Detect public IP of slave interface to use as link-address - struct odhcpd_ipaddr *ip = NULL; - if (odhcpd_get_interface_addresses(iface->ifindex, &ip) < 1) { + struct odhcpd_ipaddr *ip = relay_link_address(iface); + if (!ip) { // No suitable address! Is the slave not configured yet? // Detect public IP of master interface and use it instead // This is WRONG and probably violates the RFC. However // otherwise we have a hen and egg problem because the // slave-interface cannot be auto-configured. - if (odhcpd_get_interface_addresses(master->ifindex, &ip) < 1) + ip = relay_link_address(master); + if (!ip) return; // Could not obtain a suitable address } - memcpy(&hdr.link_address, &ip[0].addr, sizeof(hdr.link_address)); - free(ip); + + memcpy(&hdr.link_address, &ip->addr.in6, sizeof(hdr.link_address)); struct sockaddr_in6 dhcpv6_servers = {AF_INET6, htons(DHCPV6_SERVER_PORT), 0, ALL_DHCPV6_SERVERS, 0}; diff --git a/src/dhcpv6.h b/src/dhcpv6.h index b38ae82..e58cb69 100644 --- a/src/dhcpv6.h +++ b/src/dhcpv6.h @@ -190,4 +190,4 @@ void dhcpv6_enum_ia_addrs(struct interface *iface, struct dhcpv6_assignment *c, dhcpv6_binding_cb_handler_t func, void *arg); void dhcpv6_write_statefile(void); void dhcpv6_ia_preupdate(struct interface *iface); -void dhcpv6_ia_postupdate(struct interface *iface, time_t now); +void dhcpv6_ia_postupdate(struct interface *iface); diff --git a/src/ndp.c b/src/ndp.c index 8488fc5..94b7e96 100644 --- a/src/ndp.c +++ b/src/ndp.c @@ -48,7 +48,6 @@ static void handle_rtnl_event(struct odhcpd_event *ev); static int cb_rtnl_valid(struct nl_msg *msg, void *arg); static void catch_rtnl_err(struct odhcpd_event *e, int error); -static int addr6_dump_rqs = 0; static int ping_socket = -1; static struct event_socket rtnl_event = { .ev = { @@ -150,11 +149,11 @@ static void dump_neigh_table(const bool proxy) nlmsg_free(msg); } -static void dump_addr6_table(void) +static void dump_addr_table(bool v6) { struct nl_msg *msg; struct ifaddrmsg ifa = { - .ifa_family = AF_INET6, + .ifa_family = v6 ? AF_INET6 : AF_INET, }; msg = nlmsg_alloc_simple(RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP); @@ -168,20 +167,6 @@ static void dump_addr6_table(void) nlmsg_free(msg); } -void ndp_handle_addr6_dump(void) -{ - if (!addr6_dump_rqs) - return; - - dump_addr6_table(); - addr6_dump_rqs = 0; -} - -inline void ndp_rqs_addr6_dump(void) -{ - addr6_dump_rqs++; -} - int setup_ndp_interface(struct interface *iface, bool enable) { int ret = 0, procfd; @@ -253,8 +238,6 @@ int setup_ndp_interface(struct interface *iface, bool enable) dump_neigh_table(false); else dump_neigh = false; - - ndp_rqs_addr6_dump(); } if (dump_neigh) @@ -340,38 +323,18 @@ static void setup_route(struct in6_addr *addr, struct interface *iface, bool add odhcpd_setup_route(addr, 128, iface, NULL, 1024, add); } -// compare prefixes -static int prefixcmp(const void *va, const void *vb) -{ - const struct odhcpd_ipaddr *a = va, *b = vb; - uint32_t a_pref = IN6_IS_ADDR_ULA(&a->addr) ? 1 : a->preferred; - uint32_t b_pref = IN6_IS_ADDR_ULA(&b->addr) ? 1 : b->preferred; - return (a_pref < b_pref) ? 1 : (a_pref > b_pref) ? -1 : 0; -} - // Check address update -static void check_addr_updates(struct interface *iface) +static void check_addr6_updates(struct interface *iface) { struct odhcpd_ipaddr *addr = NULL; - time_t now = odhcpd_time(); - ssize_t len = odhcpd_get_interface_addresses(iface->ifindex, &addr); + ssize_t len = odhcpd_get_interface_addresses(iface->ifindex, true, &addr); if (len < 0) return; - qsort(addr, len, sizeof(*addr), prefixcmp); - - for (int i = 0; i < len; ++i) { - if (addr[i].preferred < UINT32_MAX - now) - addr[i].preferred += now; - - if (addr[i].valid < UINT32_MAX - now) - addr[i].valid += now; - } - bool change = len != (ssize_t)iface->ia_addr_len; for (ssize_t i = 0; !change && i < len; ++i) - if (!IN6_ARE_ADDR_EQUAL(&addr[i].addr, &iface->ia_addr[i].addr) || + if (!IN6_ARE_ADDR_EQUAL(&addr[i].addr.in6, &iface->ia_addr[i].addr.in6) || (addr[i].preferred > 0) != (iface->ia_addr[i].preferred > 0) || addr[i].valid < iface->ia_addr[i].valid || addr[i].preferred < iface->ia_addr[i].preferred) @@ -385,7 +348,7 @@ static void check_addr_updates(struct interface *iface) iface->ia_addr_len = len; if (change) - dhcpv6_ia_postupdate(iface, now); + dhcpv6_ia_postupdate(iface); if (change) { syslog(LOG_INFO, "Raising SIGUSR1 due to address change on %s", iface->ifname); @@ -477,7 +440,7 @@ static int cb_rtnl_valid(struct nl_msg *msg, _unused void *arg) syslog(LOG_DEBUG, "Netlink %s %s%%%s", true ? "newaddr" : "deladdr", ipbuf, iface->ifname); - check_addr_updates(iface); + check_addr6_updates(iface); if (iface->ndp != RELAYD_RELAY) break; @@ -562,7 +525,7 @@ static void catch_rtnl_err(struct odhcpd_event *e, int error) if (nl_socket_set_buffer_size(ev_sock->sock, ev_sock->sock_bufsize, 0)) goto err; - dump_addr6_table(); + dump_addr_table(true); return; err: diff --git a/src/odhcpd.c b/src/odhcpd.c index ee628a5..6f38d5c 100644 --- a/src/odhcpd.c +++ b/src/odhcpd.c @@ -222,6 +222,7 @@ ssize_t odhcpd_send(int socket, struct sockaddr_in6 *dest, struct addr_info { int ifindex; + int af; struct odhcpd_ipaddr **addrs; int pending; ssize_t ret; @@ -240,6 +241,7 @@ static int cb_valid_handler(struct nl_msg *msg, void *arg) ifa = NLMSG_DATA(hdr); if (ifa->ifa_scope != RT_SCOPE_UNIVERSE || + (ctxt->af != ifa->ifa_family) || (ctxt->ifindex && ifa->ifa_index != (unsigned)ctxt->ifindex)) return NL_SKIP; @@ -293,12 +295,21 @@ static int cb_error_handler(_unused struct sockaddr_nl *nla, struct nlmsgerr *er return NL_STOP; } +// compare prefixes +static int prefixcmp(const void *va, const void *vb) +{ + const struct odhcpd_ipaddr *a = va, *b = vb; + uint32_t a_pref = IN6_IS_ADDR_ULA(&a->addr.in6) ? 1 : a->preferred; + uint32_t b_pref = IN6_IS_ADDR_ULA(&b->addr.in6) ? 1 : b->preferred; + return (a_pref < b_pref) ? 1 : (a_pref > b_pref) ? -1 : 0; +} + // Detect an IPV6-address currently assigned to the given interface -ssize_t odhcpd_get_interface_addresses(int ifindex, struct odhcpd_ipaddr **addrs) +ssize_t odhcpd_get_interface_addresses(int ifindex, bool v6, struct odhcpd_ipaddr **addrs) { struct nl_msg *msg; struct ifaddrmsg ifa = { - .ifa_family = AF_INET6, + .ifa_family = v6? AF_INET6: AF_INET, .ifa_prefixlen = 0, .ifa_flags = 0, .ifa_scope = 0, @@ -306,6 +317,7 @@ ssize_t odhcpd_get_interface_addresses(int ifindex, struct odhcpd_ipaddr **addrs struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT); struct addr_info ctxt = { .ifindex = ifindex, + .af = v6? AF_INET6: AF_INET, .addrs = addrs, .ret = 0, .pending = 1, @@ -334,6 +346,23 @@ ssize_t odhcpd_get_interface_addresses(int ifindex, struct odhcpd_ipaddr **addrs nl_recvmsgs(rtnl_socket, cb); nlmsg_free(msg); + + if (ctxt.ret <= 0) + goto out; + + time_t now = odhcpd_time(); + struct odhcpd_ipaddr *addr = *addrs; + + qsort(addr, ctxt.ret, sizeof(*addr), prefixcmp); + + for (ssize_t i = 0; i < ctxt.ret; ++i) { + if (addr[i].preferred < UINT32_MAX - now) + addr[i].preferred += now; + + if (addr[i].valid < UINT32_MAX - now) + addr[i].valid += now; + } + out: nl_cb_put(cb); @@ -383,12 +412,12 @@ int odhcpd_get_interface_dns_addr(const struct interface *iface, struct in6_addr iface->ia_addr[i].preferred < (uint32_t)now) continue; - if (IN6_IS_ADDR_ULA(&iface->ia_addr[i].addr)) { - if (!IN6_IS_ADDR_ULA(&iface->ia_addr[m].addr)) { + if (IN6_IS_ADDR_ULA(&iface->ia_addr[i].addr.in6)) { + if (!IN6_IS_ADDR_ULA(&iface->ia_addr[m].addr.in6)) { m = i; continue; } - } else if (IN6_IS_ADDR_ULA(&iface->ia_addr[m].addr)) + } else if (IN6_IS_ADDR_ULA(&iface->ia_addr[m].addr.in6)) continue; if (iface->ia_addr[i].preferred > iface->ia_addr[m].preferred) @@ -396,7 +425,7 @@ int odhcpd_get_interface_dns_addr(const struct interface *iface, struct in6_addr } if (m >= 0) { - *addr = iface->ia_addr[m].addr; + *addr = iface->ia_addr[m].addr.in6; return 0; } diff --git a/src/odhcpd.h b/src/odhcpd.h index 8a196ea..28eb88e 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -68,10 +68,16 @@ struct odhcpd_event { void (*recv_msgs)(struct odhcpd_event *e); }; +union if_addr { + struct in_addr in; + struct in6_addr in6; +}; struct odhcpd_ipaddr { - struct in6_addr addr; + union if_addr addr; uint8_t prefix; + + /* ipv6 only */ uint8_t dprefix; uint32_t preferred; uint32_t valid; @@ -203,7 +209,7 @@ struct nl_sock *odhcpd_create_nl_socket(int protocol); ssize_t odhcpd_send(int socket, struct sockaddr_in6 *dest, struct iovec *iov, size_t iov_len, const struct interface *iface); -ssize_t odhcpd_get_interface_addresses(int ifindex, +ssize_t odhcpd_get_interface_addresses(int ifindex, bool v6, struct odhcpd_ipaddr **addrs); int odhcpd_get_interface_dns_addr(const struct interface *iface, struct in6_addr *addr); @@ -229,9 +235,6 @@ void odhcpd_bmemcpy(void *av, const void *bv, size_t bits); int config_parse_interface(void *data, size_t len, const char *iname, bool overwrite); -void ndp_handle_addr6_dump(void); -void ndp_rqs_addr6_dump(void); - #ifdef WITH_UBUS int init_ubus(void); const char* ubus_get_ifname(const char *name); diff --git a/src/router.c b/src/router.c index 0463d68..19702a2 100644 --- a/src/router.c +++ b/src/router.c @@ -119,7 +119,6 @@ int setup_router_interface(struct interface *iface, bool enable) } else if (iface->ra == RELAYD_SERVER && !iface->master) { iface->timer_rs.cb = trigger_router_advert; uloop_timeout_set(&iface->timer_rs, 1000); - ndp_rqs_addr6_dump(); } if (iface->ra == RELAYD_RELAY || (iface->ra == RELAYD_SERVER && !iface->master)) @@ -182,7 +181,9 @@ static bool parse_routes(struct odhcpd_ipaddr *n, ssize_t len) char line[512], ifname[16]; bool found_default = false; - struct odhcpd_ipaddr p = {IN6ADDR_ANY_INIT, 0, 0, 0, 0}; + struct odhcpd_ipaddr p = { .addr.in6 = IN6ADDR_ANY_INIT, .prefix = 0, + .dprefix = 0, .preferred = 0, .valid = 0}; + while (fgets(line, sizeof(line), fp_route)) { uint32_t rflags; if (sscanf(line, "00000000000000000000000000000000 00 " @@ -191,15 +192,15 @@ static bool parse_routes(struct odhcpd_ipaddr *n, ssize_t len) found_default = true; } else if (sscanf(line, "%8" SCNx32 "%8" SCNx32 "%*8" SCNx32 "%*8" SCNx32 " %hhx %*s " "%*s 00000000000000000000000000000000 %*s %*s %*s %" SCNx32 " lo", - &p.addr.s6_addr32[0], &p.addr.s6_addr32[1], &p.prefix, &rflags) && + &p.addr.in6.s6_addr32[0], &p.addr.in6.s6_addr32[1], &p.prefix, &rflags) && p.prefix > 0 && (rflags & RTF_NONEXTHOP) && (rflags & RTF_REJECT)) { // Find source prefixes by scanning through unreachable-routes - p.addr.s6_addr32[0] = htonl(p.addr.s6_addr32[0]); - p.addr.s6_addr32[1] = htonl(p.addr.s6_addr32[1]); + p.addr.in6.s6_addr32[0] = htonl(p.addr.in6.s6_addr32[0]); + p.addr.in6.s6_addr32[1] = htonl(p.addr.in6.s6_addr32[1]); for (ssize_t i = 0; i < len; ++i) { if (n[i].prefix <= 64 && n[i].prefix >= p.prefix && - !odhcpd_bmemcmp(&p.addr, &n[i].addr, p.prefix)) { + !odhcpd_bmemcmp(&p.addr.in6, &n[i].addr.in6, p.prefix)) { n[i].dprefix = p.prefix; break; } @@ -353,7 +354,7 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add if (addr->prefix > 96 || addr->valid <= (uint32_t)now) { char namebuf[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, addr, namebuf, sizeof(namebuf)); + inet_ntop(AF_INET6, &addr->addr.in6, namebuf, sizeof(namebuf)); syslog(LOG_INFO, "Address %s (prefix %d, valid %u) not suitable as RA prefix on %s", namebuf, addr->prefix, addr->valid, iface->ifname); continue; @@ -363,7 +364,7 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add for (size_t i = 0; i < pfxs_cnt; ++i) { if (addr->prefix == pfxs[i].nd_opt_pi_prefix_len && !odhcpd_bmemcmp(&pfxs[i].nd_opt_pi_prefix, - &addr->addr, addr->prefix)) + &addr->addr.in6, addr->prefix)) p = &pfxs[i]; } @@ -396,10 +397,10 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add if (minvalid > valid) minvalid = valid; - if (!IN6_IS_ADDR_ULA(&addr->addr) || iface->default_router) + if (!IN6_IS_ADDR_ULA(&addr->addr.in6) || iface->default_router) valid_prefix = true; - odhcpd_bmemcpy(&p->nd_opt_pi_prefix, &addr->addr, + odhcpd_bmemcpy(&p->nd_opt_pi_prefix, &addr->addr.in6, (iface->ra_advrouter) ? 128 : addr->prefix); p->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; p->nd_opt_pi_len = 4; @@ -498,10 +499,10 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add (addr->dprefix == 64 && addr->prefix == 64)) { continue; // Address not suitable } else if (addr->dprefix > 32) { - addr->addr.s6_addr32[1] &= htonl(~((1U << (64 - addr->dprefix)) - 1)); + addr->addr.in6.s6_addr32[1] &= htonl(~((1U << (64 - addr->dprefix)) - 1)); } else if (addr->dprefix <= 32) { - addr->addr.s6_addr32[0] &= htonl(~((1U << (32 - addr->dprefix)) - 1)); - addr->addr.s6_addr32[1] = 0; + addr->addr.in6.s6_addr32[0] &= htonl(~((1U << (32 - addr->dprefix)) - 1)); + addr->addr.in6.s6_addr32[1] = 0; } tmp = realloc(routes, sizeof(*routes) * (routes_cnt + 1)); @@ -522,8 +523,8 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add else if (iface->route_preference > 0) routes[routes_cnt].flags |= ND_RA_PREF_HIGH; routes[routes_cnt].lifetime = htonl(TIME_LEFT(addr->valid, now)); - routes[routes_cnt].addr[0] = addr->addr.s6_addr32[0]; - routes[routes_cnt].addr[1] = addr->addr.s6_addr32[1]; + routes[routes_cnt].addr[0] = addr->addr.in6.s6_addr32[0]; + routes[routes_cnt].addr[1] = addr->addr.in6.s6_addr32[1]; routes[routes_cnt].addr[2] = 0; routes[routes_cnt].addr[3] = 0; -- 2.11.0