/**
 * @file graphs_local.c
 *
 * @brief Network graphs - functions local to each node.
 *
 * Copyright 2007-2008, Freie Universitaet Berlin. All rights reserved.
 * Please refer to the COPYING file for detailed licensing information.
 *
 * @author Georg Wittenburg
 *
 * $Id: graphs_local.c 2685 2008-06-25 16:38:56Z wittenbu $
 */

#include <stdlib.h>
#include <string.h>

#include "../types.h"
#include "../vars.h"
#include "../interface.h"
#include "../interface_internal.h"
#include "../util/debug.h"
#include "../util/list.h"
#include "../util/callback.h"
#include "../util/net.h"
#include "../icmp-light/icmp-light.h"
#include "../rudp-light/rudp-light.h"
#include "graphs.h"
#include "graphs_types.h"
#include "graphs_vars.h"
#include "graphs_local.h"

/**
 * @brief Send a GRAPHS REPLY packet.
 *
 * @param to Address of the destination node.
 * @param data_nodes List of nodes with data on network conditions.
 */
static void send_GRAPHS_REPLY(C_addr_t to, list_t* data_nodes) {
	GRAPHS_local_data_node_t* node_array = NULL;

	C_DEBUG(C_DEBUG_LEVEL_DEBUG, "GRAPHS: Sending GRAPHS REPLY to node %s...\n", addr_to_str(to));
	MALLOC_ARRAY(node_array, GRAPHS_local_data_node_t, list_size(data_nodes));
	list_to_array(data_nodes, node_array, sizeof(GRAPHS_local_data_node_t));
	RUDP_sendto(to, APP_TYPE_GRAPHS, GRAPHS_PACKET_TYPE_REPLY, node_array, (list_size(data_nodes) * sizeof(GRAPHS_local_data_node_t)), NULL, NULL);
	FREE(node_array);
}

/**
 * @brief Send a GRAPHS RESET packet.
 *
 * @param to Address of the destination node.
 * @param newly_discovered_nodes List of newly discovered nodes.
 */
static void send_GRAPHS_RESET(C_addr_t to, list_t* newly_discovered_nodes) {
	node_t* node_array = NULL;

	C_DEBUG(C_DEBUG_LEVEL_DEBUG, "GRAPHS: Sending GRAPHS RESET to node %s...\n", addr_to_str(to));
	MALLOC_ARRAY(node_array, node_t, list_size(newly_discovered_nodes));
	list_to_array(newly_discovered_nodes, node_array, sizeof(node_t));
	RUDP_sendto(to, APP_TYPE_GRAPHS, GRAPHS_PACKET_TYPE_RESET, node_array, (list_size(newly_discovered_nodes) * sizeof(node_t)), NULL, NULL);
	FREE(node_array);
}

/**
 * @brief RUDP callback for a GRAPHS REST REQUEST packet.
 *
 * @param parameter Pointer to RUDP transmission result.
 */
static void send_GRAPHS_TEST_REQUEST_callback(callback_parameter_t parameter) {
	RUDP_transmission_result_t* result = (RUDP_transmission_result_t*) parameter;
	GRAPHS_local_data_t* local_data = (GRAPHS_local_data_t*) result->parameter;

	if(result->error_code == C_ERROR_OK) {
		C_DEBUG(C_DEBUG_LEVEL_DEBUG, "GRAPHS: GRAPHS TEST REQUEST to node %s was successful.\n", addr_to_str(result->to));
	} else {
		C_DEBUG(C_DEBUG_LEVEL_WARN, "GRAPHS: GRAPHS TEST REQUEST to node %s failed (%d), invalidating current test...\n", addr_to_str(result->to), result->error_code);
		local_data->current_test_invalid = true;
	}
	FREE(result);
}

/**
 * @brief Send a GRAPHS TEST REQUEST packet.
 *
 * @param to Address of destination node.
 * @param test_id ID of test.
 * @param delay Delay before starting the test.
 * @param packets Number of test packets.
 * @param interval Time interval between test packets.
 * @param duration Duration of the test (used if <code>packets</code> is set to 0).
 * @param local_data Pointer to local test data.
 */
