dhcpv6/router: add support for mutiple master interfaces
[project/odhcpd.git] / src / router.c
index a79f09c28bf61e595b8802c0fd3f2bfce4768ec3..976e28aaa949dcc09c89a4e716e3689ea637c68f 100644 (file)
@@ -209,7 +209,7 @@ static void router_netevent_cb(unsigned long event, struct netevent_handler_info
                if (info->rt.dst_len)
                        break;
 
-               list_for_each_entry(iface, &interfaces, head) {
+               avl_for_each_element(&interfaces, iface, avl) {
                        if (iface->ra == MODE_SERVER && !iface->master)
                                uloop_timeout_set(&iface->timer_rs, 1000);
                }
@@ -292,7 +292,6 @@ static bool parse_routes(struct odhcpd_ipaddr *n, ssize_t len)
                                        break;
                                }
                        }
-
                }
        }
 
@@ -456,9 +455,13 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
                }
 
                if (odhcpd_bmemcmp(&addr->addr, &iface->pio_filter_addr,
-                               iface->pio_filter_length) != 0 ||
-                               addr->prefix < iface->pio_filter_length)
-                       continue; // PIO filtered out of this RA
+                                  iface->pio_filter_length) != 0 ||
+                   addr->prefix < iface->pio_filter_length) {
+                       syslog(LOG_INFO, "Address %s filtered out as RA prefix on %s",
+                              inet_ntop(AF_INET6, &addr->addr.in6, buf, sizeof(buf)),
+                              iface->name);
+                       continue; /* PIO filtered out of this RA */
+               }
 
                struct nd_opt_prefix_info *p = NULL;
                for (size_t i = 0; i < pfxs_cnt; ++i) {
@@ -605,8 +608,12 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
 
                if (odhcpd_bmemcmp(&addr->addr, &iface->pio_filter_addr,
                                iface->pio_filter_length) != 0 ||
-                               addr->prefix < iface->pio_filter_length)
-                       continue; /* RIO filtered out of this RA */
+                               addr->prefix < iface->pio_filter_length) {
+                       syslog(LOG_INFO, "Address %s filtered out as RA route on %s",
+                              inet_ntop(AF_INET6, &addr->addr.in6, buf, sizeof(buf)),
+                              iface->name);
+                       continue; /* PIO filtered out of this RA */
+               }
 
                if (addr->dprefix > 32) {
                        addr->addr.in6.s6_addr32[1] &= htonl(~((1U << (64 - addr->dprefix)) - 1));
@@ -668,6 +675,8 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
        else
                inet_pton(AF_INET6, ALL_IPV6_NODES, &dest.sin6_addr);
 
+       syslog(LOG_INFO, "Sending a RA on %s", iface->name);
+
        odhcpd_send(router_event.uloop.fd,
                        &dest, iov, ARRAY_SIZE(iov), iface);
 
@@ -703,10 +712,17 @@ static void handle_icmpv6(void *addr, void *data, size_t len,
                if (hdr->icmp6_type == ND_ROUTER_SOLICIT)
                        send_router_advert(iface, &from->sin6_addr);
        } else if (iface->ra == MODE_RELAY) { /* Relay mode */
-               if (hdr->icmp6_type == ND_ROUTER_ADVERT && iface->master)
+               if (hdr->icmp6_type == ND_ROUTER_SOLICIT && !iface->master) {
+                       struct interface *c;
+
+                       avl_for_each_element(&interfaces, c, avl) {
+                               if (!c->master || c->ra != MODE_RELAY)
+                                       continue;
+
+                               forward_router_solicitation(c);
+                       }
+               } else if (hdr->icmp6_type == ND_ROUTER_ADVERT && iface->master)
                        forward_router_advertisement(iface, data, len);
-               else if (hdr->icmp6_type == ND_ROUTER_SOLICIT && !iface->master)
-                       forward_router_solicitation(odhcpd_get_master_interface());
        }
 }
 
@@ -736,14 +752,15 @@ static void forward_router_advertisement(const struct interface *iface, uint8_t
 {
        struct nd_router_advert *adv = (struct nd_router_advert *)data;
        struct sockaddr_in6 all_nodes;
-
+       struct icmpv6_opt *opt;
+       struct interface *c;
+       struct iovec iov = { .iov_base = data, .iov_len = len };
        /* Rewrite options */
        uint8_t *end = data + len;
        uint8_t *mac_ptr = NULL;
        struct in6_addr *dns_ptr = NULL;
        size_t dns_count = 0;
 
-       struct icmpv6_opt *opt;
        icmpv6_for_each_option(opt, &adv[1], end) {
                if (opt->type == ND_OPT_SOURCE_LINKADDR) {
                        /* Store address of source MAC-address */
@@ -765,10 +782,7 @@ static void forward_router_advertisement(const struct interface *iface, uint8_t
        all_nodes.sin6_family = AF_INET6;
        inet_pton(AF_INET6, ALL_IPV6_NODES, &all_nodes.sin6_addr);
 
-       struct iovec iov = {data, len};
-
-       struct interface *c;
-       list_for_each_entry(c, &interfaces, head) {
+       avl_for_each_element(&interfaces, c, avl) {
                if (c->ra != MODE_RELAY || c->master)
                        continue;
 
@@ -797,6 +811,8 @@ static void forward_router_advertisement(const struct interface *iface, uint8_t
                        }
                }
 
+               syslog(LOG_NOTICE, "Forward a RA on %s", c->name);
+
                odhcpd_send(router_event.uloop.fd, &all_nodes, &iov, 1, c);
        }
 }