static void process_rs(int sock, struct Interface *iface, unsigned char *msg, int len, struct sockaddr_in6 *addr) { /* validation */ len -= sizeof(struct nd_router_solicit); uint8_t *opt_str = (uint8_t *) (msg + sizeof(struct nd_router_solicit)); while (len > 0) { if (len < 2) { flog(LOG_WARNING, "trailing garbage in RS"); return; } int const optlen = (opt_str[1] << 3); if (optlen == 0) { flog(LOG_WARNING, "zero length option in RS"); return; } else if (optlen > len) { flog(LOG_WARNING, "option length greater than total length in RS"); return; } if (*opt_str == ND_OPT_SOURCE_LINKADDR && IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr)) { flog(LOG_WARNING, "received icmpv6 RS packet with unspecified source address and there is a lladdr option"); return; } len -= optlen; opt_str += optlen; } struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); double const delay = (MAX_RA_DELAY_SECONDS * rand() / (RAND_MAX + 1.0)); if (iface->UnicastOnly) { send_ra_forall(sock, iface, &addr->sin6_addr); } else if (timespecdiff(&ts, &iface->times.last_multicast) / 1000.0 < iface->MinDelayBetweenRAs) { /* last RA was sent only a few moments ago, don't send another immediately. */ double next = iface->MinDelayBetweenRAs - (ts.tv_sec + ts.tv_nsec / 1000000000.0) + (iface->times.last_multicast.tv_sec + iface->times.last_multicast.tv_nsec / 1000000000.0) + delay; dlog(LOG_DEBUG, 5, "%s: rate limiting RA's, rescheduling RA %f seconds from now", iface->props.name, next); reschedule_iface(iface, next); } else { /* no RA sent in a while, send a multicast reply */ send_ra_forall(sock, iface, NULL); double next = rand_between(iface->MinRtrAdvInterval, iface->MaxRtrAdvInterval); reschedule_iface(iface, next); } dlog(LOG_DEBUG, 2, "%s processed an RS", iface->props.name); }
static void timer_handler(int sock, struct Interface *iface) { dlog(LOG_DEBUG, 1, "timer_handler called for %s", iface->props.name); if (send_ra_forall(sock, iface, NULL) != 0) { dlog(LOG_DEBUG, 4, "send_ra_forall failed on interface %s", iface->props.name); } double next = rand_between(iface->MinRtrAdvInterval, iface->MaxRtrAdvInterval); reschedule_iface(iface, next); }
/* * send initial advertisement and set timers */ static void kickoff_adverts(int sock, struct Interface *iface) { clock_gettime(CLOCK_MONOTONIC, &iface->times.last_ra_time); if (iface->UnicastOnly) return; clock_gettime(CLOCK_MONOTONIC, &iface->times.last_multicast); /* send an initial advertisement */ if (send_ra_forall(sock, iface, NULL) != 0) { dlog(LOG_DEBUG, 4, "send_ra_forall failed on interface %s", iface->props.name); } double next = min(MAX_INITIAL_RTR_ADVERT_INTERVAL, iface->MaxRtrAdvInterval); reschedule_iface(iface, next); }