static void send_GRAPHS_TEST_REQUEST(C_addr_t to, uint16_t test_id, C_time_t delay, uint16_t packets, C_time_t interval, C_time_t duration, GRAPHS_local_data_t* local_data) {
	GRAPHS_TEST_REQUEST_packet_t test_request;
	RUDP_transmission_result_t* result = NULL;

	C_DEBUG(C_DEBUG_LEVEL_DEBUG, "GRAPHS: Sending GRAPHS TEST REQUEST to node %s...\n", addr_to_str(to));
	test_request.test_id = test_id;
	test_request.delay = delay;
	test_request.packets = packets;
	test_request.interval = interval;
	test_request.duration = duration;
	MALLOC(result, RUDP_transmission_result_t);
	result->parameter = local_data;
	RUDP_sendto(to, APP_TYPE_GRAPHS, GRAPHS_PACKET_TYPE_TEST_REQUEST, &test_request, sizeof(GRAPHS_TEST_REQUEST_packet_t), send_GRAPHS_TEST_REQUEST_callback, result);
}

/**
 * @brief Send a GRAPHS TEST DATA packet.
 *
 * @param test_id ID of test.
 * @param node_address Address of the node that requested the test.
 */
static void send_GRAPHS_TEST_DATA(uint16_t test_id, C_addr_t node_address) {
	GRAPHS_TEST_DATA_packet_t test_data;
	char* payload = NULL;

	C_DEBUG(C_DEBUG_LEVEL_VERBOSE, "GRAPHS: Broadcasting GRAPHS TEST DATA as requested by node %s...\n", addr_to_str(node_address));
	test_data.test_id = test_id;
	test_data.node_address = node_address;
	MALLOC_ARRAY(payload, char, (GRAPHS_INTERFERENCE_PAYLOAD_SIZE - sizeof(GRAPHS_TEST_DATA_packet_t)));
	C_sendto2(C_BROADCAST_ADDR, APP_TYPE_GRAPHS, GRAPHS_PACKET_TYPE_TEST_DATA, &test_data, sizeof(GRAPHS_TEST_DATA_packet_t), payload, (GRAPHS_INTERFERENCE_PAYLOAD_SIZE - sizeof(GRAPHS_TEST_DATA_packet_t)));
	FREE(payload);
}

static void collect_interference_data(GRAPHS_local_data_t* local_data);

/**
 * @brief Callback for gathering interference information.
 *
 * @param parameter Callback parameter.
 */
static void collect_interference_data_timeout(callback_parameter_t parameter) {
	GRAPHS_local_data_t* local_data = (GRAPHS_local_data_t*) parameter;

	if(local_data->last_interference_packet_source == local_data->reference_node_address) {
		C_DEBUG(C_DEBUG_LEVEL_WARN, "GRAPHS: Last interference packet was received from reference node %s instead of active node %s.\n", addr_to_str(C_GRAPHS_local_data->reference_node_address), addr_to_str(C_GRAPHS_local_data->active_data_node->node.address));
	}

	if(!local_data->current_test_invalid) {
		local_data->active_data_node->interference = (((float) local_data->active_data_node->interference_count) / ((float) local_data->reference_connectivity_count));
		C_DEBUG(C_DEBUG_LEVEL_INFO, "GRAPHS: Interference test with node %s complete (%.0f%%).\n", addr_to_str(local_data->active_data_node->node.address), (local_data->active_data_node->interference * 100));
	} else {
		C_DEBUG(C_DEBUG_LEVEL_WARN, "GRAPHS: Interference test with node %s complete, but invalid. Skipping node...\n", addr_to_str(local_data->active_data_node->node.address));
		local_data->active_data_node->interference = -0.01f;
		local_data->current_test_invalid = false;
	}
	local_data->active_test_id++;
	local_data->last_interference_packet_source = C_BROADCAST_ADDR;
	collect_interference_data(local_data);
}

/**
 * @brief Check whether a local data node has no interference information.
 *
 * @param item Local data node to check.
 * @param UNUSED Unused.
 * @return <code>true</code> if the data node has no interference information,
 * <code>false</code> otherwise.
 */
static bool local_data_node_without_interference(const void* item, const void* UNUSED) {
	GRAPHS_local_data_node_t* data_node = (GRAPHS_local_data_node_t*) item;
	return (data_node->interference == -1);
}

/**
 * @brief Gather interference information.
 *
 * @param local_data Data structure for keeping the locally collected data.
 */
