X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fodhcpd.git;a=blobdiff_plain;f=src%2Frouter.c;h=e62282b92cdf0e25cb2150c3058d2eb461103a98;hp=19702a2d08f3af29e23a74e508dcb2e777fcebeb;hb=96033e937c56a407d8ca9302c5901cd77366da29;hpb=18df6cca092743a07be8e0f05d0a9ef941957b66 diff --git a/src/router.c b/src/router.c index 19702a2..e62282b 100644 --- a/src/router.c +++ b/src/router.c @@ -33,20 +33,22 @@ static void forward_router_advertisement(uint8_t *data, size_t len); static void handle_icmpv6(void *addr, void *data, size_t len, struct interface *iface, void *dest); static void trigger_router_advert(struct uloop_timeout *event); -static void sigusr1_refresh(int signal); +static void router_netevent_cb(unsigned long event, struct netevent_handler_info *info); static struct odhcpd_event router_event = {.uloop = {.fd = -1}, .handle_dgram = handle_icmpv6, }; +static struct netevent_handler router_netevent_handler = { .cb = router_netevent_cb, }; static FILE *fp_route = NULL; + #define TIME_LEFT(t1, now) ((t1) != UINT32_MAX ? (t1) - (now) : UINT32_MAX) -int init_router(void) +int router_init(void) { // Open ICMPv6 socket int sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_ICMPV6); if (sock < 0 && errno != EAFNOSUPPORT) { - syslog(LOG_ERR, "Failed to open RAW-socket: %s", strerror(errno)); + syslog(LOG_ERR, "Failed to open RAW-socket: %m"); return -1; } @@ -80,15 +82,15 @@ int init_router(void) odhcpd_register(&router_event); if (!(fp_route = fopen("/proc/net/ipv6_route", "r"))) - syslog(LOG_ERR, "Failed to open routing table: %s", - strerror(errno)); + syslog(LOG_ERR, "Failed to open routing table: %m"); + + netlink_add_netevent_handler(&router_netevent_handler); - signal(SIGUSR1, sigusr1_refresh); return 0; } -int setup_router_interface(struct interface *iface, bool enable) +int router_setup_interface(struct interface *iface, bool enable) { if (!fp_route || router_event.uloop.fd < 0) return -1; @@ -113,15 +115,15 @@ int setup_router_interface(struct interface *iface, bool enable) } else { void *mreq = &all_routers; - if (iface->ra == RELAYD_RELAY && iface->master) { + if (iface->ra == MODE_RELAY && iface->master) { mreq = &all_nodes; forward_router_solicitation(iface); - } else if (iface->ra == RELAYD_SERVER && !iface->master) { + } else if (iface->ra == MODE_SERVER && !iface->master) { iface->timer_rs.cb = trigger_router_advert; uloop_timeout_set(&iface->timer_rs, 1000); } - if (iface->ra == RELAYD_RELAY || (iface->ra == RELAYD_SERVER && !iface->master)) + if (iface->ra == MODE_RELAY || (iface->ra == MODE_SERVER && !iface->master)) setsockopt(router_event.uloop.fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq, sizeof(all_nodes)); } @@ -129,15 +131,32 @@ int setup_router_interface(struct interface *iface, bool enable) } -// Signal handler to resend all RDs -static void sigusr1_refresh(_unused int signal) +static void router_netevent_cb(unsigned long event, struct netevent_handler_info *info) { struct interface *iface; - list_for_each_entry(iface, &interfaces, head) - if (iface->ra == RELAYD_SERVER && !iface->master) + + switch (event) { + case NETEV_ROUTE6_ADD: + case NETEV_ROUTE6_DEL: + if (info->rt.dst_len) + break; + + list_for_each_entry(iface, &interfaces, head) { + if (iface->ra == MODE_SERVER && !iface->master) + uloop_timeout_set(&iface->timer_rs, 1000); + } + break; + case NETEV_ADDR6LIST_CHANGE: + iface = info->iface; + if (iface && iface->ra == MODE_SERVER && !iface->master) uloop_timeout_set(&iface->timer_rs, 1000); + break; + default: + break; + } } + static bool router_icmpv6_valid(struct sockaddr_in6 *source, uint8_t *data, size_t len) { struct icmp6_hdr *hdr = (struct icmp6_hdr *)data; @@ -298,7 +317,7 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add if (iface->dhcpv6) adv.h.nd_ra_flags_reserved = ND_RA_FLAG_OTHER; - if (iface->managed >= RELAYD_MANAGED_MFLAG) + if (iface->ra_managed >= RA_MANAGED_MFLAG) adv.h.nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED; if (iface->route_preference < 0) @@ -320,11 +339,11 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add // If not shutdown if (iface->timer_rs.cb) { - size_t size = sizeof(*addrs) * iface->ia_addr_len; + size_t size = sizeof(*addrs) * iface->addr6_len; addrs = alloca(size); - memcpy(addrs, iface->ia_addr, size); + memcpy(addrs, iface->addr6, size); - ipcnt = iface->ia_addr_len; + ipcnt = iface->addr6_len; // Check default route if (iface->default_router) { @@ -360,6 +379,11 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add continue; } + 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 + struct nd_opt_prefix_info *p = NULL; for (size_t i = 0; i < pfxs_cnt; ++i) { if (addr->prefix == pfxs[i].nd_opt_pi_prefix_len && @@ -408,7 +432,7 @@ static uint64_t send_router_advert(struct interface *iface, const struct in6_add p->nd_opt_pi_flags_reserved = 0; if (!iface->ra_not_onlink) p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK; - if (iface->managed < RELAYD_MANAGED_NO_AFLAG && addr->prefix <= 64) + if (iface->ra_managed < RA_MANAGED_NO_AFLAG && addr->prefix <= 64) p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO; if (iface->ra_advrouter) p->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR; @@ -584,10 +608,10 @@ static void handle_icmpv6(void *addr, void *data, size_t len, if (!router_icmpv6_valid(addr, data, len)) return; - if ((iface->ra == RELAYD_SERVER && !iface->master)) { // Server mode + if ((iface->ra == MODE_SERVER && !iface->master)) { // Server mode if (hdr->icmp6_type == ND_ROUTER_SOLICIT) send_router_advert(iface, &from->sin6_addr); - } else if (iface->ra == RELAYD_RELAY) { // Relay mode + } else if (iface->ra == MODE_RELAY) { // Relay mode if (hdr->icmp6_type == ND_ROUTER_ADVERT && iface->master) forward_router_advertisement(data, len); else if (hdr->icmp6_type == ND_ROUTER_SOLICIT && !iface->master) @@ -646,7 +670,7 @@ static void forward_router_advertisement(uint8_t *data, size_t len) struct interface *iface; list_for_each_entry(iface, &interfaces, head) { - if (iface->ra != RELAYD_RELAY || iface->master) + if (iface->ra != MODE_RELAY || iface->master) continue; // Fixup source hardware address option