/*---------------------------------------------------------------------------*/ int rpl_set_default_route(rpl_instance_t *instance, uip_ipaddr_t *from) { if(instance->def_route != NULL) { PRINTF("RPL: Removing default route through "); PRINT6ADDR(&instance->def_route->ipaddr); PRINTF("\n"); uip_ds6_defrt_rm(instance->def_route); instance->def_route = NULL; } if(from != NULL) { PRINTF("RPL: Adding default route through "); PRINT6ADDR(from); PRINTF("\n"); instance->def_route = uip_ds6_defrt_add(from, RPL_DEFAULT_ROUTE_INFINITE_LIFETIME ? 0 : RPL_LIFETIME(instance, instance->default_lifetime)); if(instance->def_route == NULL) { return 0; } } else { PRINTF("RPL: Removing default route\n"); if(instance->def_route != NULL) { uip_ds6_defrt_rm(instance->def_route); } else { PRINTF("RPL: Not actually removing default route, since instance had no default route\n"); } } return 1; }
/*---------------------------------------------------------------------------*/ void rpl_nullify_parent(rpl_parent_t *parent) { rpl_dag_t *dag = parent->dag; #if WITH_ORPL /* We don't have a preferred parent in ORPL. * We simply recalculate our EDC. */ dag->instance->of->calculate_rank(parent, 0); return; #endif /* WITH_ORPL */ /* This function can be called when the preferred parent is NULL, so we need to handle this condition in order to trigger uip_ds6_defrt_rm. */ if(parent == dag->preferred_parent || dag->preferred_parent == NULL) { rpl_set_preferred_parent(dag, NULL); dag->rank = INFINITE_RANK; if(dag->joined) { if(dag->instance->def_route != NULL) { PRINTF("RPL: Removing default route "); PRINT6ADDR(rpl_get_parent_ipaddr(parent)); PRINTF("\n"); uip_ds6_defrt_rm(dag->instance->def_route); dag->instance->def_route = NULL; } dao_output(parent, RPL_ZERO_LIFETIME); } } PRINTF("RPL: Nullifying parent "); PRINT6ADDR(rpl_get_parent_ipaddr(parent)); PRINTF("\n"); }
/*---------------------------------------------------------------------------*/ void rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent) { if(parent == dag_src->preferred_parent) { rpl_set_preferred_parent(dag_src, NULL); dag_src->rank = INFINITE_RANK; if(dag_src->joined && dag_src->instance->def_route != NULL) { PRINTF("RPL: Removing default route "); PRINT6ADDR(rpl_get_parent_ipaddr(parent)); PRINTF("\n"); PRINTF("rpl_move_parent\n"); uip_ds6_defrt_rm(dag_src->instance->def_route); dag_src->instance->def_route = NULL; } } else if(dag_src->joined) { /* Remove uIPv6 routes that have this parent as the next hop. */ rpl_remove_routes_by_nexthop(rpl_get_parent_ipaddr(parent), dag_src); } PRINTF("RPL: Moving parent "); PRINT6ADDR(rpl_get_parent_ipaddr(parent)); PRINTF("\n"); parent->dag = dag_dst; }
/*---------------------------------------------------------------------------*/ void rpl_nullify_parent(rpl_parent_t *parent) { rpl_dag_t *dag = parent->dag; /* This function can be called when the preferred parent is NULL, so we need to handle this condition in order to trigger uip_ds6_defrt_rm. */ if(parent == dag->preferred_parent || dag->preferred_parent == NULL) { dag->rank = INFINITE_RANK; if(dag->joined) { if(dag->instance->def_route != NULL) { PRINTF("RPL: Removing default route "); PRINT6ADDR(rpl_get_parent_ipaddr(parent)); PRINTF("\n"); uip_ds6_defrt_rm(dag->instance->def_route); dag->instance->def_route = NULL; } /* Send No-Path DAO only to preferred parent, if any */ if(parent == dag->preferred_parent) { dao_output(parent, RPL_ZERO_LIFETIME); rpl_set_preferred_parent(dag, NULL); } } } PRINTF("RPL: Nullifying parent "); PRINT6ADDR(rpl_get_parent_ipaddr(parent)); PRINTF("\n"); }
int rpl_set_default_route(rpl_dag_t *dag, uip_ipaddr_t *from) { if(dag->def_route != NULL) { PRINTF("RPL: Removing default route through "); PRINT6ADDR(&dag->def_route->ipaddr); PRINTF("\n"); uip_ds6_defrt_rm(dag->def_route); } if(from != NULL) { PRINTF("RPL: Adding default route through "); PRINT6ADDR(from); PRINTF("\n"); if(DEFAULT_ROUTE_LIFETIME == INFINITE_LIFETIME) { dag->def_route = uip_ds6_defrt_add(from, 0); } else { dag->def_route = uip_ds6_defrt_add(from, DEFAULT_ROUTE_LIFETIME); } if(dag->def_route == NULL) { return 0; } } return 1; }
void rpl_move_parent(rpl_dag_t *dag_src, rpl_dag_t *dag_dst, rpl_parent_t *parent) { if(parent == dag_src->preferred_parent) { dag_src->preferred_parent = NULL; dag_src->rank = INFINITE_RANK; if(dag_src->joined && dag_src->instance->def_route != NULL) { if(dag_src->instance->def_route->isused) { PRINTF("RPL: Removing default route "); PRINT6ADDR(&parent->addr); PRINTF("\n"); uip_ds6_defrt_rm(dag_src->instance->def_route); } dag_src->instance->def_route = NULL; } } else if(dag_src->joined) { /* Remove uIPv6 routes that have this parent as the next hop. */ rpl_remove_routes_by_nexthop(&parent->addr, dag_src); } PRINTF("RPL: Moving parent "); PRINT6ADDR(&parent->addr); PRINTF("\n"); list_remove(dag_src->parents, parent); parent->dag = dag_dst; list_add(dag_dst->parents, parent); }
int rpl_set_default_route(rpl_instance_t *instance, uip_ipaddr_t *from) { if(instance->def_route != NULL) { if(instance->def_route->isused) { PRINTF("RPL: Removing default route through "); PRINT6ADDR(&instance->def_route->ipaddr); PRINTF("\n"); uip_ds6_defrt_rm(instance->def_route); } instance->def_route = NULL; } if(from != NULL) { PRINTF("RPL: Adding default route through "); PRINT6ADDR(from); PRINTF("\n"); instance->def_route = uip_ds6_defrt_add(from, RPL_LIFETIME(instance, instance->default_lifetime)); if(instance->def_route == NULL) { return 0; } } return 1; }
int rpl_remove_parent(rpl_dag_t *dag, rpl_parent_t *parent) { uip_ds6_defrt_t *defrt; /* Remove uIPv6 routes that have this parent as the next hop. **/ uip_ds6_route_rm_by_nexthop(&parent->addr); defrt = uip_ds6_defrt_lookup(&parent->addr); if(defrt != NULL) { PRINTF("RPL: Removing default route "); PRINT6ADDR(&parent->addr); PRINTF("\n"); uip_ds6_defrt_rm(defrt); dag->def_route = NULL; } PRINTF("RPL: Removing parent "); PRINT6ADDR(&parent->addr); PRINTF("\n"); if(parent == dag->preferred_parent) { dag->preferred_parent = NULL; } list_remove(dag->parents, parent); memb_free(&parent_memb, parent); return 0; }
/*---------------------------------------------------------------------------*/ void uip_ds6_neighbor_periodic(void) { /* Periodic processing on neighbors */ uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors); while(nbr != NULL) { switch(nbr->state) { case NBR_REACHABLE: if(stimer_expired(&nbr->reachable)) { PRINTF("REACHABLE: moving to STALE ("); PRINT6ADDR(&nbr->ipaddr); PRINTF(")\n"); nbr->state = NBR_STALE; } break; #if UIP_ND6_SEND_NA case NBR_INCOMPLETE: if(nbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) { uip_ds6_nbr_rm(nbr); } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) { nbr->nscount++; PRINTF("NBR_INCOMPLETE: NS %u\n", nbr->nscount); uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr); stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000); } break; case NBR_DELAY: if(stimer_expired(&nbr->reachable)) { nbr->state = NBR_PROBE; nbr->nscount = 0; PRINTF("DELAY: moving to PROBE\n"); stimer_set(&nbr->sendns, 0); } break; case NBR_PROBE: if(nbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) { uip_ds6_defrt_t *locdefrt; PRINTF("PROBE END\n"); if((locdefrt = uip_ds6_defrt_lookup(&nbr->ipaddr)) != NULL) { if (!locdefrt->isinfinite) { uip_ds6_defrt_rm(locdefrt); } } uip_ds6_nbr_rm(nbr); } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) { nbr->nscount++; PRINTF("PROBE: NS %u\n", nbr->nscount); uip_nd6_ns_output(NULL, &nbr->ipaddr, &nbr->ipaddr); stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000); } break; #endif /* UIP_ND6_SEND_NA */ default: break; } nbr = nbr_table_next(ds6_neighbors, nbr); } }
/*---------------------------------------------------------------------------*/ int rpl_dag_root_init_dag_immediately(void) { struct uip_ds6_addr *root_if; int i; uint8_t state; uip_ipaddr_t *ipaddr = NULL; rpl_dag_root_init(); for(i = 0; i < UIP_DS6_ADDR_NB; i++) { state = uip_ds6_if.addr_list[i].state; if(uip_ds6_if.addr_list[i].isused && state == ADDR_PREFERRED && !uip_is_addr_linklocal(&uip_ds6_if.addr_list[i].ipaddr)) { ipaddr = &uip_ds6_if.addr_list[i].ipaddr; } } if(ipaddr != NULL) { root_if = uip_ds6_addr_lookup(ipaddr); if(root_if != NULL) { rpl_dag_t *dag; uip_ipaddr_t prefix; rpl_set_root(RPL_DEFAULT_INSTANCE, ipaddr); dag = rpl_get_any_dag(); /* If there are routes in this dag, we remove them all as we are from now on the new dag root and the old routes are wrong */ if(RPL_IS_STORING(dag->instance)) { rpl_remove_routes(dag); } if(dag->instance != NULL && dag->instance->def_route != NULL) { uip_ds6_defrt_rm(dag->instance->def_route); dag->instance->def_route = NULL; } uip_ip6addr(&prefix, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0); rpl_set_prefix(dag, &prefix, 64); PRINTF("RPL: rpl_dag_root_init_dag: created a new RPL dag\n"); return 0; } else { PRINTF("RPL: rpl_dag_root_init_dag: failed to create a new RPL DAG\n"); return -1; } } else { PRINTF("RPL: rpl_dag_root_init_dag: failed to create a new RPL DAG, no preferred IP address found\n"); return -2; } }
/*---------------------------------------------------------------------------*/ void uip_ds6_br_periodic(void) { #if !UIP_CONF_6LBR for(locbr = uip_ds6_br_list; locbr < uip_ds6_br_list + UIP_DS6_BR_NB; locbr++) { if(locbr->state == BR_ST_USED && stimer_expired(&locbr->timeout)) { /* remove all thing associate to border router */ uip_ds6_br_rm(locbr); } else if(stimer_expired(&locbr->rs_timer) && (locbr->state == BR_ST_MUST_SEND_RS || locbr->state == BR_ST_SENDING_RS)) { /* Send RS if needed well before all timer expired */ uip_ds6_defrt_t *d; d = list_head(defaultrouterlist); uint8_t allnotdone = 0; while(d != NULL) { if(d->br == locbr) { if(d->state != DEFRT_ST_SENDING_RS && locbr->state == BR_ST_MUST_SEND_RS) { /* Init defrt to send unicast RS */ d->state = DEFRT_ST_SENDING_RS; } if(d->state == DEFRT_ST_SENDING_RS) { if(locbr->rscount > UIP_ND6_MAX_RTR_SOLICITATIONS) { uip_ds6_defrt_rm(d); } else { /* Must send unicast RS */ uip_nd6_rs_unicast_output(&d->ipaddr); allnotdone = 1; } } } d = list_item_next(d); } if(list_head(defaultrouterlist) == NULL) { uip_ds6_send_rs(); locbr->state = BR_ST_USED; return; } if(locbr->state == BR_ST_MUST_SEND_RS) { locbr->state = BR_ST_SENDING_RS; locbr->rscount = 1; } else if(!allnotdone) { locbr->state = BR_ST_USED; } else { locbr->rscount++; } stimer_set(&locbr->rs_timer, UIP_ND6_MAX_RTR_SOLICITATION_DELAY); } } #endif /* !UIP_CONF_6LBR */ }
/*---------------------------------------------------------------------------*/ int simple_rpl_init_dag_immediately(void) { struct uip_ds6_addr *root_if; int i; uint8_t state; uip_ipaddr_t *ipaddr = NULL; for(i = 0; i < UIP_DS6_ADDR_NB; i++) { state = uip_ds6_if.addr_list[i].state; if(uip_ds6_if.addr_list[i].isused && state == ADDR_PREFERRED && !uip_is_addr_link_local(&uip_ds6_if.addr_list[i].ipaddr)) { ipaddr = &uip_ds6_if.addr_list[i].ipaddr; } } if(ipaddr != NULL) { root_if = uip_ds6_addr_lookup(ipaddr); if(root_if != NULL) { rpl_dag_t *dag; uip_ipaddr_t prefix; rpl_set_root(RPL_DEFAULT_INSTANCE, ipaddr); dag = rpl_get_any_dag(); /* If there are routes in this dag, we remove them all as we are from now on the new dag root and the old routes are wrong */ rpl_remove_routes(dag); if(dag->instance != NULL && dag->instance->def_route != NULL) { uip_ds6_defrt_rm(dag->instance->def_route); dag->instance->def_route = NULL; } #if CONTIKI_TARGET_TRXEB1120 || CONTIKI_TARGET_ETH1120 || CONTIKI_TARGET_TRXEB2520 || CONTIKI_TARGET_TRXEB1101 || CONTIKI_TARGET_ETH1101 || CONTIKI_TARGET_ETH2520 uip_ip6addr(&prefix, 0xfc00, 0, 0xabba, 0xabba, 0, 0, 0, 0); #else /* CONTIKI_TARGET_TRXEB1120 */ uip_ip6addr(&prefix, 0xfc00, 0, 0, 0, 0, 0, 0, 0); #endif /* CONTIKI_TARGET_TRXEB1120 */ rpl_set_prefix(dag, &prefix, 64); printf("\r\nsimple_rpl_init_dag: created a new RPL dag\n"); return 0; } else { printf("\r\nsimple_rpl_init_dag: failed to create a new RPL DAG\n"); return -1; } } else { printf("\r\nsimple_rpl_init_dag: failed to create a new RPL DAG, no preferred IP address found\n"); return -2; } }
/*---------------------------------------------------------------------------*/ void uip_ds6_defrt_periodic(void) { uip_ds6_defrt_t *d; d = list_head(defaultrouterlist); while(d != NULL) { if(!d->isinfinite && stimer_expired(&d->lifetime)) { PRINTF("uip_ds6_defrt_periodic: defrt lifetime expired\n"); uip_ds6_defrt_rm(d); d = list_head(defaultrouterlist); } else { d = list_item_next(d); } } }
/*---------------------------------------------------------------------------*/ void rpl_nullify_parent(rpl_dag_t *dag, rpl_parent_t *parent) { if(parent == dag->preferred_parent) { dag->preferred_parent = NULL; dag->rank = INFINITE_RANK; if(dag->joined) { if(dag->instance->def_route != NULL) { PRINTF("RPL: Removing default route "); PRINT6ADDR(&parent->addr); PRINTF("\n"); uip_ds6_defrt_rm(dag->instance->def_route); dag->instance->def_route = NULL; } dao_output(parent, RPL_ZERO_LIFETIME); } } PRINTF("RPL: Nullifying parent "); PRINT6ADDR(&parent->addr); PRINTF("\n"); }
int rpl_set_default_route(rpl_dag_t *dag, uip_ipaddr_t *from) { if(dag->def_route != NULL) { PRINTF("RPL: Removing default route through "); PRINT6ADDR(&dag->def_route->ipaddr); PRINTF("\n"); uip_ds6_defrt_rm(dag->def_route); } if(from != NULL) { PRINTF("RPL: Adding default route through "); PRINT6ADDR(from); PRINTF("\n"); dag->def_route = uip_ds6_defrt_add(from, RPL_LIFETIME(dag, dag->default_lifetime)); if(dag->def_route == NULL) { return 0; } } return 1; }
/** * Neighbor Advertisement Processing * * we might have to send a pkt that had been buffered while address * resolution was performed (if we support buffering, see UIP_CONF_QUEUE_PKT) * * As per RFC 4861, on link layer that have addresses, TLLAO options MUST be * included when responding to multicast solicitations, SHOULD be included in * response to unicast (here we assume it is for now) * * NA can be received after sending NS for DAD, Address resolution or NUD. Can * be unsolicited as well. * It can trigger update of the state of the neighbor in the neighbor cache, * router in the router list. * If the NS was for DAD, it means DAD failed * */ static void na_input(void) { uint8_t is_llchange; uint8_t is_router; uint8_t is_solicited; uint8_t is_override; uip_lladdr_t lladdr_aligned; PRINTF("Received NA from "); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF(" to "); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF(" with target address "); PRINT6ADDR((uip_ipaddr_t *) (&UIP_ND6_NA_BUF->tgtipaddr)); PRINTF("\n"); UIP_STAT(++uip_stat.nd6.recv); /* * booleans. the three last one are not 0 or 1 but 0 or 0x80, 0x40, 0x20 * but it works. Be careful though, do not use tests such as is_router == 1 */ is_llchange = 0; is_router = ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_ROUTER)); is_solicited = ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_SOLICITED)); is_override = ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_OVERRIDE)); #if UIP_CONF_IPV6_CHECKS if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) || (UIP_ICMP_BUF->icode != 0) || (uip_is_addr_mcast(&UIP_ND6_NA_BUF->tgtipaddr)) || (is_solicited && uip_is_addr_mcast(&UIP_IP_BUF->destipaddr))) { PRINTF("NA received is bad\n"); goto discard; } #endif /*UIP_CONF_IPV6_CHECKS */ /* Options processing: we handle TLLAO, and must ignore others */ nd6_opt_offset = UIP_ND6_NA_LEN; nd6_opt_llao = NULL; while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) { #if UIP_CONF_IPV6_CHECKS if(UIP_ND6_OPT_HDR_BUF->len == 0) { PRINTF("NA received is bad\n"); goto discard; } #endif /*UIP_CONF_IPV6_CHECKS */ switch (UIP_ND6_OPT_HDR_BUF->type) { case UIP_ND6_OPT_TLLAO: nd6_opt_llao = (uint8_t *)UIP_ND6_OPT_HDR_BUF; break; default: PRINTF("ND option not supported in NA\n"); break; } nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3); } addr = uip_ds6_addr_lookup(&UIP_ND6_NA_BUF->tgtipaddr); /* Message processing, including TLLAO if any */ if(addr != NULL) { #if UIP_ND6_DEF_MAXDADNS > 0 if(addr->state == ADDR_TENTATIVE) { uip_ds6_dad_failed(addr); } #endif /*UIP_ND6_DEF_MAXDADNS > 0 */ PRINTF("NA received is bad\n"); goto discard; } else { const uip_lladdr_t *lladdr; nbr = uip_ds6_nbr_lookup(&UIP_ND6_NA_BUF->tgtipaddr); if(nbr == NULL) { goto discard; } lladdr = uip_ds6_nbr_get_ll(nbr); if(lladdr == NULL) { goto discard; } if(nd6_opt_llao != NULL) { is_llchange = memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr, UIP_LLADDR_LEN); } if(nbr->state == NBR_INCOMPLETE) { if(nd6_opt_llao == NULL || !extract_lladdr_from_llao_aligned(&lladdr_aligned)) { goto discard; } if(nbr_table_update_lladdr((const linkaddr_t *)lladdr, (const linkaddr_t *)&lladdr_aligned, 1) == 0) { /* failed to update the lladdr */ goto discard; } /* Note: No need to refresh the state of the nbr here. * It has already been refreshed upon receiving the unicast IPv6 ND packet. * See: uip_ds6_nbr_refresh_reachable_state() */ if(!is_solicited) { nbr->state = NBR_STALE; } nbr->isrouter = is_router; } else { /* NBR is not INCOMPLETE */ if(!is_override && is_llchange) { if(nbr->state == NBR_REACHABLE) { nbr->state = NBR_STALE; } goto discard; } else { /** * If this is an cache override, or same lladdr, or no llao - * do updates of nbr states. */ if(is_override || !is_llchange || nd6_opt_llao == NULL) { if(nd6_opt_llao != NULL && is_llchange) { if(!extract_lladdr_from_llao_aligned(&lladdr_aligned) || nbr_table_update_lladdr((const linkaddr_t *) lladdr, (const linkaddr_t *) &lladdr_aligned, 1) == 0) { /* failed to update the lladdr */ goto discard; } } /* Note: No need to refresh the state of the nbr here. * It has already been refreshed upon receiving the unicast IPv6 ND packet. * See: uip_ds6_nbr_refresh_reachable_state() */ } } if(nbr->isrouter && !is_router) { defrt = uip_ds6_defrt_lookup(&UIP_IP_BUF->srcipaddr); if(defrt != NULL) { uip_ds6_defrt_rm(defrt); } } nbr->isrouter = is_router; } } #if UIP_CONF_IPV6_QUEUE_PKT /* The nbr is now reachable, check if we had buffered a pkt for it */ /*if(nbr->queue_buf_len != 0) { uip_len = nbr->queue_buf_len; memcpy(UIP_IP_BUF, nbr->queue_buf, uip_len); nbr->queue_buf_len = 0; return; }*/ if(uip_packetqueue_buflen(&nbr->packethandle) != 0) { uip_len = uip_packetqueue_buflen(&nbr->packethandle); memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len); uip_packetqueue_free(&nbr->packethandle); return; } #endif /*UIP_CONF_IPV6_QUEUE_PKT */ discard: uip_clear_buf(); return; }
/*---------------------------------------------------------------------------*/ 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; }
/*---------------------------------------------------------------------------*/ uip_ds6_nbr_t * uip_ds6_nbr_add(uip_ipaddr_t * ipaddr, uip_lladdr_t * lladdr, u8_t isrouter, u8_t state) { int r; r = uip_ds6_list_loop ((uip_ds6_element_t *) uip_ds6_nbr_cache, UIP_DS6_NBR_NB, sizeof(uip_ds6_nbr_t), ipaddr, 128, (uip_ds6_element_t **) &locnbr); // printf("r %d\n", r); if(r == FREESPACE) { locnbr->isused = 1; uip_ipaddr_copy(&(locnbr->ipaddr), ipaddr); if(lladdr != NULL) { memcpy(&(locnbr->lladdr), lladdr, UIP_LLADDR_LEN); } else { memset(&(locnbr->lladdr), 0, UIP_LLADDR_LEN); } locnbr->isrouter = isrouter; locnbr->state = state; /* timers are set separately, for now we put them in expired state */ stimer_set(&(locnbr->reachable), 0); stimer_set(&(locnbr->sendns), 0); locnbr->nscount = 0; PRINTF("Adding neighbor with ip addr"); PRINT6ADDR(ipaddr); PRINTF("link addr"); PRINTLLADDR((&(locnbr->lladdr))); PRINTF("state %u\n", state); NEIGHBOR_STATE_CHANGED(locnbr); locnbr->last_lookup = clock_time(); // printf("add %p\n", locnbr); return locnbr; } else if(r == NOSPACE) { /* We did not find any empty slot on the neighbor list, so we need to remove one old entry to make room. */ uip_ds6_nbr_t *n, *oldest; clock_time_t oldest_time; oldest = NULL; oldest_time = clock_time(); for(n = uip_ds6_nbr_cache; n < &uip_ds6_nbr_cache[UIP_DS6_NBR_NB]; n++) { if(n->isused) { if((n->last_lookup < oldest_time) && (uip_ds6_is_nbr_garbage_collectible(n))) { /* We do not want to remove any non-garbage-collectible entry */ oldest = n; oldest_time = n->last_lookup; } } } if(oldest != NULL) { // printf("rm3\n"); uip_ds6_nbr_rm(oldest); locdefrt = uip_ds6_defrt_lookup(&oldest->ipaddr); uip_ds6_defrt_rm(locdefrt); uip_ds6_reg_cleanup_defrt(locdefrt); return uip_ds6_nbr_add(ipaddr, lladdr, isrouter, state); } } PRINTF("uip_ds6_nbr_add drop\n"); return NULL; }
/* * Process a Router Advertisement * * - Possible actions when receiving a RA: add router to router list, * recalculate reachable time, update link hop limit, update retrans timer. * - If MTU option: update MTU. * - If SLLAO option: update entry in neighbor cache * - If prefix option: start autoconf, add prefix to prefix list */ void ra_input(void) { PRINTF("Received RA from"); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF("to"); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF("\n"); UIP_STAT(++uip_stat.nd6.recv); #if UIP_CONF_IPV6_CHECKS if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) || (!uip_is_addr_link_local(&UIP_IP_BUF->srcipaddr)) || (UIP_ICMP_BUF->icode != 0)) { PRINTF("RA received is bad"); goto discard; } #endif /*UIP_CONF_IPV6_CHECKS */ if(UIP_ND6_RA_BUF->cur_ttl != 0) { uip_ds6_if.cur_hop_limit = UIP_ND6_RA_BUF->cur_ttl; PRINTF("uip_ds6_if.cur_hop_limit %u\n", uip_ds6_if.cur_hop_limit); } if(UIP_ND6_RA_BUF->reachable_time != 0) { if(uip_ds6_if.base_reachable_time != uip_ntohl(UIP_ND6_RA_BUF->reachable_time)) { uip_ds6_if.base_reachable_time = uip_ntohl(UIP_ND6_RA_BUF->reachable_time); uip_ds6_if.reachable_time = uip_ds6_compute_reachable_time(); } } if(UIP_ND6_RA_BUF->retrans_timer != 0) { uip_ds6_if.retrans_timer = uip_ntohl(UIP_ND6_RA_BUF->retrans_timer); } /* Options processing */ nd6_opt_offset = UIP_ND6_RA_LEN; while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) { if(UIP_ND6_OPT_HDR_BUF->len == 0) { PRINTF("RA received is bad"); goto discard; } switch (UIP_ND6_OPT_HDR_BUF->type) { case UIP_ND6_OPT_SLLAO: PRINTF("Processing SLLAO option in RA\n"); nd6_opt_llao = (uint8_t *) UIP_ND6_OPT_HDR_BUF; nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr); if(nbr == NULL) { nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, (uip_lladdr_t *)&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], 1, NBR_STALE); } else { uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr); if(nbr->state == NBR_INCOMPLETE) { nbr->state = NBR_STALE; } if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr, UIP_LLADDR_LEN) != 0) { memcpy(lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], UIP_LLADDR_LEN); nbr->state = NBR_STALE; } nbr->isrouter = 1; } break; case UIP_ND6_OPT_MTU: PRINTF("Processing MTU option in RA\n"); uip_ds6_if.link_mtu = uip_ntohl(((uip_nd6_opt_mtu *) UIP_ND6_OPT_HDR_BUF)->mtu); break; case UIP_ND6_OPT_PREFIX_INFO: PRINTF("Processing PREFIX option in RA\n"); nd6_opt_prefix_info = (uip_nd6_opt_prefix_info *) UIP_ND6_OPT_HDR_BUF; if((uip_ntohl(nd6_opt_prefix_info->validlt) >= uip_ntohl(nd6_opt_prefix_info->preferredlt)) && (!uip_is_addr_link_local(&nd6_opt_prefix_info->prefix))) { /* on-link flag related processing */ if(nd6_opt_prefix_info->flagsreserved1 & UIP_ND6_RA_FLAG_ONLINK) { prefix = uip_ds6_prefix_lookup(&nd6_opt_prefix_info->prefix, nd6_opt_prefix_info->preflen); if(prefix == NULL) { if(nd6_opt_prefix_info->validlt != 0) { if(nd6_opt_prefix_info->validlt != UIP_ND6_INFINITE_LIFETIME) { prefix = uip_ds6_prefix_add(&nd6_opt_prefix_info->prefix, nd6_opt_prefix_info->preflen, uip_ntohl(nd6_opt_prefix_info-> validlt)); } else { prefix = uip_ds6_prefix_add(&nd6_opt_prefix_info->prefix, nd6_opt_prefix_info->preflen, 0); } } } else { switch (nd6_opt_prefix_info->validlt) { case 0: uip_ds6_prefix_rm(prefix); break; case UIP_ND6_INFINITE_LIFETIME: prefix->isinfinite = 1; break; default: PRINTF("Updating timer of prefix"); PRINT6ADDR(&prefix->ipaddr); PRINTF("new value %lu\n", uip_ntohl(nd6_opt_prefix_info->validlt)); stimer_set(&prefix->vlifetime, uip_ntohl(nd6_opt_prefix_info->validlt)); prefix->isinfinite = 0; break; } } } /* End of on-link flag related processing */ /* autonomous flag related processing */ if((nd6_opt_prefix_info->flagsreserved1 & UIP_ND6_RA_FLAG_AUTONOMOUS) && (nd6_opt_prefix_info->validlt != 0) && (nd6_opt_prefix_info->preflen == UIP_DEFAULT_PREFIX_LEN)) { uip_ipaddr_copy(&ipaddr, &nd6_opt_prefix_info->prefix); uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); addr = uip_ds6_addr_lookup(&ipaddr); if((addr != NULL) && (addr->type == ADDR_AUTOCONF)) { if(nd6_opt_prefix_info->validlt != UIP_ND6_INFINITE_LIFETIME) { /* The processing below is defined in RFC4862 section 5.5.3 e */ if((uip_ntohl(nd6_opt_prefix_info->validlt) > 2 * 60 * 60) || (uip_ntohl(nd6_opt_prefix_info->validlt) > stimer_remaining(&addr->vlifetime))) { PRINTF("Updating timer of address"); PRINT6ADDR(&addr->ipaddr); PRINTF("new value %lu\n", uip_ntohl(nd6_opt_prefix_info->validlt)); stimer_set(&addr->vlifetime, uip_ntohl(nd6_opt_prefix_info->validlt)); } else { stimer_set(&addr->vlifetime, 2 * 60 * 60); PRINTF("Updating timer of address "); PRINT6ADDR(&addr->ipaddr); PRINTF("new value %lu\n", (unsigned long)(2 * 60 * 60)); } addr->isinfinite = 0; } else { addr->isinfinite = 1; } } else { if(uip_ntohl(nd6_opt_prefix_info->validlt) == UIP_ND6_INFINITE_LIFETIME) { uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); } else { uip_ds6_addr_add(&ipaddr, uip_ntohl(nd6_opt_prefix_info->validlt), ADDR_AUTOCONF); } } } /* End of autonomous flag related processing */ } break; default: PRINTF("ND option not supported in RA"); break; } nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3); } defrt = uip_ds6_defrt_lookup(&UIP_IP_BUF->srcipaddr); if(UIP_ND6_RA_BUF->router_lifetime != 0) { if(nbr != NULL) { nbr->isrouter = 1; } if(defrt == NULL) { uip_ds6_defrt_add(&UIP_IP_BUF->srcipaddr, (unsigned long)(uip_ntohs(UIP_ND6_RA_BUF->router_lifetime))); } else { stimer_set(&(defrt->lifetime), (unsigned long)(uip_ntohs(UIP_ND6_RA_BUF->router_lifetime))); } } else { if(defrt != NULL) { uip_ds6_defrt_rm(defrt); } } #if UIP_CONF_IPV6_QUEUE_PKT /* If the nbr just became reachable (e.g. it was in NBR_INCOMPLETE state * and we got a SLLAO), check if we had buffered a pkt for it */ /* if((nbr != NULL) && (nbr->queue_buf_len != 0)) { uip_len = nbr->queue_buf_len; memcpy(UIP_IP_BUF, nbr->queue_buf, uip_len); nbr->queue_buf_len = 0; return; }*/ if(nbr != NULL && uip_packetqueue_buflen(&nbr->packethandle) != 0) { uip_len = uip_packetqueue_buflen(&nbr->packethandle); memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len); uip_packetqueue_free(&nbr->packethandle); return; } #endif /*UIP_CONF_IPV6_QUEUE_PKT */ discard: uip_len = 0; return; }
/** * Neighbor Advertisement Processing * * we might have to send a pkt that had been buffered while address * resolution was performed (if we support buffering, see UIP_CONF_QUEUE_PKT) * * As per RFC 4861, on link layer that have addresses, TLLAO options MUST be * included when responding to multicast solicitations, SHOULD be included in * response to unicast (here we assume it is for now) * * NA can be received after sending NS for DAD, Address resolution or NUD. Can * be unsolicited as well. * It can trigger update of the state of the neighbor in the neighbor cache, * router in the router list. * If the NS was for DAD, it means DAD failed * */ static void na_input(void) { #if CETIC_6LBR_SMARTBRIDGE uip_ds6_route_t * route; #endif uint8_t is_llchange; uint8_t is_router; uint8_t is_solicited; uint8_t is_override; PRINTF("Received NA from"); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF("to"); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF("with target address"); PRINT6ADDR((uip_ipaddr_t *) (&UIP_ND6_NA_BUF->tgtipaddr)); PRINTF("\n"); UIP_STAT(++uip_stat.nd6.recv); /* * booleans. the three last one are not 0 or 1 but 0 or 0x80, 0x40, 0x20 * but it works. Be careful though, do not use tests such as is_router == 1 */ is_llchange = 0; is_router = ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_ROUTER)); is_solicited = ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_SOLICITED)); is_override = ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_OVERRIDE)); #if UIP_CONF_IPV6_CHECKS if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) || (UIP_ICMP_BUF->icode != 0) || (uip_is_addr_mcast(&UIP_ND6_NA_BUF->tgtipaddr)) || (is_solicited && uip_is_addr_mcast(&UIP_IP_BUF->destipaddr))) { PRINTF("NA received is bad\n"); goto discard; } #endif /*UIP_CONF_IPV6_CHECKS */ /* Options processing: we handle TLLAO, and must ignore others */ nd6_opt_offset = UIP_ND6_NA_LEN; nd6_opt_llao = NULL; while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) { #if UIP_CONF_IPV6_CHECKS if(UIP_ND6_OPT_HDR_BUF->len == 0) { PRINTF("NA received is bad\n"); goto discard; } #endif /*UIP_CONF_IPV6_CHECKS */ switch (UIP_ND6_OPT_HDR_BUF->type) { case UIP_ND6_OPT_TLLAO: nd6_opt_llao = (uint8_t *)UIP_ND6_OPT_HDR_BUF; break; default: PRINTF("ND option not supported in NA\n"); break; } nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3); } #if CETIC_6LBR_SMARTBRIDGE /* Address Advertisement */ if ( (nvm_data.mode & CETIC_MODE_SMART_MULTI_BR) != 0 ) { if (uip_is_addr_mcast(&UIP_IP_BUF->destipaddr) && uip_is_mcast_group_id_all_nodes(&UIP_IP_BUF->destipaddr)) { LOG6LBR_6ADDR(INFO, &UIP_ND6_NA_BUF->tgtipaddr, "Received purge NA for "); #if CETIC_NODE_INFO node_info_rm_by_addr(&UIP_ND6_NA_BUF->tgtipaddr); #endif route = uip_ds6_route_lookup(&UIP_ND6_NA_BUF->tgtipaddr); if (route != NULL ) { uip_ds6_route_rm(route); } goto discard; } } #endif addr = uip_ds6_addr_lookup(&UIP_ND6_NA_BUF->tgtipaddr); /* Message processing, including TLLAO if any */ if(addr != NULL) { #if UIP_ND6_DEF_MAXDADNS > 0 if(addr->state == ADDR_TENTATIVE) { uip_ds6_dad_failed(addr); } #endif /*UIP_ND6_DEF_MAXDADNS > 0 */ PRINTF("NA received is bad\n"); goto discard; } else { uip_lladdr_t *lladdr; nbr = uip_ds6_nbr_lookup(&UIP_ND6_NA_BUF->tgtipaddr); lladdr = (uip_lladdr_t *)uip_ds6_nbr_get_ll(nbr); if(nbr == NULL) { goto discard; } if(nd6_opt_llao != 0) { is_llchange = memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], (void *)lladdr, UIP_LLADDR_LEN); } if(nbr->state == NBR_INCOMPLETE) { if(nd6_opt_llao == NULL) { goto discard; } memcpy(lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], UIP_LLADDR_LEN); if(is_solicited) { nbr->state = NBR_REACHABLE; nbr->nscount = 0; /* reachable time is stored in ms */ stimer_set(&(nbr->reachable), uip_ds6_if.reachable_time / 1000); } else { nbr->state = NBR_STALE; } nbr->isrouter = is_router; } else { if(!is_override && is_llchange) { if(nbr->state == NBR_REACHABLE) { nbr->state = NBR_STALE; } goto discard; } else { if(is_override || (!is_override && nd6_opt_llao != 0 && !is_llchange) || nd6_opt_llao == 0) { if(nd6_opt_llao != 0) { memcpy(lladdr, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], UIP_LLADDR_LEN); } if(is_solicited) { nbr->state = NBR_REACHABLE; /* reachable time is stored in ms */ stimer_set(&(nbr->reachable), uip_ds6_if.reachable_time / 1000); } else { if(nd6_opt_llao != 0 && is_llchange) { nbr->state = NBR_STALE; } } } } if(nbr->isrouter && !is_router) { defrt = uip_ds6_defrt_lookup(&UIP_IP_BUF->srcipaddr); if(defrt != NULL) { uip_ds6_defrt_rm(defrt); } } nbr->isrouter = is_router; } } #if UIP_CONF_IPV6_QUEUE_PKT /* The nbr is now reachable, check if we had buffered a pkt for it */ /*if(nbr->queue_buf_len != 0) { uip_len = nbr->queue_buf_len; memcpy(UIP_IP_BUF, nbr->queue_buf, uip_len); nbr->queue_buf_len = 0; return; }*/ if(uip_packetqueue_buflen(&nbr->packethandle) != 0) { uip_len = uip_packetqueue_buflen(&nbr->packethandle); memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len); uip_packetqueue_free(&nbr->packethandle); return; } #endif /*UIP_CONF_IPV6_QUEUE_PKT */ discard: uip_clear_buf(); return; }
/*---------------------------------------------------------------------------*/ void uip_ds6_periodic(void) { /* 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); #if UIP_ND6_DEF_MAXDADNS > 0 } else if((locaddr->state == ADDR_TENTATIVE) && (locaddr->dadnscount <= uip_ds6_if.maxdadns) && (timer_expired(&locaddr->dadtimer)) && (uip_len == 0)) { uip_ds6_dad(locaddr); #endif /* UIP_ND6_DEF_MAXDADNS > 0 */ } } } /* Periodic processing on default routers */ for(locdefrt = uip_ds6_defrt_list; locdefrt < uip_ds6_defrt_list + UIP_DS6_DEFRT_NB; locdefrt++) { if((locdefrt->isused) && (!locdefrt->isinfinite) && (stimer_expired(&(locdefrt->lifetime)))) { uip_ds6_defrt_rm(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 && stimer_expired(&(locprefix->vlifetime))) { uip_ds6_prefix_rm(locprefix); } } #endif /* !UIP_CONF_ROUTER */ /* 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) { case NBR_INCOMPLETE: if(locnbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) { uip_ds6_nbr_rm(locnbr); } else if(stimer_expired(&locnbr->sendns) && (uip_len == 0)) { 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); } break; case NBR_REACHABLE: if(stimer_expired(&locnbr->reachable)) { PRINTF("REACHABLE: moving to STALE ("); PRINT6ADDR(&locnbr->ipaddr); PRINTF(")\n"); locnbr->state = NBR_STALE; } break; case NBR_DELAY: if(stimer_expired(&locnbr->reachable)) { locnbr->state = NBR_PROBE; locnbr->nscount = 0; PRINTF("DELAY: moving to PROBE\n"); stimer_set(&locnbr->sendns, 0); } break; case NBR_PROBE: if(locnbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) { PRINTF("PROBE END\n"); if((locdefrt = uip_ds6_defrt_lookup(&locnbr->ipaddr)) != NULL) { if (!locdefrt->isinfinite) { uip_ds6_defrt_rm(locdefrt); } } uip_ds6_nbr_rm(locnbr); } else if(stimer_expired(&locnbr->sendns) && (uip_len == 0)) { locnbr->nscount++; PRINTF("PROBE: NS %u\n", locnbr->nscount); uip_nd6_ns_output(NULL, &locnbr->ipaddr, &locnbr->ipaddr); stimer_set(&locnbr->sendns, uip_ds6_if.retrans_timer / 1000); } break; default: break; } } } #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 */ etimer_reset(&uip_ds6_timer_periodic); return; }
/** Periodic processing on neighbors */ void uip_ds6_neighbor_periodic(void) { uip_ds6_nbr_t *nbr = nbr_table_head(ds6_neighbors); while(nbr != NULL) { switch(nbr->state) { case NBR_REACHABLE: if(stimer_expired(&nbr->reachable)) { #if UIP_CONF_IPV6_RPL /* when a neighbor leave its REACHABLE state and is a default router, instead of going to STALE state it enters DELAY state in order to force a NUD on it. Otherwise, if there is no upward traffic, the node never knows if the default router is still reachable. This mimics the 6LoWPAN-ND behavior. */ if(uip_ds6_defrt_lookup(&nbr->ipaddr) != NULL) { PRINTF("REACHABLE: defrt moving to DELAY ("); PRINT6ADDR(&nbr->ipaddr); PRINTF(")\n"); nbr->state = NBR_DELAY; stimer_set(&nbr->reachable, UIP_ND6_DELAY_FIRST_PROBE_TIME); nbr->nscount = 0; } else { PRINTF("REACHABLE: moving to STALE ("); PRINT6ADDR(&nbr->ipaddr); PRINTF(")\n"); nbr->state = NBR_STALE; } #else /* UIP_CONF_IPV6_RPL */ PRINTF("REACHABLE: moving to STALE ("); PRINT6ADDR(&nbr->ipaddr); PRINTF(")\n"); nbr->state = NBR_STALE; #endif /* UIP_CONF_IPV6_RPL */ } break; case NBR_INCOMPLETE: if(nbr->nscount >= UIP_ND6_MAX_MULTICAST_SOLICIT) { uip_ds6_nbr_rm(nbr); } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) { nbr->nscount++; PRINTF("NBR_INCOMPLETE: NS %u\n", nbr->nscount); uip_nd6_ns_output(NULL, NULL, &nbr->ipaddr); stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000); } break; case NBR_DELAY: if(stimer_expired(&nbr->reachable)) { nbr->state = NBR_PROBE; nbr->nscount = 0; PRINTF("DELAY: moving to PROBE\n"); stimer_set(&nbr->sendns, 0); } break; case NBR_PROBE: if(nbr->nscount >= UIP_ND6_MAX_UNICAST_SOLICIT) { uip_ds6_defrt_t *locdefrt; PRINTF("PROBE END\n"); if((locdefrt = uip_ds6_defrt_lookup(&nbr->ipaddr)) != NULL) { if (!locdefrt->isinfinite) { uip_ds6_defrt_rm(locdefrt); } } uip_ds6_nbr_rm(nbr); } else if(stimer_expired(&nbr->sendns) && (uip_len == 0)) { nbr->nscount++; PRINTF("PROBE: NS %u\n", nbr->nscount); uip_nd6_ns_output(NULL, &nbr->ipaddr, &nbr->ipaddr); stimer_set(&nbr->sendns, uip_ds6_if.retrans_timer / 1000); } break; default: break; } nbr = nbr_table_next(ds6_neighbors, nbr); } }