/*---------------------------------------------------------------------------*/ uip_ds6_nbr_t * uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, const uip_lladdr_t *lladdr, uint8_t isrouter, uint8_t state) { uip_ds6_nbr_t *nbr = nbr_table_add_lladdr(ds6_neighbors, (linkaddr_t*)lladdr); if(nbr) { uip_ipaddr_copy(&nbr->ipaddr, ipaddr); nbr->isrouter = isrouter; nbr->state = state; #if UIP_CONF_IPV6_QUEUE_PKT uip_packetqueue_new(&nbr->packethandle); #endif /* UIP_CONF_IPV6_QUEUE_PKT */ /* timers are set separately, for now we put them in expired state */ stimer_set(&nbr->reachable, 0); stimer_set(&nbr->sendns, 0); nbr->nscount = 0; PRINTF("Adding neighbor with ip addr "); PRINT6ADDR(ipaddr); PRINTF(" link addr "); PRINTLLADDR(lladdr); PRINTF(" state %u\n", state); NEIGHBOR_STATE_CHANGED(nbr); return nbr; } else { PRINTF("uip_ds6_nbr_add drop ip addr "); PRINT6ADDR(ipaddr); PRINTF(" link addr (%p) ", lladdr); PRINTLLADDR(lladdr); PRINTF(" state %u\n", state); return NULL; } }
/*---------------------------------------------------------------------------*/ rpl_parent_t * rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr) { rpl_parent_t *p = NULL; /* Is the parent known by ds6? Drop this request if not. * Typically, the parent is added upon receiving a DIO. */ uip_lladdr_t *lladdr = uip_ds6_nbr_lladdr_from_ipaddr(addr); PRINTF("RPL: rpl_add_parent lladdr %p\n", lladdr); if(lladdr != NULL) { /* Add parent in rpl_parents */ p = nbr_table_add_lladdr(rpl_parents, (rimeaddr_t *)lladdr); p->dag = dag; p->rank = dio->rank; p->dtsn = dio->dtsn; p->link_metric = RPL_INIT_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR; #if WITH_ORPL p->bc_ackcount = 0; #endif /* WITH_ORPL */ #if RPL_DAG_MC != RPL_DAG_MC_NONE memcpy(&p->mc, &dio->mc, sizeof(p->mc)); #endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */ } return p; }
/*---------------------------------------------------------------------------*/ rpl_parent_t * rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr) { rpl_parent_t *p = NULL; /* Is the parent known by ds6? Drop this request if not. * Typically, the parent is added upon receiving a DIO. */ uip_lladdr_t *lladdr = uip_ds6_nbr_lladdr_from_ipaddr(addr); // PRINTF("RPL: rpl_add_parent lladdr %p\n", lladdr); if(lladdr != NULL) { /* Add parent in rpl_parents */ p = nbr_table_add_lladdr(rpl_parents, (rimeaddr_t *)lladdr); p->dag = dag; p->rank = dio->rank; p->dtsn = dio->dtsn; p->rssi= cc2420_last_rssi-45; p->update_time = clock_seconds(); if(dag->rank > p->rank) p->flag= PRNT; else p->flag=NBR; p->link_metric = RPL_INIT_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR; #if RPL_DAG_MC != RPL_DAG_MC_NONE memcpy(&p->mc, &dio->mc, sizeof(p->mc)); #endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */ } return p; }
/*---------------------------------------------------------------------------*/ void phase_update(const linkaddr_t *neighbor, rtimer_clock_t time, uint32_t cycle_time, int mac_status) { struct phase *e; /* If we have an entry for this neighbor already, we renew it. */ e = nbr_table_get_from_lladdr(nbr_phase, neighbor); if(e != NULL) { if(mac_status == MAC_TX_OK) { #if PHASE_DRIFT_CORRECT e->drift = time-e->time; #endif e->time = time; if(cycle_time!=0){ e->cycle=cycle_time; } else{ e->cycle=CONTIKIMAC_CONF_CYCLE_TIME; } } /* If the neighbor didn't reply to us, it may have switched phase (rebooted). We try a number of transmissions to it before we drop it from the phase list. */ if(mac_status == MAC_TX_NOACK) { PRINTF("phase noacks %d to %d.%d\n", e->noacks, neighbor->u8[0], neighbor->u8[1]); e->noacks++; if(e->noacks == 1) { timer_set(&e->noacks_timer, MAX_NOACKS_TIME); } if(e->noacks >= MAX_NOACKS || timer_expired(&e->noacks_timer)) { PRINTF("drop %d\n", neighbor->u8[0]); nbr_table_remove(nbr_phase, e); return; } if(e->noacks >= MAX_NOACKbis){ e->cycle=CONTIKIMAC_CONF_CYCLE_TIME; } } else if(mac_status == MAC_TX_OK) { e->noacks = 0; } } else { /* No matching phase was found, so we allocate a new one. */ if(mac_status == MAC_TX_OK && e == NULL) { e = nbr_table_add_lladdr(nbr_phase, neighbor); if(e) { e->time = time; #if PHASE_DRIFT_CORRECT e->drift = 0; #endif e->noacks = 0; } } } }
/* Packet input callback. Updates statistics for receptions on a given link */ void link_stats_input_callback(const linkaddr_t *lladdr) { struct link_stats *stats; int16_t packet_rssi = packetbuf_attr(PACKETBUF_ATTR_RSSI); stats = nbr_table_get_from_lladdr(link_stats, lladdr); if(stats == NULL) { /* Add the neighbor */ stats = nbr_table_add_lladdr(link_stats, lladdr, NBR_TABLE_REASON_LINK_STATS, NULL); if(stats != NULL) { /* Initialize */ stats->rssi = packet_rssi; stats->etx = LINK_STATS_INIT_ETX(stats); } return; } /* Update RSSI EWMA */ stats->rssi = ((int32_t)stats->rssi * (EWMA_SCALE - EWMA_ALPHA) + (int32_t)packet_rssi * EWMA_ALPHA) / EWMA_SCALE; }
/*---------------------------------------------------------------------------*/ rpl_parent_t * rpl_add_parent(rpl_dag_t *dag, rpl_dio_t *dio, uip_ipaddr_t *addr) { rpl_parent_t *p = NULL; /* Is the parent known by ds6? Drop this request if not. * Typically, the parent is added upon receiving a DIO. */ const uip_lladdr_t *lladdr = uip_ds6_nbr_lladdr_from_ipaddr(addr); PRINTF("RPL: rpl_add_parent lladdr %p ", lladdr); PRINTLLADDR(lladdr); PRINTF(" "); PRINT6ADDR(addr); PRINTF("\n"); if(lladdr != NULL) { /* Add parent in rpl_parents */ p = nbr_table_add_lladdr(rpl_parents, (linkaddr_t *)lladdr); if(p == NULL) { PRINTF("RPL: rpl_add_parent p NULL\n"); } else { uip_ds6_nbr_t *nbr; nbr = rpl_get_nbr(p); p->dag = dag; p->rank = dio->rank; p->dtsn = dio->dtsn; /* Check whether we have a neighbor that has not gotten a link metric yet */ if(nbr != NULL && nbr->link_metric == 0) { nbr->link_metric = RPL_INIT_LINK_METRIC * RPL_DAG_MC_ETX_DIVISOR; } #if RPL_DAG_MC != RPL_DAG_MC_NONE memcpy(&p->mc, &dio->mc, sizeof(p->mc)); #endif /* RPL_DAG_MC != RPL_DAG_MC_NONE */ } } return p; }
/* Packet sent callback. Updates stats for transmissions to lladdr */ void link_stats_packet_sent(const linkaddr_t *lladdr, int status, int numtx) { struct link_stats *stats; uint16_t packet_etx; uint8_t ewma_alpha; if(status != MAC_TX_OK && status != MAC_TX_NOACK) { /* Do not penalize the ETX when collisions or transmission errors occur. */ return; } stats = nbr_table_get_from_lladdr(link_stats, lladdr); if(stats == NULL) { /* Add the neighbor */ stats = nbr_table_add_lladdr(link_stats, lladdr, NBR_TABLE_REASON_LINK_STATS, NULL); if(stats != NULL) { stats->etx = LINK_STATS_INIT_ETX(stats); } else { return; /* No space left, return */ } } /* Update last timestamp and freshness */ stats->last_tx_time = clock_time(); stats->freshness = MIN(stats->freshness + numtx, FRESHNESS_MAX); /* ETX used for this update */ packet_etx = ((status == MAC_TX_NOACK) ? ETX_NOACK_PENALTY : numtx) * ETX_DIVISOR; /* ETX alpha used for this update */ ewma_alpha = link_stats_is_fresh(stats) ? EWMA_ALPHA : EWMA_BOOTSTRAP_ALPHA; /* Compute EWMA and update ETX */ stats->etx = ((uint32_t)stats->etx * (EWMA_SCALE - ewma_alpha) + (uint32_t)packet_etx * ewma_alpha) / EWMA_SCALE; }
/*---------------------------------------------------------------------------*/ uip_ds6_route_t * uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, uip_ipaddr_t *nexthop) { uip_ds6_route_t *r; struct uip_ds6_route_neighbor_route *nbrr; #if DEBUG != DEBUG_NONE assert_nbr_routes_list_sane(); #endif /* DEBUG != DEBUG_NONE */ /* Get link-layer address of next hop, make sure it is in neighbor table */ const uip_lladdr_t *nexthop_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(nexthop); if(nexthop_lladdr == NULL) { PRINTF("uip_ds6_route_add: neighbor link-local address unknown for "); PRINT6ADDR(nexthop); PRINTF("\n"); return NULL; } /* First make sure that we don't add a route twice. If we find an existing route for our destination, we'll delete the old one first. */ r = uip_ds6_route_lookup(ipaddr); if(r != NULL) { PRINTF("uip_ds6_route_add: old route for "); PRINT6ADDR(ipaddr); PRINTF(" found, deleting it\n"); uip_ds6_route_rm(r); } { struct uip_ds6_route_neighbor_routes *routes; /* If there is no routing entry, create one. We first need to check if we have room for this route. If not, we remove the least recently used one we have. */ if(uip_ds6_route_num_routes() == UIP_DS6_ROUTE_NB) { /* Removing the oldest route entry from the route table. The least recently used route is the first route on the list. */ uip_ds6_route_t *oldest; oldest = list_tail(routelist); /* uip_ds6_route_head(); */ PRINTF("uip_ds6_route_add: dropping route to "); PRINT6ADDR(&oldest->ipaddr); PRINTF("\n"); uip_ds6_route_rm(oldest); } /* Every neighbor on our neighbor table holds a struct uip_ds6_route_neighbor_routes which holds a list of routes that go through the neighbor. We add our route entry to this list. We first check to see if we already have this neighbor in our nbr_route table. If so, the neighbor already has a route entry list. */ routes = nbr_table_get_from_lladdr(nbr_routes, (linkaddr_t *)nexthop_lladdr); if(routes == NULL) { /* If the neighbor did not have an entry in our neighbor table, we create one. The nbr_table_add_lladdr() function returns a pointer to a pointer that we may use for our own purposes. We initialize this pointer with the list of routing entries that are attached to this neighbor. */ routes = nbr_table_add_lladdr(nbr_routes, (linkaddr_t *)nexthop_lladdr); if(routes == NULL) { /* This should not happen, as we explicitly deallocated one route table entry above. */ PRINTF("uip_ds6_route_add: could not allocate neighbor table entry\n"); return NULL; } LIST_STRUCT_INIT(routes, route_list); } /* Allocate a routing entry and populate it. */ r = memb_alloc(&routememb); if(r == NULL) { /* This should not happen, as we explicitly deallocated one route table entry above. */ PRINTF("uip_ds6_route_add: could not allocate route\n"); return NULL; } /* add new routes first - assuming that there is a reason to add this and that there is a packet coming soon. */ list_push(routelist, r); nbrr = memb_alloc(&neighborroutememb); if(nbrr == NULL) { /* This should not happen, as we explicitly deallocated one route table entry above. */ PRINTF("uip_ds6_route_add: could not allocate neighbor route list entry\n"); memb_free(&routememb, r); return NULL; } nbrr->route = r; /* Add the route to this neighbor */ list_add(routes->route_list, nbrr); r->neighbor_routes = routes; num_routes++; PRINTF("uip_ds6_route_add num %d\n", num_routes); } uip_ipaddr_copy(&(r->ipaddr), ipaddr); r->length = length; #ifdef UIP_DS6_ROUTE_STATE_TYPE memset(&r->state, 0, sizeof(UIP_DS6_ROUTE_STATE_TYPE)); #endif PRINTF("uip_ds6_route_add: adding route: "); PRINT6ADDR(ipaddr); PRINTF(" via "); PRINT6ADDR(nexthop); PRINTF("\n"); ANNOTATE("#L %u 1;blue\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]); #if UIP_DS6_NOTIFICATIONS call_route_callback(UIP_DS6_NOTIFICATION_ROUTE_ADD, ipaddr, nexthop); #endif #if DEBUG != DEBUG_NONE assert_nbr_routes_list_sane(); #endif /* DEBUG != DEBUG_NONE */ return r; }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(rpl_forwarder_set_update_process, ev, instance) { static rpl_rank_t best_rank; static rpl_rank_t best_forwarder_rank; static rpl_rank_t curr_rank; static rpl_forwarder_set_member_t *curr_forwarder; static rpl_forwarder_set_member_t *next_forwarder; static rpl_forwarder_set_member_t *best_forwarder; static rpl_forwarder_set_member_t *last_forwarder; static nbr_table_item_t *nbr_table_parent; static uint8_t *membership_status; PROCESS_BEGIN(); while(1) { PROCESS_WAIT_EVENT(); if(ev == PROCESS_EVENT_CONTINUE) { nbr_table_parent = nbr_table_head(rpl_parents); best_rank = 0xFFFF; if(nbr_table_parent != NULL) { list_init(forwarder_set_list); list_init(current_set_list); /* Build a list of potential forwarders */ int is_potential_forwarder; PRINTF("RPL: Potential forwarders: "); do { is_potential_forwarder = 0; curr_forwarder = memb_alloc(&forwarder_set_memb); if(curr_forwarder == NULL) { PRINTF("RPL: unable to allocate forwarder set member\n"); return 0; } curr_forwarder->forwarder = (rpl_parent_t *)nbr_table_parent; if(((rpl_instance_t *)instance)->of->parent_path_cost(curr_forwarder->forwarder) < 0xFFFF) { list_add(forwarder_set_list, curr_forwarder); PRINTF("%u ", rpl_get_parent_lladdr(curr_forwarder->forwarder)->u8[7]); is_potential_forwarder = 1; } membership_status = (uint8_t *)nbr_table_add_lladdr(forwarder_set, rpl_get_parent_lladdr(curr_forwarder->forwarder), NBR_TABLE_REASON_UNDEFINED, NULL); if(membership_status == NULL) { PRINTF("RPL: error setting membership status in forwarder set\n"); return 0; } else { *membership_status = 0; } if(!is_potential_forwarder) { memb_free(&forwarder_set_memb, curr_forwarder); } nbr_table_parent = nbr_table_next(rpl_parents, nbr_table_parent); } while(nbr_table_parent != NULL); PRINTF("\n"); last_forwarder = NULL; /* Try all incremental combinations in ascending order according to rank */ while(list_head(forwarder_set_list) != NULL) { next_forwarder = list_head(forwarder_set_list); best_forwarder = next_forwarder; best_forwarder_rank = ((rpl_instance_t *)instance)->of->parent_path_cost(best_forwarder->forwarder); /* Instead of sorting, we'll go through and find the best forwarder each time */ do { curr_forwarder = next_forwarder; curr_rank = ((rpl_instance_t *)instance)->of->parent_path_cost(curr_forwarder->forwarder); if(curr_rank < best_forwarder_rank) { best_forwarder = curr_forwarder; best_forwarder_rank = curr_rank; } next_forwarder = list_item_next(curr_forwarder); } while(next_forwarder != NULL); /* Add the best forwarder to the current list and remove it from the candidate list */ //PRINTF("RPL: adding %u with rank %u\n", rpl_get_parent_lladdr(best_forwarder->forwarder)->u8[7], best_forwarder_rank); list_remove(forwarder_set_list, best_forwarder); list_add(current_set_list, best_forwarder); /* Find the routing metric with the current list and compare to the best so far */ curr_rank = ((rpl_instance_t *)instance)->of->rank_via_set(list_head(current_set_list)); //PRINTF("RPL: resulting rank %u, current best rank %u\n", curr_rank, best_rank); if(curr_rank <= best_rank) { best_rank = curr_rank; last_forwarder = list_tail(current_set_list); } } /* Trim the list back to the best combination. */ if(last_forwarder != NULL) { while(list_head(current_set_list) != NULL) { curr_forwarder = list_chop(current_set_list); if(curr_forwarder == last_forwarder) { list_add(current_set_list, last_forwarder); break; } memb_free(&forwarder_set_memb, curr_forwarder); } if(list_head(current_set_list) == NULL) { PRINTF("RPL: error trimming forwarder set list\n"); } PRINTF("RPL: best rank %u\n", best_rank); #if DEBUG PRINTF("RPL: best set "); next_forwarder = list_head(current_set_list); do { curr_forwarder = next_forwarder; PRINTF("%u ", rpl_get_parent_lladdr(curr_forwarder->forwarder)->u8[7]); next_forwarder = list_item_next(curr_forwarder); } while(next_forwarder != NULL); PRINTF("\n"); #endif /* Now we have the best combination - store it in a neighbor table */ while(list_head(current_set_list) != NULL) { curr_forwarder = list_pop(current_set_list); membership_status = nbr_table_get_from_lladdr(forwarder_set, rpl_get_parent_lladdr(curr_forwarder->forwarder)); *membership_status = 1; memb_free(&forwarder_set_memb, curr_forwarder); } } else { PRINTF("RPL: empty forwarder set\n"); } } PRINTF("RPL: updating opp routing rank from %d to %d\n", current_rank, best_rank); if(best_rank != 0xFFFF) { current_rank = best_rank; } else { current_rank = INFINITE_RANK; } } } PROCESS_END(); }
/*---------------------------------------------------------------------------*/ static void eb_input(struct input_packet *current_input) { /* PRINTF("TSCH: EB received\n"); */ frame802154_t frame; /* Verify incoming EB (does its ASN match our Rx time?), * and update our join priority. */ struct ieee802154_ies eb_ies; if(tsch_packet_parse_eb(current_input->payload, current_input->len, &frame, &eb_ies, NULL, 1)) { /* PAN ID check and authentication done at rx time */ #if TSCH_AUTOSELECT_TIME_SOURCE if(!tsch_is_coordinator) { /* Maintain EB received counter for every neighbor */ struct eb_stat *stat = (struct eb_stat *)nbr_table_get_from_lladdr(eb_stats, &frame.src_addr); if(stat == NULL) { stat = (struct eb_stat *)nbr_table_add_lladdr(eb_stats, &frame.src_addr); } if(stat != NULL) { stat->rx_count++; stat->jp = eb_ies.join_priority; best_neighbor_eb_count = MAX(best_neighbor_eb_count, stat->rx_count); } /* Select best time source */ struct eb_stat *best_stat = NULL; stat = nbr_table_head(eb_stats); while(stat != NULL) { /* Is neighbor eligible as a time source? */ if(stat->rx_count > best_neighbor_eb_count / 2) { if(best_stat == NULL || stat->jp < best_stat->jp) { best_stat = stat; } } stat = nbr_table_next(eb_stats, stat); } /* Update time source */ if(best_stat != NULL) { tsch_queue_update_time_source(nbr_table_get_lladdr(eb_stats, best_stat)); tsch_join_priority = best_stat->jp + 1; } } #endif struct tsch_neighbor *n = tsch_queue_get_time_source(); /* Did the EB come from our time source? */ if(n != NULL && linkaddr_cmp((linkaddr_t *)&frame.src_addr, &n->addr)) { /* Check for ASN drift */ int32_t asn_diff = ASN_DIFF(current_input->rx_asn, eb_ies.ie_asn); if(asn_diff != 0) { /* We disagree with our time source's ASN -- leave the network */ PRINTF("TSCH:! ASN drifted by %ld, leaving the network\n", asn_diff); tsch_disassociate(); } if(eb_ies.ie_join_priority >= TSCH_MAX_JOIN_PRIORITY) { /* Join priority unacceptable. Leave network. */ PRINTF("TSCH:! EB JP too high %u, leaving the network\n", eb_ies.ie_join_priority); tsch_disassociate(); } else { #if TSCH_AUTOSELECT_TIME_SOURCE /* Update join priority */ if(tsch_join_priority != eb_ies.ie_join_priority + 1) { PRINTF("TSCH: update JP from EB %u -> %u\n", tsch_join_priority, eb_ies.ie_join_priority + 1); tsch_join_priority = eb_ies.ie_join_priority + 1; } #endif /* TSCH_AUTOSELECT_TIME_SOURCE */ } } } }
/*---------------------------------------------------------------------------*/ uip_ds6_route_t * uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length, uip_ipaddr_t *nexthop) { uip_ds6_route_t *r; #if DEBUG != DEBUG_NONE assert_nbr_routes_list_sane(); #endif /* DEBUG != DEBUG_NONE */ /* Get link-layer address of next hop, make sure it is in neighbor table */ const uip_lladdr_t *nexthop_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(nexthop); if(nexthop_lladdr == NULL) { PRINTF("uip_ds6_route_add: neighbor link-local address unknown "); PRINT6ADDR(ipaddr); PRINTF("\n"); return NULL; } /* First make sure that we don't add a route twice. If we find an existing route for our destination, we'll just update the old one. */ r = uip_ds6_route_lookup(ipaddr); if(r != NULL) { PRINTF("uip_ds6_route_add: old route already found, updating this one instead: "); PRINT6ADDR(ipaddr); PRINTF("\n"); } else { struct uip_ds6_route_neighbor_routes *routes; /* If there is no routing entry, create one */ /* Every neighbor on our neighbor table holds a struct uip_ds6_route_neighbor_routes which holds a list of routes that go through the neighbor. We add our route entry to this list. We first check to see if we already have this neighbor in our nbr_route table. If so, the neighbor already has a route entry list. */ routes = nbr_table_get_from_lladdr(nbr_routes, (rimeaddr_t *)nexthop_lladdr); if(routes == NULL) { /* If the neighbor did not have an entry in our neighbor table, we create one. The nbr_table_add_lladdr() function returns a pointer to a pointer that we may use for our own purposes. We initialize this pointer with the list of routing entries that are attached to this neighbor. */ routes = nbr_table_add_lladdr(nbr_routes, (rimeaddr_t *)nexthop_lladdr); if(routes == NULL) { PRINTF("uip_ds6_route_add: could not allocate a neighbor table entri for new route to "); PRINT6ADDR(ipaddr); PRINTF(", dropping it\n"); return NULL; } LIST_STRUCT_INIT(routes, route_list); } /* Allocate a routing entry and populate it. */ r = memb_alloc(&routememb); if(r == NULL) { PRINTF("uip_ds6_route_add: could not allocate memory for new route to "); PRINT6ADDR(ipaddr); PRINTF(", dropping it\n"); return NULL; } /* Add the route to this neighbor */ list_add(routes->route_list, r); num_routes++; PRINTF("uip_ds6_route_add num %d\n", num_routes); r->routes = routes; } uip_ipaddr_copy(&(r->ipaddr), ipaddr); r->length = length; #ifdef UIP_DS6_ROUTE_STATE_TYPE memset(&r->state, 0, sizeof(UIP_DS6_ROUTE_STATE_TYPE)); #endif PRINTF("uip_ds6_route_add: adding route: "); PRINT6ADDR(ipaddr); PRINTF(" via "); PRINT6ADDR(nexthop); PRINTF("\n"); ANNOTATE("#L %u 1;blue\n", nexthop->u8[sizeof(uip_ipaddr_t) - 1]); #if UIP_DS6_NOTIFICATIONS call_route_callback(UIP_DS6_NOTIFICATION_ROUTE_ADD, ipaddr, nexthop); #endif #if DEBUG != DEBUG_NONE assert_nbr_routes_list_sane(); #endif /* DEBUG != DEBUG_NONE */ return r; }
/*---------------------------------------------------------------------------*/ static int parse(void) { int result; const linkaddr_t *sender; struct anti_replay_info* info; result = DECORATED_FRAMER.parse(); if(result == FRAMER_FAILED) { return result; } if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) != SEC_LVL) { PRINTF("noncoresec: received frame with wrong security level\n"); return FRAMER_FAILED; } sender = packetbuf_addr(PACKETBUF_ADDR_SENDER); if(linkaddr_cmp(sender, &linkaddr_node_addr)) { PRINTF("noncoresec: frame from ourselves\n"); return FRAMER_FAILED; } packetbuf_set_datalen(packetbuf_datalen() - MIC_LEN); if(!aead(result, 0)) { PRINTF("noncoresec: received unauthentic frame %lu\n", anti_replay_get_counter()); return FRAMER_FAILED; } info = nbr_table_get_from_lladdr(anti_replay_table, sender); if(!info) { info = nbr_table_add_lladdr(anti_replay_table, sender, NBR_TABLE_REASON_LLSEC, NULL); if(!info) { PRINTF("noncoresec: could not get nbr_table_item\n"); return FRAMER_FAILED; } /* * Locking avoids replay attacks due to removed neighbor table items. * Unfortunately, an attacker can mount a memory-based DoS attack * on this by replaying broadcast frames from other network parts. * However, this is not an issue as long as the network size does not * exceed NBR_TABLE_MAX_NEIGHBORS. * * To avoid locking, we could swap anti-replay information * to external flash. Locking is also unnecessary when using * pairwise session keys, as done in coresec. */ if(!nbr_table_lock(anti_replay_table, info)) { nbr_table_remove(anti_replay_table, info); PRINTF("noncoresec: could not lock\n"); return FRAMER_FAILED; } anti_replay_init_info(info); } else { if(anti_replay_was_replayed(info)) { PRINTF("noncoresec: received replayed frame %lu\n", anti_replay_get_counter()); return FRAMER_FAILED; } } return result; }