static void collect_interference_data(GRAPHS_local_data_t* local_data) {
	GRAPHS_local_data_node_t* data_node = NULL;
	data_node = (GRAPHS_local_data_node_t*) list_find(local_data->data_nodes, NULL, local_data_node_without_interference);
	if(data_node != NULL) {
		local_data->active_data_node = data_node;
		if(local_data->active_data_node->node.address != local_data->max_connectivity_node_address) {
			// Use best connected node as reference.
			local_data->reference_node_address = local_data->max_connectivity_node_address;
			local_data->reference_connectivity_count = local_data->max_connectivity_count;
		} else if(local_data->max2_connectivity_node_address != C_BROADCAST_ADDR) {
			// Use second best connected node as reference.
			local_data->reference_node_address = local_data->max2_connectivity_node_address;
			local_data->reference_connectivity_count = local_data->max2_connectivity_count;
		} else {
			// We don't have a second best connected node.
			C_DEBUG(C_DEBUG_LEVEL_WARN, "GRAPHS: Skipping interference with node %s, because no reference node is avaible.\n", addr_to_str(data_node->node.address));
			local_data->active_data_node->interference = -0.01f;
			collect_interference_data(local_data);
			return;
		}
		C_DEBUG(C_DEBUG_LEVEL_INFO, "GRAPHS: Testing interference with node %s using node %s as reference...\n", addr_to_str(data_node->node.address), addr_to_str(local_data->reference_node_address));
		local_data->active_data_node->interference_count = local_data->reference_connectivity_count;
		send_GRAPHS_TEST_REQUEST(local_data->active_data_node->node.address, local_data->active_test_id, GRAPHS_INTERFERENCE_TEST_DELAY, 0, GRAPHS_INTERFERENCE_TEST_INTERVAL, GRAPHS_INTERFERENCE_TEST_DURATION, local_data);
		send_GRAPHS_TEST_REQUEST(local_data->reference_node_address, local_data->active_test_id, GRAPHS_INTERFERENCE_REFERENCE_DELAY, GRAPHS_INTERFERENCE_SAMPLES, GRAPHS_INTERFERENCE_REFERENCE_INTERVAL, 0, local_data);
		callback_add(collect_interference_data_timeout, local_data, (C_TIMEOUT + GRAPHS_INTERFERENCE_TEST_DURATION));
	} else {
		C_DEBUG(C_DEBUG_LEVEL_INFO, "GRAPHS: Interference tests on node %s complete, sending data to coordinator node...\n", addr_to_str(C_LOCAL_ADDR));
		send_GRAPHS_REPLY(local_data->coordinator_address, local_data->data_nodes);
		list_free(&local_data->data_nodes);
		list_free(&local_data->newly_discovered_nodes);
		FREE(local_data);
		C_GRAPHS_local_data = NULL;
	}
}

/**
 * @brief Check whether two local data nodes have the same address.
 *
 * @param item Data node to check.
 * @param cmp_item Reference data node.
 * @return <code>true</code> if the data nodes have the same address,
 * <code>false</code> otherwise.
 */
static bool cmp_local_data_node_addr(const void* item, const void* cmp_item) {
	GRAPHS_local_data_node_t* data_node = (GRAPHS_local_data_node_t*) item;
	GRAPHS_local_data_node_t* cmp_data_node = (GRAPHS_local_data_node_t*) cmp_item;
	return (data_node->node.address == cmp_data_node->node.address);
}

static void collect_connectivity_data(GRAPHS_local_data_t* local_data);

/**
 * @brief Callback for the echo request that gathers connectivity information.
 *
 * @param parameter The results of the echo request.
 */
