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\n", 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); } } }
/*---------------------------------------------------------------------------*/ void uip_ds6_periodic(void) { /* This flag signals whether we allow or not to send a packet in the current * invocation. */ u8_t allow_output = 1; /* minimum lifetime */ min_lifetime = 0xFFFFFFFF; /* router with minimum lifetime */ min_defrt = NULL; /* Periodic processing on registrations */ for(locreg = uip_ds6_reg_list; locreg < uip_ds6_reg_list + UIP_DS6_REG_LIST_SIZE; locreg++) { if (locreg->isused) { if (stimer_expired(&locreg->reg_lifetime)) { uip_ds6_reg_rm(locreg); } else if (allow_output) { /* If no output is allowed, it is pointless to enter here in this invocation */ if (uip_ds6_if.registration_in_progress) { /* There is a registration in progress */ if ((locreg == uip_ds6_if.registration_in_progress) && (timer_expired(&locreg->registration_timer))) { /* We already sent a NS message for this address but there has been no response */ if(locreg->reg_count >= UIP_ND6_MAX_UNICAST_SOLICIT) { /* NUD failed. Signal the need for next-hop determination by deleting the * NCE (RFC 4861) */ uip_ds6_reg_rm(locreg); /* And then, delete neighbor and corresponding router (as hosts only keep * NCEs for routers in 6lowpan-nd) */ locnbr = uip_ds6_nbr_lookup(&locreg->defrt->ipaddr); uip_ds6_nbr_rm(locnbr); uip_ds6_defrt_rm(locreg->defrt); /* Since we are deleting a default router, we must delete also all * registrations with that router. * Be careful here, uip_ds6_reg_cleanup_defrt() modifies the value of locreg!*/ uip_ds6_reg_cleanup_defrt(locreg->defrt); /* We will also need to start sending RS, as specified in I-D.ietf-6lowpan-nd * for NUD failure case */ uip_ds6_send_rs(NULL); uip_ds6_if.registration_in_progress = NULL; } else { locreg->reg_count++; timer_restart(&locreg->registration_timer); uip_nd6_ns_output(&locreg->addr->ipaddr, &locreg->defrt->ipaddr, &locreg->defrt->ipaddr, 1, UIP_ND6_REGISTRATION_LIFETIME); } allow_output = 0; /* Prevent this invocation from sending anything else */ } } else { /* There are no registrations in progress, let's see this entry needs (re)registration * or deletion */ if ((locreg->state == REG_GARBAGE_COLLECTIBLE) || (locreg->state == REG_TO_BE_UNREGISTERED) || ((locreg->state == REG_REGISTERED) && (stimer_remaining(&locreg->reg_lifetime) < stimer_elapsed(&locreg->reg_lifetime)))) { /* Issue (re)registration */ uip_ds6_if.registration_in_progress = locreg; locreg->reg_count++; timer_set(&locreg->registration_timer, (uip_ds6_if.retrans_timer / 1000) * (CLOCK_SECOND /* FIXME @@@jwg!!!!*/+250)); if (locreg->state == REG_TO_BE_UNREGISTERED) { uip_nd6_ns_output(&locreg->addr->ipaddr, &locreg->defrt->ipaddr, &locreg->defrt->ipaddr, 1, 0); } else { uip_nd6_ns_output(&locreg->addr->ipaddr, &locreg->defrt->ipaddr, &locreg->defrt->ipaddr, 1, UIP_ND6_REGISTRATION_LIFETIME); } allow_output = 0; /* Prevent this invocation from sending anything else */ } } } } } /* Periodic processing on unicast addresses */ for(locaddr = uip_ds6_if.addr_list; locaddr < uip_ds6_if.addr_list + UIP_DS6_ADDR_NB; locaddr++) { if(locaddr->isused) { if((!locaddr->isinfinite) && (stimer_expired(&locaddr->vlifetime))) { uip_ds6_addr_rm(locaddr); } else if (allow_output) { if (stimer_remaining(&locaddr->vlifetime) < min_lifetime) { min_lifetime = stimer_remaining(&locaddr->vlifetime); min_defrt = locaddr->defrt; } } } } /* Periodic processing on default routers */ if (uip_ds6_defrt_choose() == NULL) { if (allow_output) { /* If default router list is empty, start sending RS */ uip_ds6_send_rs(NULL); allow_output = 0; /* Prevent this invocation from sending anything else */ } } else { for(locdefrt = uip_ds6_defrt_list; locdefrt < uip_ds6_defrt_list + UIP_DS6_DEFRT_NB; locdefrt++) { if((locdefrt->isused) && (!locdefrt->isinfinite)) { if (stimer_expired(&(locdefrt->lifetime))) { uip_ds6_defrt_rm(locdefrt); /* If default router list is empty, we will start sending RS in * the next invocation of ds6_periodic() */ } else { if (allow_output) { if (stimer_remaining(&locdefrt->lifetime) < min_lifetime) { min_lifetime = stimer_remaining(&locdefrt->lifetime); min_defrt = locdefrt; } } } } } } #if !UIP_CONF_ROUTER /* Periodic processing on prefixes */ for (locprefix = uip_ds6_prefix_list; locprefix < uip_ds6_prefix_list + UIP_DS6_PREFIX_NB; locprefix++) { if((locprefix->isused) && (!locprefix->isinfinite)) { if (stimer_expired(&locprefix->vlifetime)) { uip_ds6_prefix_rm(locprefix); } else if (allow_output) { if (stimer_remaining(&locprefix->vlifetime) < min_lifetime) { min_lifetime = stimer_remaining(&locprefix->vlifetime); min_defrt = locprefix->defrt; } } } } #endif /* !UIP_CONF_ROUTER */ #if CONF_6LOWPAN_ND_6CO /* Periodic processing on contexts */ for(loccontext = uip_ds6_addr_context_table; loccontext < uip_ds6_addr_context_table + SICSLOWPAN_CONF_MAX_ADDR_CONTEXTS; loccontext++) { if(loccontext->state != NOT_IN_USE) { if (stimer_expired(&loccontext->vlifetime)) { if (loccontext->state != EXPIRED) { loccontext->state = IN_USE_UNCOMPRESS_ONLY; stimer_set(&loccontext->vlifetime, 2 * loccontext->defrt_lifetime); } else { uip_ds6_context_rm(loccontext); } } else if (allow_output) { if (stimer_remaining(&loccontext->vlifetime) < min_lifetime) { min_lifetime = stimer_remaining(&loccontext->vlifetime); min_defrt = loccontext->defrt; } } } } #endif /* CONF_6LOWPAN_ND_6CO */ /* Start sending RS well before the minimum of the lifetimes (def. router, * context, or prefix) expires */ if ((allow_output) && (min_lifetime < UIP_DS6_LIFETIME_THRESHOLD)) { /* Start sending RSs to the router with minimum lifetime (if possible) */ uip_ds6_send_rs(min_defrt); allow_output = 0; } /* Periodic processing on neighbors */ for(locnbr = uip_ds6_nbr_cache; locnbr < uip_ds6_nbr_cache + UIP_DS6_NBR_NB; locnbr++) { if(locnbr->isused) { switch (locnbr->state) { #if UIP_CONF_ROUTER /* There can not be INCOMPLETE NCEs in a host in 6lowpan-nd */ case NBR_INCOMPLETE: if (allow_output) { if(locnbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) { uip_ds6_nbr_rm(locnbr); } else if(stimer_expired(&(locnbr->sendns))) { locnbr->nscount++; PRINTF("NBR_INCOMPLETE: NS %u\n", locnbr->nscount); uip_nd6_ns_output(NULL, NULL, &locnbr->ipaddr); stimer_set(&(locnbr->sendns), uip_ds6_if.retrans_timer / 1000); allow_output = 0; } } break; #endif /* UIP_CONF_ROUTER */ case NBR_REACHABLE: if(stimer_expired(&(locnbr->reachable))) { PRINTF("REACHABLE: moving to STALE ("); PRINT6ADDR(&locnbr->ipaddr); PRINTF(")\n"); locnbr->state = NBR_STALE; NEIGHBOR_STATE_CHANGED(locnbr); } break; case NBR_DELAY: if (allow_output) { if(stimer_expired(&(locnbr->reachable))) { locnbr->state = NBR_PROBE; locnbr->nscount = 1; NEIGHBOR_STATE_CHANGED(locnbr); PRINTF("DELAY: moving to PROBE + NS %u\n", locnbr->nscount); uip_nd6_ns_output(NULL, &locnbr->ipaddr, &locnbr->ipaddr, 0, 0); stimer_set(&(locnbr->sendns), uip_ds6_if.retrans_timer / 1000); allow_output = 0; } } break; case NBR_PROBE: if (allow_output) { if(locnbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) { PRINTF("PROBE END \n"); if((locdefrt = uip_ds6_defrt_lookup(&locnbr->ipaddr)) != NULL) { uip_ds6_defrt_rm(locdefrt); } uip_ds6_nbr_rm(locnbr); } else if(stimer_expired(&(locnbr->sendns))) { locnbr->nscount++; PRINTF("PROBE: NS %u\n", locnbr->nscount); uip_nd6_ns_output(NULL, &locnbr->ipaddr, &locnbr->ipaddr, 0, 0); stimer_set(&(locnbr->sendns), uip_ds6_if.retrans_timer / 1000); allow_output = 0; } } break; default: break; } } } #if UIP_CONF_ROUTER & UIP_ND6_SEND_RA /* Periodic RA sending */ if(stimer_expired(&uip_ds6_timer_ra)) { uip_ds6_send_ra_periodic(); } #endif /* UIP_CONF_ROUTER & UIP_ND6_SEND_RA */ etimer_reset(&uip_ds6_timer_periodic); return; }