router: only send RAs to neighbors if unsolicited
[project/odhcpd.git] / src / router.c
index 3d26c58..a66f65f 100644 (file)
@@ -37,6 +37,7 @@ static void sigusr1_refresh(int signal);
 static struct odhcpd_event router_event = {{.fd = -1}, handle_icmpv6};
 
 static FILE *fp_route = NULL;
+#define RA_IOV_LEN 6
 
 
 int init_router(void)
@@ -176,7 +177,7 @@ 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, false, 0, 0, 0};
+       struct odhcpd_ipaddr p = {IN6ADDR_ANY_INIT, 0, 0, 0, 0};
        while (fgets(line, sizeof(line), fp_route)) {
                uint32_t rflags;
                if (sscanf(line, "00000000000000000000000000000000 00 "
@@ -205,13 +206,28 @@ static bool parse_routes(struct odhcpd_ipaddr *n, ssize_t len)
        return found_default;
 }
 
+// Unicsat RAs
+static void send_neigh_ra(const struct in6_addr *addr,
+               const struct interface *iface, void *data)
+{
+       struct sockaddr_in6 dest = {
+               .sin6_family = AF_INET6,
+               .sin6_addr = *addr,
+               .sin6_scope_id = iface->ifindex,
+       };
+       if (IN6_IS_ADDR_LINKLOCAL(addr))
+               odhcpd_send(router_event.uloop.fd, &dest, data, RA_IOV_LEN, iface);
+}
+
 
 // Router Advert server mode
 static uint64_t send_router_advert(struct interface *iface, const struct in6_addr *from)
 {
-       int mtu = odhcpd_get_interface_mtu(iface->ifname);
-       if (mtu < 0)
-               mtu = 1500;
+       int mtu = odhcpd_get_interface_config(iface->ifname, "mtu");
+       int hlim = odhcpd_get_interface_config(iface->ifname, "hop_limit");
+
+       if (mtu < 1280)
+               mtu = 1280;
 
        struct {
                struct nd_router_advert h;
@@ -224,6 +240,9 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
                .mtu = {ND_OPT_MTU, 1, 0, htonl(mtu)},
        };
 
+       if (hlim > 0)
+               adv.h.nd_ra_curhoplimit = hlim;
+
        if (iface->dhcpv6)
                adv.h.nd_ra_flags_reserved = ND_RA_FLAG_OTHER;
 
@@ -262,7 +281,7 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
 
        for (ssize_t i = 0; i < ipcnt; ++i) {
                struct odhcpd_ipaddr *addr = &addrs[i];
-               if (addr->prefix > 96 || addr->has_class)
+               if (addr->prefix > 96)
                        continue; // Address not suitable
 
                if (addr->preferred > MaxPreferredTime)
@@ -438,7 +457,8 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
                .data = {0, 0, maxival >> 24, maxival >> 16, maxival >> 8, maxival}
        };
 
-       struct iovec iov[] = {{&adv, (uint8_t*)&adv.prefix[cnt] - (uint8_t*)&adv},
+       struct iovec iov[RA_IOV_LEN] = {
+                       {&adv, (uint8_t*)&adv.prefix[cnt] - (uint8_t*)&adv},
                        {&routes, routes_cnt * sizeof(*routes)},
                        {&dns, (dns_cnt) ? sizeof(dns) : 0},
                        {dns_addr, dns_cnt * sizeof(*dns_addr)},
@@ -448,6 +468,8 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add
 
        if (from && !IN6_IS_ADDR_UNSPECIFIED(from))
                dest.sin6_addr = *from;
+       else
+               odhcpd_iterate_interface_neighbors(iface, send_neigh_ra, iov);
 
        odhcpd_send(router_event.uloop.fd,
                        &dest, iov, ARRAY_SIZE(iov), iface);