static void collect_connectivity_data_callback(callback_parameter_t parameter) {
	ICMP_echo_request_result_t* echo_request_result = (ICMP_echo_request_result_t*) parameter;
	GRAPHS_local_data_t* local_data = (GRAPHS_local_data_t*) echo_request_result->parameter;

	switch(echo_request_result->error_code) {
	case C_ERROR_OK:
		while(!list_empty(echo_request_result->nodes)) {
			node_t* node = (node_t*) list_head(echo_request_result->nodes);
			GRAPHS_local_data_node_t* data_node = NULL;
			GRAPHS_local_data_node_t cmp_data_node;
			cmp_data_node.node.address = node->address;
			data_node = (GRAPHS_local_data_node_t*) list_find(local_data->data_nodes, &cmp_data_node, cmp_local_data_node_addr);
			if(data_node == NULL) {
				C_DEBUG(C_DEBUG_LEVEL_DEBUG, "GRAPHS: Received connectivity test packet from node %s, but it is not in the local data list...\n", addr_to_str(node->address));
				if(list_find(local_data->newly_discovered_nodes, node, matches_node_addr) == NULL) {
					list_add(local_data->newly_discovered_nodes, node);
					list_remove(echo_request_result->nodes, node);
				} else {
					list_remove(echo_request_result->nodes, node);
					FREE(node);
				}
			} else {
				C_DEBUG(C_DEBUG_LEVEL_DEBUG, "GRAPHS: Received connectivity test packet from node %s.\n", addr_to_str(data_node->node.address));
				data_node->connectivity_count++;
				list_remove(echo_request_result->nodes, node);
				FREE(node);
			}
		}
		break;
	case C_ERROR_TIMEOUT:
		C_DEBUG(C_DEBUG_LEVEL_DEBUG, "GRAPHS: Connectivity test packet from timed out.\n");
		break;
	default:
		C_DEBUG(C_DEBUG_LEVEL_FATAL, "GRAPHS: Callback with unknown error code 0x%X.\n", echo_request_result->error_code);
		abort();
	}
	list_free(&echo_request_result->nodes);
	FREE(echo_request_result);

	collect_connectivity_data(local_data);
}

/**
 * @brief Gather connectivity information.
 *
 * Send local ECHO broadcasts and count which nodes reply.
 *
 * @param local_data Data structure for keeping the locally collected data.
 */
static void collect_connectivity_data(GRAPHS_local_data_t* local_data) {
	if(local_data->connectivity_samples < GRAPHS_CONNECTIVITY_SAMPLES) {
		ICMP_echo_request_result_t* echo_request_result = NULL;
		local_data->connectivity_samples++;
		C_DEBUG(C_DEBUG_LEVEL_DEBUG, "GRAPHS: Sending connectivity test packet #%d...\n", local_data->connectivity_samples);
		MALLOC(echo_request_result, ICMP_echo_request_result_t);
		list_alloc(&echo_request_result->nodes);
		echo_request_result->parameter = local_data;
		ICMP_send_echo_request(C_BROADCAST_ADDR, 1, collect_connectivity_data_callback, echo_request_result);
	} else {
		unsigned int i;

		if(!list_empty(local_data->newly_discovered_nodes)) {
			C_DEBUG(C_DEBUG_LEVEL_WARN, "GRAPHS: Connectivity tests at node %s complete, %d new node(s) have been discovered: ", addr_to_str(C_LOCAL_ADDR), list_size(local_data->newly_discovered_nodes));
			list_print(local_data->newly_discovered_nodes, print_node_addr);
			C_DEBUG(C_DEBUG_LEVEL_NONE, "\n");
			send_GRAPHS_RESET(local_data->coordinator_address, local_data->newly_discovered_nodes);
			list_free(&local_data->data_nodes);
			list_free(&local_data->newly_discovered_nodes);
			FREE(local_data);
			C_GRAPHS_local_data = NULL;
			return;
		}
		C_DEBUG(C_DEBUG_LEVEL_INFO, "GRAPHS: Connectivity tests complete.\n");

		// Establish the reference node and its backup.
		for(i = 0; i < list_size(local_data->data_nodes); i++) {
			GRAPHS_local_data_node_t* data_node = (GRAPHS_local_data_node_t*) list_get(local_data->data_nodes, i);
			if(
				(data_node->node.address != C_LOCAL_ADDR)
				&& (data_node->connectivity_count > local_data->max_connectivity_count)
			) {
				local_data->max_connectivity_count = data_node->connectivity_count;
				local_data->max_connectivity_node_address = data_node->node.address;
			}
		}
		for(i = 0; i < list_size(local_data->data_nodes); i++) {
			GRAPHS_local_data_node_t* data_node = (GRAPHS_local_data_node_t*) list_get(local_data->data_nodes, i);
			if(
				(data_node->node.address != C_LOCAL_ADDR)
				&& (data_node->node.address != local_data->max_connectivity_node_address)
				&& (data_node->connectivity_count > local_data->max2_connectivity_count)
			) {
				local_data->max2_connectivity_count = data_node->connectivity_count;
				local_data->max2_connectivity_node_address = data_node->node.address;
			}
		}

		C_DEBUG(C_DEBUG_LEVEL_INFO, "GRAPHS: Starting interference tests using node %s as reference and node %s as backup...\n", addr_to_str(local_data->max_connectivity_node_address), addr_to_str(local_data->max2_connectivity_node_address));
		collect_interference_data(local_data);
	}
}

