lwip中关于nd的实现,没有路由器的功能,不能发送ra
在contiki中发现有nd发送ra的实现,
contiki/core/net/ipv6/uip-ds6.c
在rs的接收处理中,发送sollicited,在定时器中定期发送periodic。
发送solicted的时候,其实,是让定时器直接到时间实现的。
在uip_ds6_init中初始化ra发送定时器,初始设为2s后发送?等待链路本地地址有效
初始设置为2s,之后定时处理函数会处理定时器首次超时,处理完之后,会将定时器设置为RA间隔时间。
void
uip_ds6_init(void)
{
#if UIP_ND6_SEND_RA
stimer_set(&uip_ds6_timer_ra, 2); /* wait to have a link local IP address */
#endif /* UIP_ND6_SEND_RA */
在uip_ds6_periodic中定期处理是否超时,uip_ds6_periodic类似lwip中的nd_tmr。如果超时了,就发送uip_ds6_send_ra_periodic
void
uip_ds6_periodic(void)
{
#if UIP_CONF_ROUTER && UIP_ND6_SEND_RA
/* Periodic RA sending */
if(stimer_expired(&uip_ds6_timer_ra) && (uip_len == 0)) {
uip_ds6_send_ra_periodic();
}
#endif /* UIP_CONF_ROUTER && UIP_ND6_SEND_RA */
uip_ds6_send_ra_periodic函数中设置了两次随机时间,没看明白为什么?
第一次时间:间隔=最小间隔+随机数*(最大间隔-最小间隔)
第二次时间:初始的3次ra间隔不能超过初始最大间隔16s,后续的ra间隔没限制
1 /*---------------------------------------------------------------------------*/ 2 void 3 uip_ds6_send_ra_periodic(void) 4 { 5 if(racount > 0) { 6 /* send previously scheduled RA */ 7 uip_nd6_ra_output(NULL); 8 PRINTF("Sending periodic RA "); 9 } 10 /* rand_t = min + rand % (max - min) */ 11 rand_time = UIP_ND6_MIN_RA_INTERVAL + random_rand() % 12 (uint16_t) (UIP_ND6_MAX_RA_INTERVAL - UIP_ND6_MIN_RA_INTERVAL); 13 PRINTF("Random time 1 = %u ", rand_time); 14 /* intial ra interval = 16s, initial 3 ra, should not exceed initial_ra_interval */ 15 if(racount < UIP_ND6_MAX_INITIAL_RAS) { 16 if(rand_time > UIP_ND6_MAX_INITIAL_RA_INTERVAL) { 17 rand_time = UIP_ND6_MAX_INITIAL_RA_INTERVAL; 18 PRINTF("Random time 2 = %u ", rand_time); 19 } 20 racount++; 21 } 22 PRINTF("Random time 3 = %u ", rand_time); 23 stimer_set(&uip_ds6_timer_ra, rand_time); 24 } 25
如果收到了rs(rs_input在uip-nd6.c文件中),则会发送sollicited的ra,在uip_ds6_send_ra_sollicited中,其实是直接将定时器设置到时间。
/*---------------------------------------------------------------------------*/ #if UIP_CONF_ROUTER #if UIP_ND6_SEND_RA void uip_ds6_send_ra_sollicited(void) { /* We have a pb here: RA timer max possible value is 1800s, * hence we have to use stimers. However, when receiving a RS, we * should delay the reply by a random value between 0 and 500ms timers. * stimers are in seconds, hence we cannot do this. Therefore we just send * the RA (setting the timer to 0 below). We keep the code logic for * the days contiki will support appropriate timers */ rand_time = 0; PRINTF("Solicited RA, random time %u ", rand_time); if(stimer_remaining(&uip_ds6_timer_ra) > rand_time) { if(stimer_elapsed(&uip_ds6_timer_ra) < UIP_ND6_MIN_DELAY_BETWEEN_RAS) { /* Ensure that the RAs are rate limited */ /* stimer_set(&uip_ds6_timer_ra, rand_time + UIP_ND6_MIN_DELAY_BETWEEN_RAS - stimer_elapsed(&uip_ds6_timer_ra)); */ } else { stimer_set(&uip_ds6_timer_ra, rand_time); } } }
uip-nd6.c实际的接收rs和发送ra在这个文件中定义
1 /*---------------------------------------------------------------------------*/ 2 static void 3 rs_input(void) 4 { 5 6 PRINTF("Received RS from "); 7 PRINT6ADDR(&UIP_IP_BUF->srcipaddr); 8 PRINTF(" to "); 9 PRINT6ADDR(&UIP_IP_BUF->destipaddr); 10 PRINTF(" "); 11 UIP_STAT(++uip_stat.nd6.recv); 12 13 14 #if UIP_CONF_IPV6_CHECKS 15 /* 16 * Check hop limit / icmp code 17 * target address must not be multicast 18 * if the NA is solicited, dest must not be multicast 19 */ 20 if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) || (UIP_ICMP_BUF->icode != 0)) { 21 PRINTF("RS received is bad "); 22 goto discard; 23 } 24 #endif /*UIP_CONF_IPV6_CHECKS */ 25 26 /* Only valid option is Source Link-Layer Address option any thing 27 else is discarded */ 28 nd6_opt_offset = UIP_ND6_RS_LEN; 29 nd6_opt_llao = NULL; 30 31 while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) { 32 #if UIP_CONF_IPV6_CHECKS 33 if(UIP_ND6_OPT_HDR_BUF->len == 0) { 34 PRINTF("RS received is bad "); 35 goto discard; 36 } 37 #endif /*UIP_CONF_IPV6_CHECKS */ 38 switch (UIP_ND6_OPT_HDR_BUF->type) { 39 case UIP_ND6_OPT_SLLAO: 40 nd6_opt_llao = (uint8_t *)UIP_ND6_OPT_HDR_BUF; 41 break; 42 default: 43 PRINTF("ND option not supported in RS "); 44 break; 45 } 46 nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3); 47 } 48 /* Options processing: only SLLAO */ 49 if(nd6_opt_llao != NULL) { 50 #if UIP_CONF_IPV6_CHECKS 51 if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { 52 PRINTF("RS received is bad "); 53 goto discard; 54 } else { 55 #endif /*UIP_CONF_IPV6_CHECKS */ 56 uip_lladdr_t lladdr_aligned; 57 extract_lladdr_from_llao_aligned(&lladdr_aligned); 58 if((nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr)) == NULL) { 59 /* we need to add the neighbor */ 60 uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned, 61 0, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL); 62 } else { 63 /* If LL address changed, set neighbor state to stale */ 64 const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr); 65 if(lladdr == NULL) { 66 goto discard; 67 } 68 if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], 69 lladdr, UIP_LLADDR_LEN) != 0) { 70 uip_ds6_nbr_t nbr_data; 71 nbr_data = *nbr; 72 uip_ds6_nbr_rm(nbr); 73 nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned, 74 0, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL); 75 nbr->reachable = nbr_data.reachable; 76 nbr->sendns = nbr_data.sendns; 77 nbr->nscount = nbr_data.nscount; 78 } 79 nbr->isrouter = 0; 80 } 81 #if UIP_CONF_IPV6_CHECKS 82 } 83 #endif /*UIP_CONF_IPV6_CHECKS */ 84 } 85 86 /* Schedule a sollicited RA */ 87 uip_ds6_send_ra_sollicited(); 88 89 discard: 90 uip_clear_buf(); 91 return; 92 }
1 /*---------------------------------------------------------------------------*/ 2 void 3 uip_nd6_ra_output(uip_ipaddr_t * dest) 4 { 5 6 UIP_IP_BUF->vtc = 0x60; 7 UIP_IP_BUF->tcflow = 0; 8 UIP_IP_BUF->flow = 0; 9 UIP_IP_BUF->proto = UIP_PROTO_ICMP6; 10 UIP_IP_BUF->ttl = UIP_ND6_HOP_LIMIT; 11 12 if(dest == NULL) { 13 uip_create_linklocal_allnodes_mcast(&UIP_IP_BUF->destipaddr); 14 } else { 15 /* For sollicited RA */ 16 uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, dest); 17 } 18 uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr); 19 20 UIP_ICMP_BUF->type = ICMP6_RA; 21 UIP_ICMP_BUF->icode = 0; 22 23 UIP_ND6_RA_BUF->cur_ttl = uip_ds6_if.cur_hop_limit; 24 25 UIP_ND6_RA_BUF->flags_reserved = 26 (UIP_ND6_M_FLAG << 7) | (UIP_ND6_O_FLAG << 6); 27 28 UIP_ND6_RA_BUF->router_lifetime = uip_htons(UIP_ND6_ROUTER_LIFETIME); 29 //UIP_ND6_RA_BUF->reachable_time = uip_htonl(uip_ds6_if.reachable_time); 30 //UIP_ND6_RA_BUF->retrans_timer = uip_htonl(uip_ds6_if.retrans_timer); 31 UIP_ND6_RA_BUF->reachable_time = 0; 32 UIP_ND6_RA_BUF->retrans_timer = 0; 33 34 uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_RA_LEN; 35 nd6_opt_offset = UIP_ND6_RA_LEN; 36 37 38 /* Prefix list */ 39 for(prefix = uip_ds6_prefix_list; 40 prefix < uip_ds6_prefix_list + UIP_DS6_PREFIX_NB; prefix++) { 41 if((prefix->isused) && (prefix->advertise)) { 42 UIP_ND6_OPT_PREFIX_BUF->type = UIP_ND6_OPT_PREFIX_INFO; 43 UIP_ND6_OPT_PREFIX_BUF->len = UIP_ND6_OPT_PREFIX_INFO_LEN / 8; 44 UIP_ND6_OPT_PREFIX_BUF->preflen = prefix->length; 45 UIP_ND6_OPT_PREFIX_BUF->flagsreserved1 = prefix->l_a_reserved; 46 UIP_ND6_OPT_PREFIX_BUF->validlt = uip_htonl(prefix->vlifetime); 47 UIP_ND6_OPT_PREFIX_BUF->preferredlt = uip_htonl(prefix->plifetime); 48 UIP_ND6_OPT_PREFIX_BUF->reserved2 = 0; 49 uip_ipaddr_copy(&(UIP_ND6_OPT_PREFIX_BUF->prefix), &(prefix->ipaddr)); 50 nd6_opt_offset += UIP_ND6_OPT_PREFIX_INFO_LEN; 51 uip_len += UIP_ND6_OPT_PREFIX_INFO_LEN; 52 } 53 } 54 55 /* Source link-layer option */ 56 create_llao((uint8_t *)UIP_ND6_OPT_HDR_BUF, UIP_ND6_OPT_SLLAO); 57 58 uip_len += UIP_ND6_OPT_LLAO_LEN; 59 nd6_opt_offset += UIP_ND6_OPT_LLAO_LEN; 60 61 /* MTU */ 62 UIP_ND6_OPT_MTU_BUF->type = UIP_ND6_OPT_MTU; 63 UIP_ND6_OPT_MTU_BUF->len = UIP_ND6_OPT_MTU_LEN >> 3; 64 UIP_ND6_OPT_MTU_BUF->reserved = 0; 65 //UIP_ND6_OPT_MTU_BUF->mtu = uip_htonl(uip_ds6_if.link_mtu); 66 UIP_ND6_OPT_MTU_BUF->mtu = uip_htonl(1500); 67 68 uip_len += UIP_ND6_OPT_MTU_LEN; 69 nd6_opt_offset += UIP_ND6_OPT_MTU_LEN; 70 71 #if UIP_ND6_RA_RDNSS 72 if(uip_nameserver_count() > 0) { 73 uint8_t i = 0; 74 uip_ipaddr_t *ip = &UIP_ND6_OPT_RDNSS_BUF->ip; 75 uip_ipaddr_t *dns = NULL; 76 UIP_ND6_OPT_RDNSS_BUF->type = UIP_ND6_OPT_RDNSS; 77 UIP_ND6_OPT_RDNSS_BUF->reserved = 0; 78 UIP_ND6_OPT_RDNSS_BUF->lifetime = uip_nameserver_next_expiration(); 79 if(UIP_ND6_OPT_RDNSS_BUF->lifetime != UIP_NAMESERVER_INFINITE_LIFETIME) { 80 UIP_ND6_OPT_RDNSS_BUF->lifetime -= clock_seconds(); 81 } 82 while((dns = uip_nameserver_get(i)) != NULL) { 83 uip_ipaddr_copy(ip++, dns); 84 i++; 85 } 86 UIP_ND6_OPT_RDNSS_BUF->len = UIP_ND6_OPT_RDNSS_LEN + (i << 1); 87 PRINTF("%d nameservers reported ", i); 88 uip_len += UIP_ND6_OPT_RDNSS_BUF->len << 3; 89 nd6_opt_offset += UIP_ND6_OPT_RDNSS_BUF->len << 3; 90 } 91 #endif /* UIP_ND6_RA_RDNSS */ 92 93 UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); 94 UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); 95 96 /*ICMP checksum */ 97 UIP_ICMP_BUF->icmpchksum = 0; 98 UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); 99 100 UIP_STAT(++uip_stat.nd6.sent); 101 PRINTF("Sending RA to "); 102 PRINT6ADDR(&UIP_IP_BUF->destipaddr); 103 PRINTF(" from "); 104 PRINT6ADDR(&UIP_IP_BUF->srcipaddr); 105 PRINTF(" "); 106 return; 107 }
在linux和freebsd中每怎么找到发送ra的部分。