Ejemplo n.º 1
0
static struct discovery_ipnd_neighbour_list_entry* discovery_ipnd_find_neighbour(const uint32_t eid)
{
	if( discovery_status == 0 ) {
		// Not initialized yet
		return NULL;
	}

	const linkaddr_t addr = convert_eid_to_rime(eid);

	for(struct discovery_ipnd_neighbour_list_entry* entry = list_head(neighbour_list);
			entry != NULL;
			entry = list_item_next(entry)) {
		if( linkaddr_cmp(&entry->neighbour, &addr) ) {
			return entry;
		}
	}

	return NULL;
}
Ejemplo n.º 2
0
/**
 * \brief Forward a bundle to its destination
 * \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_directly(struct routing_entry_t * entry)
{
	struct discovery_neighbour_list_entry *nei_l = NULL;
	linkaddr_t dest_node;
	int h = 0;

	/* Who is the destination for this bundle? */
	dest_node = convert_eid_to_rime(entry->destination_node);

	/* First step: check, if the destination is one of our neighbours */
	for( nei_l = DISCOVERY.neighbours();
		 nei_l != NULL;
		 nei_l = list_item_next(nei_l) ) {

		if( linkaddr_cmp(&nei_l->neighbour, &dest_node) ) {
			break;
		}
	}

	if( nei_l == NULL ) {
		return CHAIN_ROUTE_RETURN_CONTINUE;
	}

	/* We know the neighbour, send it directly */
	LOG(LOGD_DTN, LOG_ROUTE, LOGL_INF, "send bundle %lu to %u.%u directly", 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;
	}

	/* We do not want the bundle to be sent to anybody else at the moment, so: */
	return CHAIN_ROUTE_RETURN_OK;
}
Ejemplo n.º 3
0
/**
 * \brief Callback function informing us about the status of a sent bundle
 * \param ticket CL transmit ticket of the bundle
 * \param status status code
 */
void routing_chain_bundle_sent(struct transmit_ticket_t * ticket, uint8_t status)
{
	struct routing_list_entry_t * n = NULL;
	struct routing_entry_t * entry = NULL;

	// Tell the agent to call us again to resubmit bundles
	routing_chain_schedule_resubmission();

	// Find the bundle in our internal storage
	for( n = list_head(routing_list);
		 n != NULL;
		 n = list_item_next(n) ) {

		entry = (struct routing_entry_t *) MMEM_PTR(&n->entry);

		if( entry->bundle_number == ticket->bundle_number ) {
			break;
		}
	}

	if( n == NULL ) {
		/* Free up the ticket */
		convergence_layer_free_transmit_ticket(ticket);

		LOG(LOGD_DTN, LOG_ROUTE, LOGL_ERR, "Bundle not in storage");
		return;
	}

	/* Bundle is not busy anymore */
	entry->flags &= ~ROUTING_FLAG_IN_TRANSIT;

	if( status == ROUTING_STATUS_NACK ||
		status == ROUTING_STATUS_FAIL ) {
		// NACK = Other side rejected the bundle, try again later
		// FAIL = Transmission failed

		/* Free up the ticket */
		convergence_layer_free_transmit_ticket(ticket);

		return;
	}

	if( status == ROUTING_STATUS_ERROR ) {
		LOG(LOGD_DTN, LOG_ROUTE, LOGL_ERR, "Bundle %lu has fatal error, deleting", ticket->bundle_number);

		/* Bundle failed permanently, we can delete it because it will never be delivered anyway */
		entry->flags = 0;

		routing_chain_check_keep_bundle(ticket->bundle_number);

		/* Free up the ticket */
		convergence_layer_free_transmit_ticket(ticket);

		return;
	}

	// Here: status == ROUTING_STATUS_OK
	statistics_bundle_outgoing(1);

#ifndef TEST_DO_NOT_DELETE_ON_DIRECT_DELIVERY
	linkaddr_t dest_n = convert_eid_to_rime(entry->destination_node);
	if (linkaddr_cmp(&ticket->neighbour, &dest_n)) {
		LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "bundle sent to destination node");
		uint32_t bundle_number = ticket->bundle_number;

		/* Free up the ticket */
		convergence_layer_free_transmit_ticket(ticket);
		ticket = NULL;

		// Unset the forward flag
		entry->flags &= ~ROUTING_FLAG_FORWARD;
		routing_chain_check_keep_bundle(bundle_number);

		return;
	}

	LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "bundle for %u.%u delivered to %u.%u", dest_n.u8[0], dest_n.u8[1], ticket->neighbour.u8[0], ticket->neighbour.u8[1]);
#endif


	if (entry->send_to < ROUTING_NEI_MEM) {
		linkaddr_copy(&entry->neighbours[entry->send_to], &ticket->neighbour);
		entry->send_to++;
		LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "bundle %lu sent to %u nodes", ticket->bundle_number, entry->send_to);
	} else if (entry->send_to >= ROUTING_NEI_MEM) {
		// Here we can delete the bundle from storage, because it will not be routed anyway
		LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "bundle %lu sent to max number of nodes, deleting", ticket->bundle_number);

		// Unset the forward flag
		entry->flags &= ~ROUTING_FLAG_FORWARD;
		routing_chain_check_keep_bundle(ticket->bundle_number);
	}

	/* Free up the ticket */
	convergence_layer_free_transmit_ticket(ticket);
}
Ejemplo n.º 4
0
/**
 * \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;
}
Ejemplo n.º 5
0
/**
 * \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;
			}

		}
	}
}