/**
 * @brief Handle an incoming GRAPHS REQUEST packet.
 *
 * Start gathering information on network conditions.
 *
 * @param header Pointer to header of the incoming packet.
 * @param payload Pointer to the payload that contains a list of all nodes in
 * the network.
 */
void handle_GRAPHS_REQUEST(const packet_header_t* header, const void* payload) {
	list_t* nodes = NULL;

	if(C_GRAPHS_local_data != NULL) {
		C_DEBUG(C_DEBUG_LEVEL_ERROR, "GRAPHS: Received GRAPHS REQUEST from node %s, but local graph construction is already in progress...\n", addr_to_str(header->from));
		return;
	}

	C_DEBUG(C_DEBUG_LEVEL_DEBUG, "GRAPHS: Received GRAPHS REQUEST from node %s...\n", addr_to_str(header->from));
	list_alloc(&nodes);
	list_from_array(nodes, payload, sizeof(node_t), header->payload_length);
	MALLOC(C_GRAPHS_local_data, GRAPHS_local_data_t);
	C_GRAPHS_local_data->coordinator_address = header->from;
	list_alloc(&C_GRAPHS_local_data->data_nodes);
	while(!list_empty(nodes)) {
		node_t* node = (node_t*) list_head(nodes);
		GRAPHS_local_data_node_t* data_node;
		MALLOC(data_node, GRAPHS_local_data_node_t);
		memcpy(&data_node->node, node, sizeof(node_t));
		list_remove(nodes, node);
		FREE(node);
		if(data_node->node.address == C_LOCAL_ADDR) {
			data_node->connectivity_count = GRAPHS_CONNECTIVITY_SAMPLES;
			data_node->interference = 0;
			data_node->interference_count = 0;
		} else {
			data_node->connectivity_count = 0;
			data_node->interference = -1;
			data_node->interference_count = 0;
		}
		list_add(C_GRAPHS_local_data->data_nodes, data_node);
	}
	list_free(&nodes);
	C_GRAPHS_local_data->connectivity_samples = 0;
	list_alloc(&C_GRAPHS_local_data->newly_discovered_nodes);
	C_GRAPHS_local_data->active_data_node = NULL;
	C_GRAPHS_local_data->max_connectivity_count = 0;
	C_GRAPHS_local_data->max_connectivity_node_address = C_BROADCAST_ADDR;
	C_GRAPHS_local_data->max2_connectivity_count = 0;
	C_GRAPHS_local_data->max2_connectivity_node_address = C_BROADCAST_ADDR;
	C_GRAPHS_local_data->active_data_node = NULL;
	C_GRAPHS_local_data->active_test_id = 0;
	C_GRAPHS_local_data->reference_node_address = C_BROADCAST_ADDR;
	C_GRAPHS_local_data->reference_connectivity_count = 0;
	C_GRAPHS_local_data->last_interference_packet_source = C_BROADCAST_ADDR;
	C_GRAPHS_local_data->current_test_invalid = false;

	C_DEBUG(C_DEBUG_LEVEL_INFO, "GRAPHS: Starting connectivity tests...\n");
	collect_connectivity_data(C_GRAPHS_local_data);
}

/**
 * @brief Callback for iteratively sending test packets.
 *
 * @param parameter Callback parameter.
 */
void handle_GRAPHS_TEST_REQUEST_callback(callback_parameter_t parameter) {
	GRAPHS_test_t* test = (GRAPHS_test_t*) parameter;

	C_DEBUG(C_DEBUG_LEVEL_VERBOSE, "GRAPHS: Preparing next TEST DATA packet for test #%d from node %s...\n", test->id, addr_to_str(test->node_address));
	if((test->packets > 0) && (test->packet_count < test->packets)) {
		test->packet_count++;
		send_GRAPHS_TEST_DATA(test->id, test->node_address);
		callback_add(handle_GRAPHS_TEST_REQUEST_callback, test, test->interval);
	} else if(C_time() < test->end_time) {
		send_GRAPHS_TEST_DATA(test->id, test->node_address);
		callback_add(handle_GRAPHS_TEST_REQUEST_callback, test, test->interval);
	} else {
		C_DEBUG(C_DEBUG_LEVEL_DEBUG, "GRAPHS: All packets for test #%d from node %s have been sent.\n", test->id, addr_to_str(test->node_address));
		FREE(test);
	}
}

