static void process_rs(struct Interface *iface, unsigned char *msg, int len, struct sockaddr_in6 *addr) { double delay; double next; struct timespec ts; uint8_t *opt_str; /* validation */ len -= sizeof(struct nd_router_solicit); opt_str = (uint8_t *) (msg + sizeof(struct nd_router_solicit)); while (len > 0) { int optlen; if (len < 2) { flog(LOG_WARNING, "trailing garbage in RS"); return; } 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; } clock_gettime(CLOCK_MONOTONIC, &ts); delay = MAX_RA_DELAY_TIME * rand() / (RAND_MAX + 1.0); if (iface->UnicastOnly) { send_ra_forall(iface, &addr->sin6_addr); } else if (timespecdiff(&ts, &iface->last_multicast) / 1000.0 < iface->MinDelayBetweenRAs) { /* last RA was sent only a few moments ago, don't send another immediately. */ next = iface->MinDelayBetweenRAs - (ts.tv_sec + ts.tv_nsec / 1000000000.0) + (iface->last_multicast.tv_sec + iface->last_multicast.tv_nsec / 1000000000.0) + delay / 1000.0; iface->next_multicast = next_timespec(next); } else { /* no RA sent in a while, send a multicast reply */ send_ra_forall(iface, NULL); next = rand_between(iface->MinRtrAdvInterval, iface->MaxRtrAdvInterval); iface->next_multicast = next_timespec(next); } }
void stop_adverts(void) { struct Interface *iface; /* * send final RA (a SHOULD in RFC4861 section 6.2.5) */ /* BEGIN: Added by z67728, 2009/12/28 PN:AU4D02322 Radvd模块关闭后,默认路由器将会失效。 现将前缀地址的首选时间和在链标志去除,防止PC继续使用该地址通信. */ if ( 0 == g_iReadTestFlag ) { disable_oldprefix(); disable_oldstataddr(); } /* END: Added by z67728, 2009/12/28 */ for (iface=IfaceList; iface; iface=iface->next) { if( ! iface->UnicastOnly ) { if (iface->AdvSendAdvert) { /* send a final advertisement with zero Router Lifetime */ iface->AdvDefaultLifetime = 0; send_ra_forall(sock, iface, NULL); } } } }
void kickoff_adverts(void) { struct Interface *iface; /* * send initial advertisement and set timers */ for(iface=IfaceList; iface; iface=iface->next) { if( iface->UnicastOnly ) break; init_timer(&iface->tm, timer_handler, (void *) iface); if (!iface->AdvSendAdvert) break; /* send an initial advertisement */ send_ra_forall(sock, iface, NULL); iface->init_racount++; set_timer(&iface->tm, min(MAX_INITIAL_RTR_ADVERT_INTERVAL, iface->MaxRtrAdvInterval)); } }
void kickoff_adverts(void) { struct Interface *iface; /* * send initial advertisement and set timers */ for(iface=IfaceList; iface; iface=iface->next) { double next; gettimeofday(&iface->last_ra_time, NULL); if( iface->UnicastOnly ) continue; gettimeofday(&iface->last_multicast, NULL); if (!iface->AdvSendAdvert) continue; /* send an initial advertisement */ if (send_ra_forall(iface, NULL) == 0) { iface->init_racount++; next = min(MAX_INITIAL_RTR_ADVERT_INTERVAL, iface->MaxRtrAdvInterval); iface->next_multicast = next_timeval(next); } } }
static void stop_advert_foo(struct Interface *iface, void *data) { if (!iface->UnicastOnly) { /* send a final advertisement with zero Router Lifetime */ dlog(LOG_DEBUG, 4, "stopping all adverts on %s", iface->props.name); iface->state_info.cease_adv = 1; int sock = *(int *)data; send_ra_forall(sock, iface, NULL); } }
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); }
/* BEGIN: Added by z67728, 2009/12/26 PN:AU4D02322 */ void disable_oldprefix(void) { if ( 0 == g_iReadTestFlag ) { struct Interface *iface; /* * RA配置发生变化时,将变化前的前缀设置为无效. */ for (iface=IfaceList; iface; iface=iface->next) { if( ! iface->UnicastOnly ) { if (iface->AdvSendAdvert) { /* send a final advertisement with zero Router Lifetime */ if ( NULL != iface->AdvPrefixList ) { while ( 1 ) { /* 只能修改时间,不能修改其他参数.否则客户端认为此RA非法. The only way to cancela previous on-link indication is to advertise that prefix with the L-bit set and the Lifetime set to zero. */ iface->AdvPrefixList->AdvOnLinkFlag = 0; iface->AdvPrefixList->AdvValidLifetime = 0; iface->AdvPrefixList->AdvPreferredLifetime = 0; if ( NULL == iface->AdvPrefixList->next) { break; } else { iface->AdvPrefixList = iface->AdvPrefixList->next; continue; } } send_ra_forall(sock, iface, NULL); } } } } } return; }
/* * 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); }
void stop_adverts(void) { struct Interface *iface; /* * send final RA (a SHOULD in RFC4861 section 6.2.5) */ for (iface=IfaceList; iface; iface=iface->next) { if( ! iface->UnicastOnly ) { if (iface->AdvSendAdvert) { /* send a final advertisement with zero Router Lifetime */ iface->cease_adv = 1; send_ra_forall(iface, NULL); } } } }
void timer_handler(void *data) { struct Interface *iface = (struct Interface *) data; double next; dlog(LOG_DEBUG, 4, "timer_handler called for %s", iface->Name); send_ra_forall(sock, iface, NULL); next = rand_between(iface->MinRtrAdvInterval, iface->MaxRtrAdvInterval); if (iface->init_racount < MAX_INITIAL_RTR_ADVERTISEMENTS - 1) { iface->init_racount++; next = min(MAX_INITIAL_RTR_ADVERT_INTERVAL, next); } set_timer(&iface->tm, next); }
void disable_oldstataddr() { if ( 0 == g_iReadTestFlag ) { struct Interface *iface; /* * RA配置发生变化时,将变化前的前缀设置为无效. */ for (iface=IfaceList; iface; iface=iface->next) { if( ! iface->UnicastOnly ) { if (iface->AdvSendAdvert) { /* send a final advertisement with zero Router Lifetime */ if ( NULL != iface->AdvPrefixList ) { while ( 1 ) { iface->AdvManagedFlag = 0; iface->AdvOtherConfigFlag = 0; if ( NULL == iface->AdvPrefixList->next) { break; } else { iface->AdvPrefixList = iface->AdvPrefixList->next; continue; } } send_ra_forall(sock, iface, NULL); } } } } } return; }
void timer_handler(void *data) { struct Interface *iface = (struct Interface *) data; double next; dlog(LOG_DEBUG, 4, "timer_handler called for %s", iface->Name); if (send_ra_forall(iface, NULL) != 0) { return; } next = rand_between(iface->MinRtrAdvInterval, iface->MaxRtrAdvInterval); if (iface->init_racount < MAX_INITIAL_RTR_ADVERTISEMENTS) { iface->init_racount++; next = min(MAX_INITIAL_RTR_ADVERT_INTERVAL, next); } iface->next_multicast = next_timeval(next); }
static void process_rs(int sock, struct Interface *iface, unsigned char *msg, int len, struct sockaddr_in6 *addr) { double delay; double next; struct timeval tv; uint8_t *opt_str; /* validation */ len -= sizeof(struct nd_router_solicit); opt_str = (uint8_t *)(msg + sizeof(struct nd_router_solicit)); //printf("radvd:proc_rs enter!len=%d\n",len); while (len > 0) { int optlen; if (len < 2) { flog(LOG_WARNING, "trailing garbage in RS"); //printf("radvd:return1!!!\n"); return; } optlen = (opt_str[1] << 3); if (optlen == 0) { //printf("radvd:return2!!!\n"); flog(LOG_WARNING, "zero length option in RS"); return; } else if (optlen > len) { // printf("radvd:return3!!!\n"); 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"); printf("radvd:received icmpv6 return!!!\n"); return; } len -= optlen; opt_str += optlen; } // printf("radvd:proc_rs_11\n"); gettimeofday(&tv, NULL); delay = MAX_RA_DELAY_TIME*rand()/(RAND_MAX+1.0); dlog(LOG_DEBUG, 3, "random mdelay for %s: %.2f", iface->Name, delay); if (iface->UnicastOnly) { // printf("radvd:proc_rs_22\n"); mdelay(delay); send_ra_forall(sock, iface, &addr->sin6_addr); } else if ((tv.tv_sec + tv.tv_usec / 1000000.0) - (iface->last_multicast_sec + iface->last_multicast_usec / 1000000.0) < iface->MinDelayBetweenRAs) { /* last RA was sent only a few moments ago, don't send another immediately */ // printf("radvd:proc_rs_33\n"); clear_timer(&iface->tm); next = iface->MinDelayBetweenRAs - (tv.tv_sec + tv.tv_usec / 1000000.0) + (iface->last_multicast_sec + iface->last_multicast_usec / 1000000.0) + delay/1000.0; set_timer(&iface->tm, next); } else { /* no RA sent in a while, send an immediate multicast reply */ // printf("radvd:ps_444\n"); clear_timer(&iface->tm); if (send_ra_forall(sock, iface, NULL) == 0) { next = rand_between(iface->MinRtrAdvInterval, iface->MaxRtrAdvInterval); set_timer(&iface->tm, next); } } }