/** * \brief Forward a bundle to the next hop * \param entry Pointer to the routing entry of the bundle * \return FLOOD_ROUTE_RETURN_OK if queued, FLOOD_ROUTE_RETURN_CONTINUE if not queued and FLOOD_ROUTE_RETURN_FAIL of queue is full */ int routing_chain_forward_normal(struct routing_entry_t * entry) { struct discovery_neighbour_list_entry *nei_l = NULL; linkaddr_t source_node; int h = 0; /* What is the source node of the bundle? */ source_node = convert_eid_to_rime(entry->source_node); for( nei_l = DISCOVERY.neighbours(); nei_l != NULL; nei_l = list_item_next(nei_l) ) { int sent = 0; int i; if( linkaddr_cmp(&nei_l->neighbour, &source_node) ) { LOG(LOGD_DTN, LOG_ROUTE, LOGL_INF, "not sending bundle to originator"); /* Go on with the next neighbour */ continue; } if( linkaddr_cmp(&nei_l->neighbour, &entry->received_from_node) ) { LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "not sending back to sender"); /* Go on with the next neighbour */ continue; } /* Did we forward the bundle to that neighbour already? */ for (i = 0 ; i < ROUTING_NEI_MEM ; i++) { if ( linkaddr_cmp(&entry->neighbours[i], &nei_l->neighbour)){ LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "bundle %lu already sent to node %u.%u!", entry->bundle_number, entry->neighbours[i].u8[0], entry->neighbours[i].u8[1]); sent = 1; // Break the (narrowest) for break; } } uint32_t neighbour_eid = convert_rime_to_eid(&nei_l->neighbour); if( entry->destination_node > entry->source_node ) { // Going "up" the chain if( neighbour_eid <= dtn_node_id ) { LOG(LOGD_DTN, LOG_ROUTE, LOGL_INF, "Not sending bundle %lu to %u.%u, because %lu <= %lu", entry->bundle_number, nei_l->neighbour.u8[0], nei_l->neighbour.u8[1], neighbour_eid, dtn_node_id); sent = 1; } else { LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "Sending bundle %lu to %u.%u, because %lu > %lu", entry->bundle_number, nei_l->neighbour.u8[0], nei_l->neighbour.u8[1], neighbour_eid, dtn_node_id); } } else if( entry->destination_node < entry->source_node ) { // Going "down" the chain if( neighbour_eid >= dtn_node_id ) { LOG(LOGD_DTN, LOG_ROUTE, LOGL_INF, "Not sending bundle %lu to %u.%u, because %lu >= %lu", entry->bundle_number, nei_l->neighbour.u8[0], nei_l->neighbour.u8[1], neighbour_eid, dtn_node_id); sent = 1; } else { LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "Sending bundle %lu to %u.%u, because %lu < %lu", entry->bundle_number, nei_l->neighbour.u8[0], nei_l->neighbour.u8[1], neighbour_eid, dtn_node_id); } } else { LOG(LOGD_DTN, LOG_ROUTE, LOGL_ERR, "Source and destination nodes are the same?"); sent = 1; } if(!sent) { LOG(LOGD_DTN, LOG_ROUTE, LOGL_INF, "send bundle %lu to %u.%u", entry->bundle_number, nei_l->neighbour.u8[0], nei_l->neighbour.u8[1]); /* Mark bundle as busy */ entry->flags |= ROUTING_FLAG_IN_TRANSIT; /* And queue it for sending */ h = routing_chain_send_bundle(entry->bundle_number, &nei_l->neighbour); if( h < 0 ) { /* Enqueuing bundle failed - unblock it */ entry->flags &= ~ROUTING_FLAG_IN_TRANSIT; /* If sending the bundle fails, all other will likely also fail */ return CHAIN_ROUTE_RETURN_FAIL; } /* Only one bundle at a time */ return CHAIN_ROUTE_RETURN_OK; } } return CHAIN_ROUTE_RETURN_CONTINUE; }
/** * \brief Save neighbour to local cache * \param neighbour Address of the neighbour */ static int discovery_ipnd_save_neighbour(const uint32_t eid, const cl_addr_t* const addr) { if( discovery_status == 0 ) { // Not initialized yet return -1; } // If we know that neighbour already, no need to re-add it if(discovery_ipnd_refresh_neighbour(addr) >= 1) { return 0; } /* add informations to an existing LOWPAN entry, * if the eid matches */ if (addr->isIP) { struct discovery_ipnd_neighbour_list_entry* const entry = discovery_ipnd_find_neighbour(eid); if (entry != NULL) { /* entry matching the EID already existing * add the missing parameters */ discovery_ipnd_neighbour_update_ip(addr, entry); return 1; } } struct discovery_ipnd_neighbour_list_entry* const entry = memb_alloc(&neighbour_mem); if( entry == NULL ) { LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_WRN, "no more space for neighbours"); return -2; } LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_INF, "Found new neighbour ipn:%lu", eid); // Clean the entry struct memset(entry, 0, sizeof(struct discovery_ipnd_neighbour_list_entry)); entry->neighbour = convert_eid_to_rime(eid); if (addr->isIP) { discovery_ipnd_neighbour_update_ip(addr, entry); } else { entry->addr_type = CL_TYPE_FLAG_DGRAM_LOWPAN; ip_addr_copy(entry->ip, *IP_ADDR_ANY); entry->port = 0; entry->timestamp_last_lowpan = clock_seconds(); /* rime and eid should be the same * otherwise the wrong destination will be used * in further processing */ // TODO remove const cast if (convert_rime_to_eid((linkaddr_t*)&addr->lowpan) != eid) { LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_ERR, "The EID %u and the PAN addresse %u.%u are different. This is not supported.", eid, addr->lowpan.u8[0], addr->lowpan.u8[1]); } } entry->timestamp_discovered = clock_seconds(); // Notify the statistics module statistics_contacts_up(eid); list_add(neighbour_list, entry); // We have found a new neighbour, now go and notify the agent const event_container_t event = { .event = dtn_beacon_event, .linkaddr = &entry->neighbour }; agent_send_event(&event); return 2; } /** * \brief Returns the list of currently known neighbours * \return Pointer to list with neighbours */ struct discovery_neighbour_list_entry * discovery_ipnd_list_neighbours() { return list_head(neighbour_list); } /** * \brief Stops pending discoveries */ void discovery_ipnd_stop_pending() { } static void discovery_ipnd_start(clock_time_t duration, uint8_t index) { // Send at the beginning of a cycle discovery_ipnd_send(); } static void discovery_ipnd_stop() { // Send at the end of a cycle discovery_ipnd_send(); } void discovery_ipnd_clear() { struct discovery_ipnd_neighbour_list_entry * entry; LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_INF, "Clearing neighbour list"); while(list_head(neighbour_list) != NULL) { entry = list_head(neighbour_list); // Notify the statistics module statistics_contacts_down(&entry->neighbour, entry->timestamp_last_lowpan - entry->timestamp_discovered); // TODO statistics_contacts_down(&entry->neighbour, entry->timestamp_last_ip - entry->timestamp_discovered); /* call convergence_layer_neighbour_down for all discovered address types */ cl_addr_t addr; if (discovery_neighbour_to_addr((struct discovery_neighbour_list_entry*)entry, CL_TYPE_FLAG_DGRAM_LOWPAN, &addr) >= 0) { convergence_layer_dgram_neighbour_down(&addr); } if (discovery_neighbour_to_addr((struct discovery_neighbour_list_entry*)entry, CL_TYPE_FLAG_DGRAM_UDP, &addr) >= 0) { convergence_layer_dgram_neighbour_down(&addr); } list_remove(neighbour_list, entry); memb_free(&neighbour_mem, entry); } } static int discovery_ipnd_check_neighbour_timeout(struct discovery_ipnd_neighbour_list_entry* const entry, const unsigned long timestamp_last, const uint8_t addr_type) { const unsigned long diff = clock_seconds() - timestamp_last; if (diff > DISCOVERY_NEIGHBOUR_TIMEOUT) { LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_WRN, "Neighbour ipn:%u timed out: %lu vs. %lu = %lu", convert_rime_to_eid(&entry->neighbour), clock_seconds(), timestamp_last, diff); cl_addr_t addr; if (discovery_neighbour_to_addr((struct discovery_neighbour_list_entry*)entry, addr_type, &addr) < 0) { // TODO possibly remove the entry LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_ERR, "Could not convert address of discovery entry"); return -1; } else { discovery_ipnd_delete_neighbour(&addr); return 1; } } return 0; } static void discovery_ipnd_remove_stale_neighbours(const TimerHandle_t timer) { bool changed = true; while (changed) { changed = false; for(struct discovery_ipnd_neighbour_list_entry* entry = list_head(neighbour_list); entry != NULL; entry = list_item_next(entry)) { const bool lowpan_exists = (entry->addr_type & CL_TYPE_FLAG_DGRAM_LOWPAN); const bool ip_exists = (entry->addr_type & CL_TYPE_FLAG_DGRAM_UDP); if (!lowpan_exists && !ip_exists) { LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_ERR, "Entry without an vaild address. Deleting"); discovery_ipnd_destroy_neighbour(entry); changed = true; break; } if (lowpan_exists && discovery_ipnd_check_neighbour_timeout(entry, entry->timestamp_last_lowpan, CL_TYPE_FLAG_DGRAM_LOWPAN) > 0) { changed = true; /* not break here, * because possibly the next address type is * timed out too. * So the full entry has to be deleted */ } if (ip_exists && discovery_ipnd_check_neighbour_timeout(entry, entry->timestamp_last_ip, CL_TYPE_FLAG_DGRAM_UDP) > 0) { changed = true; /* not break here, * because possibly the next address type is * timed out too. * So the full entry has to be deleted */ } /* list has changed * so reload list entries */ if (changed) { break; } } } }