/**
 * @brief Handle GRAPHS TEST REQUEST packet.
 *
 * @param header Pointer to packet header.
 * @param test_request Pointer to test request.
 */
void handle_GRAPHS_TEST_REQUEST(const packet_header_t* header, const GRAPHS_TEST_REQUEST_packet_t* test_request) {
	GRAPHS_test_t* test = NULL;

	C_DEBUG(C_DEBUG_LEVEL_DEBUG, "GRAPHS: Received GRAPHS TEST REQUEST from node %s, starting at %.2f...\n", addr_to_str(header->from), (C_time() + test_request->delay));
	MALLOC(test, GRAPHS_test_t);
	test->id = test_request->test_id;
	test->node_address = header->from;
	test->packets = test_request->packets;
	test->interval = test_request->interval;
	test->packet_count = 0;
	test->end_time = C_time() + test_request->duration;
	callback_add(handle_GRAPHS_TEST_REQUEST_callback, test, test_request->delay);
}

/**
 * @brief Handle GRAPHS TEST DATA packet.
 *
 * @param header Pointer to packet header.
 * @param test_data Pointer to test data.
 */
void handle_GRAPHS_TEST_DATA(const packet_header_t* header, const GRAPHS_TEST_DATA_packet_t* test_data) {
	if(test_data->node_address != C_LOCAL_ADDR) {
		C_DEBUG(C_DEBUG_LEVEL_VERBOSE, "GRAPHS: Ignoring GRAPHS TEST DATA from node %s to node %s...\n", addr_to_str(header->from), addr_to_str(test_data->node_address));
		return;
	} else if(C_GRAPHS_local_data == NULL) {
		C_DEBUG(C_DEBUG_LEVEL_WARN, "GRAPHS: Received GRAPHS TEST DATA from node %s, but no local graph construction is active on this node.\n", addr_to_str(header->from));
		return;
	} else if(test_data->test_id != C_GRAPHS_local_data->active_test_id) {
		C_DEBUG(C_DEBUG_LEVEL_WARN, "GRAPHS: Received GRAPHS TEST DATA from node %s with wrong test ID (%d != %d)...\n", addr_to_str(header->from), test_data->test_id, C_GRAPHS_local_data->active_test_id);
		return;
	}

	if(header->from == C_GRAPHS_local_data->reference_node_address) {
		if(C_GRAPHS_local_data->last_interference_packet_source == C_BROADCAST_ADDR) {
			C_DEBUG(C_DEBUG_LEVEL_WARN, "GRAPHS: Received GRAPHS TEST DATA from reference node %s before seeing any packets from the active node %s.\n", addr_to_str(C_GRAPHS_local_data->reference_node_address), addr_to_str(C_GRAPHS_local_data->active_data_node->node.address));
		} else if(C_GRAPHS_local_data->active_data_node->interference_count > 0) {
			C_DEBUG(C_DEBUG_LEVEL_DEBUG, "GRAPHS: Received GRAPHS TEST DATA from reference node %s...\n", addr_to_str(header->from));
			C_GRAPHS_local_data->active_data_node->interference_count--;
		} else {
			C_DEBUG(C_DEBUG_LEVEL_WARN, "GRAPHS: Ignoring excessive GRAPHS TEST DATA from reference node %s...\n", addr_to_str(header->from));
		}
	} else if(header->from == C_GRAPHS_local_data->active_data_node->node.address) {
		C_DEBUG(C_DEBUG_LEVEL_VERBOSE, "GRAPHS: Received GRAPHS TEST DATA from active node %s...\n", addr_to_str(header->from));
	} else {
		C_DEBUG(C_DEBUG_LEVEL_ERROR, "GRAPHS: Received GRAPHS TEST DATA from invalid node %s...\n", addr_to_str(header->from));
		return;
	}
	C_GRAPHS_local_data->last_interference_packet_source = header->from;
}
