1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-25 14:33:52 +01:00

removed unmaintained micro mesh routing code

This commit is contained in:
Oleg Hahm 2013-08-12 22:34:34 +02:00
parent 540515bd98
commit d7a297957f
5 changed files with 0 additions and 2283 deletions

View File

@ -1,6 +0,0 @@
INCLUDES = -I.. -I../../include -I../../drivers/include -I../../../core/include -I../../lib -I../../lib/cmdengine -I../../../hal/include
MODULE =net_mm
include $(MAKEBASE)/Makefile.base

View File

@ -1,967 +0,0 @@
/******************************************************************************
Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved.
These sources were developed at the Freie Universitaet Berlin, Computer Systems
and Telematics group (http://cst.mi.fu-berlin.de).
-------------------------------------------------------------------------------
This file is part of RIOT.
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
RIOT is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see http://www.gnu.org/licenses/ .
--------------------------------------------------------------------------------
For further information and questions please use the web site
http://scatterweb.mi.fu-berlin.de
and the mailinglist (subscription via web site)
scatterweb@lists.spline.inf.fu-berlin.de
*******************************************************************************/
/**
* @file
* @internal
* @brief Micro Mesh Routing
*
* @author Freie Universität Berlin, Computer Systems & Telematics
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de>
* @version $Revision: 3854 $
*
* @note $Id: mmr.c 3854 2011-12-06 15:27:01Z hwill $
*/
#include "configure.h"
#include "mmr.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "net.h"
#include "clock.h"
#include "utimer.h"
#include "kernel.h"
#include "thread.h"
#include "msg.h"
#define LEVEL_INFO 2 ///< All messages are printed
#define LEVEL_WARN 1 ///< Only warnings and error messages are printed
#define LEVEL_ERROR 0 ///< Only error messages are printed
#define MMR_INFO_LEVEL LEVEL_WARN ///< Current information level
#define DEBUG(...)
//#define DEBUG(...) printf(__VA_ARGS__)
#define CONSTANT_SECOND (1)
#define RREQ_ID_SEQUENCE_NUMBER_START (1)
#define RREQ_THRESHOLD (3)
#define RREQ_NONE (0xFF) /* Send no RREQs for these messages, value */
/* must be greater than RREQ_THRESHOLD */
#define TTL_START (1)
#define TTL_THRESHOLD (10)
#define RREQ_TIMEOUT_BASE (2*CONSTANT_SECOND)
#define RREQ_TIMEOUT_PER_TTL (1*CONSTANT_SECOND)
/*---------------------------------------------------------------------------*/
// Message queue data structures
/*---------------------------------------------------------------------------*/
#define MESSAGE_QUEUE_SIZE (20)
typedef struct {
net_message_t message;
volatile uint32_t timestamp;
uint8_t retry_count;
} message_queue_entry_t;
static message_queue_entry_t message_queue[MESSAGE_QUEUE_SIZE];
/*---------------------------------------------------------------------------*/
// RREQ-Timeout data structures
/*---------------------------------------------------------------------------*/
static struct utimer ut;
static volatile bool rreq_to_active = false; /* RREQ timeout active bit */
static const char *rreq_timeout_process_name = "mmrd";
static uint16_t rreq_timeout_process_pid;
static void rreq_timeout_process(void);
static void post_next_rreq_timeout(void);
/*---------------------------------------------------------------------------*/
// Statistic data structures
/*---------------------------------------------------------------------------*/
typedef struct mmr_stat {
uint32_t rreq_originated;
uint32_t rrep_originated;
uint32_t rerr_originated;
uint32_t rreq_received;
uint32_t rrep_received;
uint32_t rerr_received;
uint32_t messages_no_route_found; /* RREQ found no route */
uint32_t messages_no_route_avail_on_forward; /* Forwarding: no route in route table */
uint32_t messages_broken_link_on_forward; /* Forwarding: broken link detected */
uint32_t rreq_duplicated;
} mmr_stat_t;
static mmr_stat_t mmr_stats;
/*---------------------------------------------------------------------------*/
/**
* Returns time of RTC in seconds.
*
* @return Time of RTC in seconds
*/
static uint32_t rtc_now(void)
{
return (uint32_t)(clock_get_systemtime() / 1000);
}
/*---------------------------------------------------------------------------*/
// Routing table management
/*---------------------------------------------------------------------------*/
/**
* @brief Extract route information and store them in route table.
*
* @param local_addr Local network address of this node
* @param length Length of address list
* @param list Address list with route information
*/
static void rt_extract_routes(uint16_t local_addr, uint8_t length, uint16_t *list)
{
DEBUG("call [%u]: rt_extract_routes\n", fk_thread->pid);
uint16_t net_id = NETWORK_ADDR_BC(list[0]); /* BC address of source of RREQ */
route_table_entry_t *rte = rt_lookup_route(net_id); /* Should exist (preconfigured) */
if (rte == NULL) {
DEBUG("exit [%u]: rt_extract_routes\n", fk_thread->pid);
return; /* else exit here */
}
int i = 0;
while (i < length && list[i] != local_addr) {
i++;
}
if (i == length) {
DEBUG("exit [%u]: rt_extract_routes\n", fk_thread->pid);
return;
}
int pos = i;
int leftNeighbour = -1;
int rightNeighbour = -1;
if (pos > 0) {
leftNeighbour = list[pos - 1];
}
if (pos + 1 != length) {
rightNeighbour = list[pos + 1];
}
i = 0;
while (i < length) {
uint16_t next = list[i];
if (local_addr != next) {
int distance = pos - i;
int router = leftNeighbour;
if (distance < 0) {
router = rightNeighbour;
distance *= -1;
}
rt_add_route(next, (uint16_t)router, (uint8_t)distance, rte->interface_id);
}
i++;
}
DEBUG("exit [%u]: rt_extract_routes\n", fk_thread->pid);
}
/*---------------------------------------------------------------------------*/
// Message queue management
/*---------------------------------------------------------------------------*/
/**
* @brief Add a message to the message queue.
*
* @param msg The packet to add to the queue
*
* @return A pointer to a message queue entry or NULL if
* message queue is full.
*/
static message_queue_entry_t *mq_add(net_message_t *msg)
{
DEBUG("call [%u]: mq_add\n", fk_thread->pid);
/* Holds eventually first active RREQ to same destination */
message_queue_entry_t *pFirstFoundDup = NULL;
/* Find the first active RREQ to this destination */
int i;
for (i = 0; i < MESSAGE_QUEUE_SIZE; i++) {
if (message_queue[i].timestamp != 0 &&
message_queue[i].message.destination == msg->destination &&
message_queue[i].retry_count != RREQ_NONE) {
DEBUG("%s FOUND Duplicated Request to %u.%u in route req queue\n",
__FUNCTION__, (0xFF00 & msg->destination) >> 8, (0xFF & msg->destination));
/* Save the first found entry to modify later if insertion was successful */
pFirstFoundDup = &message_queue[i];
break;
}
}
/* If RREQ for same destination found then reset values
* even if the new message will get dropped later on because of
* limited queue space. Route to this destination gets queried
* again for sure so make new RREQ as soon as possible... */
if (pFirstFoundDup != NULL) {
pFirstFoundDup->retry_count = 0;
pFirstFoundDup->timestamp = 1;
mmr_stats.rreq_duplicated++;
}
/* Find free position to insert new message */
for (i = 0; i < MESSAGE_QUEUE_SIZE; i++) {
if (message_queue[i].timestamp == 0) {
/* Free position found, add entry */
message_queue[i].message = *msg;
if (pFirstFoundDup != NULL) {
/* There is already a RREQ for this destination, so don't
* generate a new one */
message_queue[i].retry_count = RREQ_NONE;
}
else {
/* Set initial RREQ retry counter to zero */
message_queue[i].retry_count = 0;
}
message_queue[i].timestamp = 1;
DEBUG("exit [%u]: mq_add\n", fk_thread->pid);
return &message_queue[i];
}
}
DEBUG("exit [%u]: mq_add\n", fk_thread->pid);
return NULL;
}
/**
* @brief Count messages for given destination.
*
* @param dst Destination address
*
* @return The number of messages for the destination.
*/
static int mq_msgs_for_destination(uint16_t dst)
{
DEBUG("call [%u]: mq_msgs_for_destination\n", fk_thread->pid);
int i, dst_count = 0;
for (i = 0; i < MESSAGE_QUEUE_SIZE; i++) {
if (message_queue[i].timestamp != 0 &&
message_queue[i].message.destination == dst) {
dst_count++;
}
}
DEBUG("exit [%u]: mq_msgs_for_destination\n", fk_thread->pid);
return dst_count;
}
/**
* @brief Remove all messages for given destination out of message queue.
*
* @param dst Destination address
*/
static void mq_remove_msgs_for_destination(uint16_t dst)
{
DEBUG("call [%u]: mq_remove_msgs_for_destination\n", fk_thread->pid);
int i;
for (i = 0; i < MESSAGE_QUEUE_SIZE; i++) {
if (message_queue[i].timestamp != 0 &&
message_queue[i].message.destination == dst) {
message_queue[i].timestamp = 0;
}
}
DEBUG("exit [%u]: mq_remove_msgs_for_destination\n", fk_thread->pid);
}
/**
* @brief Send all queued messages for given destination.
*
* @param dst Destination address
*/
static void mq_dequeue_and_send(uint16_t dst)
{
int i;
DEBUG("call [%u]: mq_dequeue_and_send\n", fk_thread->pid);
/* Stop any pending RREQ-Timeout, it's possibly handled now */
rreq_to_active = false;
utimer_remove(&ut);
/* Prioritize packets for given destination, route entry should exist */
route_table_entry_t *rte = rt_lookup_route(dst);
if (rte != NULL) {
for (i = 0; i < MESSAGE_QUEUE_SIZE; i++) {
if (message_queue[i].timestamp != 0 &&
message_queue[i].message.destination == dst) {
bool res = net_enqueue_for_transmission(&message_queue[i].message,
rte->interface_id,
rte->gateway, true);
if (res) {
message_queue[i].timestamp = 0;
}
}
}
}
/* Now all other packets */
for (i = 0; i < MESSAGE_QUEUE_SIZE; i++) {
if (message_queue[i].timestamp != 0 &&
message_queue[i].message.destination != dst) {
route_table_entry_t *rte = rt_lookup_route(message_queue[i].message.destination);
if (rte != NULL) {
bool res = net_enqueue_for_transmission(&message_queue[i].message,
rte->interface_id,
rte->gateway, true);
if (res) {
message_queue[i].timestamp = 0;
}
}
}
}
/* This function was triggered either by RREP packet or RREQ-Timeout. */
/* So update or set new RREQ-Timeout for other packets in queue. */
post_next_rreq_timeout();
DEBUG("exit [%u]: mq_dequeue_and_send\n", fk_thread->pid);
}
/*---------------------------------------------------------------------------*/
// Initialization of MMR layer
/*---------------------------------------------------------------------------*/
void mmr_init(void)
{
rt_init();
memset(message_queue, 0, sizeof(message_queue_entry_t) * MESSAGE_QUEUE_SIZE);
rreq_timeout_process_pid = thread_create(2500, PRIORITY_MMREQ, CREATE_STACKTEST,
rreq_timeout_process, rreq_timeout_process_name);
}
/*---------------------------------------------------------------------------*/
// Send & receive functions
/*---------------------------------------------------------------------------*/
/**
* @brief Tests if the net message contains a RERR.
*
* @param msg The net message to test
*
* @return true if the net message contains a RERR; false otherwise.
*/
static bool is_route_error(net_message_t *msg)
{
if (msg->protocol == LAYER_2_PROTOCOL_MMR) {
/* First byte in {RREQ, RREP, RERR} is always type */
if (msg->payload[0] == MMR_TYPE_RERR) {
return true;
}
}
return false;
}
/**
* @brief Generates a route reply message.
*
* @param rreq_msg Corresponding route request message
*/
static void generate_route_reply_message(mmr_rreq_message_t *rreq_msg)
{
DEBUG("call [%u]: generate_route_reply_message\n", fk_thread->pid);
/* Create RREP message */
mmr_rrep_message_t rrep_msg;
rrep_msg.type = MMR_TYPE_RREP;
rrep_msg.length = rreq_msg->length;
rrep_msg.destination = rreq_msg->source;
rrep_msg.source = rreq_msg->destination;
memcpy(rrep_msg.address, rreq_msg->address, rreq_msg->length * sizeof(uint16_t));
/* Create MMR message containing the RREP message */
net_message_t net_msg;
net_msg.protocol = LAYER_2_PROTOCOL_MMR;
net_msg.flags_tos = PRIORITY_ALARM;
net_msg.seq_clr_id = 0;
net_msg.ttl = TTL_THRESHOLD;
net_msg.source = rrep_msg.source;
net_msg.destination = rrep_msg.destination;
memcpy(net_msg.payload, (void *)&rrep_msg, sizeof(mmr_rrep_message_t));
/* Source address must exist in route table to find correct */
/* interface id and next hop (should be created by RREQ) */
route_table_entry_t *rte = rt_lookup_route(net_msg.destination);
if (rte != NULL) {
/* Send message to next hop */
mmr_stats.rrep_originated++;
net_enqueue_for_transmission(&net_msg, rte->interface_id, rte->gateway, true);
}
DEBUG("exit [%u]: generate_route_reply_message\n", fk_thread->pid);
}
/**
* @brief Generates a route error message.
*
* @param dst Destination address of RERR packet
* @param gateway Next hop network address of RERR packet
* @param intf Interface id of RERR packet
* @param type Error type of RERR packet
* @param type_data Type specific data of RERR packet
*/
static void generate_route_error_message(uint16_t dst, uint16_t gateway, int intf, uint8_t type, uint16_t type_data)
{
DEBUG("call [%u]: generate_route_error_message\n", fk_thread->pid);
/* Define RERR message */
mmr_rerr_message_t rerr_msg;
rerr_msg.type = MMR_TYPE_RERR;
rerr_msg.error_type = type;
rerr_msg.type_specific_info = type_data;
/* Wrap RERR message in net message */
net_message_t net_msg;
net_msg.protocol = LAYER_2_PROTOCOL_MMR;
net_msg.flags_tos = PRIORITY_DATA;
net_msg.seq_clr_id = 0;
net_msg.ttl = TTL_THRESHOLD;
net_msg.source = net_get_address_in_subnet(dst);
net_msg.destination = dst;
memcpy(net_msg.payload, (void *)&rerr_msg, sizeof(mmr_rerr_message_t));
/* Send message to next hop */
mmr_stats.rerr_originated++;
net_enqueue_for_transmission(&net_msg, intf, gateway, true);
DEBUG("exit [%u]: generate_route_error_message\n", fk_thread->pid);
}
/**
* @brief Receive a route request message.
*
* @param msg The route request packet
* @param packet_info Additional packet information
*/
static void receive_route_request_message(mmr_rreq_message_t *msg,
packet_info_t *packet_info)
{
DEBUG("call [%u]: receive_route_request_message\n", fk_thread->pid);
uint16_t my_addr = net_get_address_in_subnet(msg->source);
#if (MMR_INFO_LEVEL >= LEVEL_WARN)
if (my_addr == 0) {
puts("MMR [WARN]: received RREQ with unknown network part of source address");
puts("MMR [WARN]: => can't find own net address in sub net!");
}
#endif
/* If address list of RREQ message has enough space */
if (msg->length < ADDRESS_LIST_SIZE) {
/* append our node id to list */
msg->address[msg->length++] = my_addr;
/* add routes with overhearing */
rt_extract_routes(my_addr, msg->length, msg->address);
}
/* Distance between sender and receiver is too long, discard packet */
else {
/* Drop RREQ packet => set TTL to zero */
*packet_info->ttl_ptr = 0;
DEBUG("exit [%u]: receive_route_request_message\n", fk_thread->pid);
return;
}
/* If RREQ message was send to us, then send RREP message */
if (msg->destination == my_addr) {
/* Don't forward RREQ packet any further => set TTL to zero */
*packet_info->ttl_ptr = 0;
generate_route_reply_message(msg);
}
DEBUG("exit [%u]: receive_route_request_message\n", fk_thread->pid);
}
/**
* @brief Receive a route reply message.
*
* @param msg The route reply packet
* @param packet_info Additional packet information
*/
static void receive_route_reply_message(mmr_rrep_message_t *msg,
packet_info_t *packet_info)
{
DEBUG("call [%u]: receive_route_reply_message\n", fk_thread->pid);
/* RREP received: Send out queued packets for which routes are now known */
mq_dequeue_and_send(msg->source);
DEBUG("exit [%u]: receive_route_reply_message\n", fk_thread->pid);
}
/**
* @brief Receive a route error message.
*
* @param msg The route error packet
* @param packet_info Additional packet information
*/
static void receive_route_error_message(mmr_rerr_message_t *msg,
packet_info_t *packet_info)
{
DEBUG("call [%u]: receive_route_error_message\n", fk_thread->pid);
switch(msg->error_type) {
case RERR_NODE_UNREACHABLE:
rt_remove_route(msg->type_specific_info);
break;
default:
#if (MMR_INFO_LEVEL >= LEVEL_INFO)
puts("MMR [INFO]: RERR error type is unknown");
#endif
break;
}
DEBUG("exit [%u]: receive_route_error_message\n", fk_thread->pid);
}
/**
* @brief Computes the RREQ timeout period, given a
* TTL and destination address value.
*
* @param ttl Time to live
* @param dst Network destination address
*
* @return RREQ timeout period in seconds
*/
static int compute_rreq_timeout(int ttl, uint16_t dst)
{
int t_hop = net_get_interface_transmission_duration(dst);
if (t_hop == -1) {
t_hop = RREQ_TIMEOUT_PER_TTL * ttl;
}
else {
t_hop = (t_hop * ttl + 999) / 1000;
}
return RREQ_TIMEOUT_BASE + 2 * t_hop;
}
/**
* @brief Broadcast a RREQ message.
*
* A single route request can repeatedly broadcast RREQ messages,
* with increasing TTL value, until a route has been found.
*
* @param mq_entry Pointer to a message queue entry (the packet
* for which to find the route)
*/
static void rreq_broadcast(message_queue_entry_t *mq_entry)
{
DEBUG("call [%u]: rreq_broadcast\n", fk_thread->pid);
if (mq_entry->retry_count == RREQ_NONE) {
DEBUG("call [%u]: rreq duplicated do not send\n", fk_thread->pid);
return;
}
/* Create RREQ message */
mmr_rreq_message_t rreq_msg;
rreq_msg.type = MMR_TYPE_RREQ;
rreq_msg.length = 1;
rreq_msg.destination = mq_entry->message.destination;
rreq_msg.source = mq_entry->message.source;
rreq_msg.address[0] = mq_entry->message.source;
/* Wrap RREQ message in net message */
net_message_t net_msg;
net_msg.protocol = LAYER_2_PROTOCOL_MMR;
net_msg.flags_tos = PRIORITY_DATA;
net_msg.seq_clr_id = 0;
net_msg.ttl = mq_entry->retry_count == 0 ? TTL_START : TTL_THRESHOLD;
net_msg.source = rreq_msg.source;
net_msg.destination = NETWORK_ADDR_BC(rreq_msg.destination);
memcpy(net_msg.payload, (void *)&rreq_msg, sizeof(mmr_rreq_message_t));
/* Broadcast the net message */
mq_entry->retry_count++;
mq_entry->timestamp = rtc_now();
/* Find the broadcast route table entry */
route_table_entry_t *rte = rt_lookup_route(net_msg.destination);
if (rte != NULL) {
/* Next hop address is broadcast address of lower layer */
net_enqueue_for_transmission(&net_msg, rte->interface_id,
rte->gateway, true);
}
DEBUG("exit [%u]: rreq_broadcast\n", fk_thread->pid);
}
/**
* @brief Find next RREQ to time out. Post event immediately or
* with utimer.
*/
static void post_next_rreq_timeout(void)
{
DEBUG("call [%u]: post_next_rreq_timeout\n", fk_thread->pid);
int i, j = -1;
uint32_t now, next = 0xffffffff;
for (i = 0; i < MESSAGE_QUEUE_SIZE; i++) {
if ((message_queue[i].timestamp != 0) && (message_queue[i].retry_count !=
RREQ_NONE)) {
int ttl = message_queue[i].retry_count == 1 ? TTL_START : TTL_THRESHOLD;
int to = compute_rreq_timeout(ttl,
message_queue[i].message.destination);
if (message_queue[i].timestamp + to < next) {
next = message_queue[i].timestamp + to;
j = i;
}
}
}
if (j == -1) {
DEBUG("exit [%u]: post_next_rreq_timeout\n", fk_thread->pid);
return;
}
/* Stop any utimer */
rreq_to_active = false;
utimer_remove(&ut);
/* If current time greater than RREQ timeout value */
now = rtc_now();
if (now >= next) {
/* Schedule RREQ-Timeout immediately */
msg m;
m.type = MSG_TIMER;
m.content.ptr = (char *)&message_queue[j];
rreq_to_active = true;
if (msg_send(&m, rreq_timeout_process_pid, false) != 1) {
/* Message could not be send (receiver not waiting), schedule
* timer with minimum delay */
#if (MMR_INFO_LEVEL >= LEVEL_WARN)
puts("MMR [WARN]: Immediate schedule of RREQ-Timeout failed, process not waiting!");
#endif
utimer_set_wpid(&ut, 1, rreq_timeout_process_pid, &message_queue[j]);
}
}
else {
/* Set new utimer with time difference */
rreq_to_active = true;
utimer_set_wpid(&ut, next - now, rreq_timeout_process_pid,
&message_queue[j]);
}
DEBUG("exit [%u]: post_next_rreq_timeout\n", fk_thread->pid);
}
/**
* This event is called periodically after a route request is originated,
* until a route has been found.
*
* Each time it is called, it rebroadcasts the route request message with a
* new rreq id and incremented TTL.
*/
static void rreq_timeout(message_queue_entry_t *mqe)
{
DEBUG("call [%u]: rreq_timeout\n", fk_thread->pid);
/* Test if valid entry passed */
if (mqe->timestamp == 0) {
#if (MMR_INFO_LEVEL >= LEVEL_WARN)
puts("MMR [WARN]: invalid message queue entry for RREQ-Timeout");
#endif
goto post_next_to;
}
/* See if route to destination was found */
route_table_entry_t *rte = rt_lookup_route(mqe->message.destination);
/* If found and no messages in queue for destination: return (queued
* packets are send on reception of RREP); If found but messages in queue:
* trigger send immediately here!*/
if (rte != NULL) {
int msg_count = mq_msgs_for_destination(mqe->message.destination);
if (msg_count > 0) {
mq_dequeue_and_send(mqe->message.destination);
DEBUG("exit [%u]: rreq_timeout\n", fk_thread->pid);
return;
}
else {
/* Added just for security but this case should never occur */
#if (MMR_INFO_LEVEL >= LEVEL_WARN)
puts("MMR [WARN]: RREQ-Timeout occurred, route is available but no messages for destination");
#endif
/* Anyway: jump to update next RREQ-Timeout */
goto post_next_to;
}
}
/* Otherwise send new RREQ if below threshold (means also retry count !=
* RREQ_NONE) */
if (mqe->retry_count < RREQ_THRESHOLD) {
/* Broadcast new RREQ message (with incremented TTL) */
rreq_broadcast(mqe);
}
else {
/* Remove all messages for this destination */
mmr_stats.messages_no_route_found++;
mq_remove_msgs_for_destination(mqe->message.destination);
}
/* Anyway: update or set next RREQ-Timeout */
post_next_to:
post_next_rreq_timeout();
DEBUG("exit [%u]: rreq_timeout\n", fk_thread->pid);
}
static void rreq_timeout_process(void)
{
msg m;
do {
msg_receive(&m);
if (m.type == MSG_TIMER && rreq_to_active) {
rreq_to_active = false;
rreq_timeout((message_queue_entry_t *)m.content.ptr);
}
}
while (m.type != MSG_EXIT);
}
void mmr_peek(net_message_t *message, packet_info_t *packet_info)
{
DEBUG("call [%u]: mmr_peek\n", fk_thread->pid);
/* Only look at micro mesh routing messages */
if (message->protocol == LAYER_2_PROTOCOL_MMR) {
uint8_t type = message->payload[0];
uint16_t my_addr = net_get_address_in_subnet(message->source);
if (type == MMR_TYPE_RREP) {
/* Add routes to route table */
mmr_rrep_message_t *rrep_msg = (mmr_rrep_message_t *)message->payload;
#if (MMR_INFO_LEVEL >= LEVEL_WARN)
if (my_addr == 0) {
puts("MMR [WARN]: received RREP with unknown network part of source address");
puts("MMR [WARN]: => can't find own net address in sub net!");
}
#endif
rt_extract_routes(my_addr, rrep_msg->length, rrep_msg->address);
}
else if (type == MMR_TYPE_RERR) {
#if (MMR_INFO_LEVEL >= LEVEL_WARN)
if (my_addr == 0) {
puts("MMR [WARN]: received RERR with unknown network part of source address");
puts("MMR [WARN]: => can't find own net address in sub net!");
}
#endif
/* If not destination of RERR, then remove route to unavailable
* node in RERR packet */
if (message->destination != my_addr) {
mmr_rerr_message_t *rerr_msg =
(mmr_rerr_message_t *)message->payload;
if (rerr_msg->error_type == RERR_NODE_UNREACHABLE) {
rt_remove_route(rerr_msg->type_specific_info);
}
}
}
}
DEBUG("exit [%u]: mmr_peek\n", fk_thread->pid);
}
bool mmr_send(net_message_t *message)
{
DEBUG("call [%u]: mmr_send\n", fk_thread->pid);
bool enqueue = true;
if (message->destination == net_get_address_in_subnet(message->destination)) {
#if (MMR_INFO_LEVEL >= LEVEL_WARN)
puts("MMR [WARN]: message is already at destination, why is routing called?");
#endif
DEBUG("exit [%u]: mmr_send\n", fk_thread->pid);
return false;
}
if (NETWORK_ADDR_NET(message->destination) == 0) {
#if (MMR_INFO_LEVEL >= LEVEL_WARN)
puts("MMR [WARN]: NET part of address cannot be 0!");
#endif
DEBUG("exit [%u]: mmr_send\n", fk_thread->pid);
return false;
}
if (NETWORK_ADDR_HOST(message->destination) == 0) {
#if (MMR_INFO_LEVEL >= LEVEL_INFO)
puts("MMR [INFO]: broadcast destination, why is routing called? A route entry should exist!");
#endif
enqueue = false;
}
/* Look up next hop address for this destination in routing table */
route_table_entry_t *rte = rt_lookup_route(message->destination);
/* If next hop address found in routing table, forward message */
if (rte != NULL) {
DEBUG("exit [%u]: mmr_send\n", fk_thread->pid);
return net_enqueue_for_transmission(message, rte->interface_id, rte->gateway, true);
}
/* Otherwise, save message in queue; broadcast RREQ message */
else {
if (!enqueue) {
/* Don't enqueue broadcast destinations */
DEBUG("exit [%u]: mmr_send\n", fk_thread->pid);
return false;
}
message_queue_entry_t *mqe = mq_add(message);
if (mqe != NULL) {
rreq_broadcast(mqe);
post_next_rreq_timeout();
mmr_stats.rreq_originated++;
DEBUG("exit [%u]: mmr_send\n", fk_thread->pid);
return true;
}
}
DEBUG("exit [%u]: mmr_send\n", fk_thread->pid);
return false;
}
void mmr_packet_dropped(net_message_t *message, uint16_t next_hop, int error)
{
DEBUG("call [%u]: mmr_packet_dropped\n", fk_thread->pid);
if (error == ROUTE_ERROR_BROKEN_ROUTE) {
/* Local failure detected - remove all routes through broken link */
rt_remove_gateway_routes(next_hop);
mmr_stats.messages_broken_link_on_forward++;
}
else if (error == ROUTE_ERROR_MISSING_ROUTE) {
mmr_stats.messages_no_route_avail_on_forward++;
}
/* If source != net_addr, send RERR to source of message */
if (message->source != net_get_address_in_subnet(message->source)) {
/* Do not generate RERR if it is already a RERR message */
if (is_route_error(message)) {
DEBUG("exit [%u]: mmr_packet_dropped\n", fk_thread->pid);
return;
}
/* Find next hop to source */
route_table_entry_t *rte = rt_lookup_route(message->source);
if (rte != NULL) {
generate_route_error_message(message->source, rte->gateway,
rte->interface_id,
RERR_NODE_UNREACHABLE,
message->destination);
}
#if (MMR_INFO_LEVEL >= LEVEL_WARN)
else {
printf("MMR [WARN]: cannot send RERR to source #%u, no route found!\n",
message->source);
}
#endif
}
DEBUG("exit [%u]: mmr_packet_dropped\n", fk_thread->pid);
}
void mmr_receive(void *msg, int msg_size, packet_info_t *packet_info)
{
DEBUG("call [%u]: mmr_receive\n", fk_thread->pid);
uint8_t *p = (uint8_t *) msg;
uint8_t type = p[0];
if (type == MMR_TYPE_RREQ) {
receive_route_request_message((mmr_rreq_message_t *)msg, packet_info);
mmr_stats.rreq_received++;
}
else if (type == MMR_TYPE_RREP) {
receive_route_reply_message((mmr_rrep_message_t *)msg, packet_info);
mmr_stats.rrep_received++;
}
else if (type == MMR_TYPE_RERR) {
receive_route_error_message((mmr_rerr_message_t *)msg, packet_info);
mmr_stats.rerr_received++;
}
#if (MMR_INFO_LEVEL >= LEVEL_INFO)
else {
printf("MMR [INFO]: can't handle message of type %u\n", type);
}
#endif
DEBUG("exit [%u]: mmr_receive\n", fk_thread->pid);
}
void mmr_print_stats(void)
{
printf("ROUTING LAYER STATS\r\n");
printf("-------------------\r\n");
printf("Route requests originated: %lu\r\n", mmr_stats.rreq_originated);
printf("Route requests duplicated: %lu\r\n", mmr_stats.rreq_duplicated);
printf("Route replies originated: %lu\r\n", mmr_stats.rrep_originated);
printf("Route errors originated: %lu\r\n", mmr_stats.rerr_originated);
printf("Route requests received: %lu\r\n", mmr_stats.rreq_received);
printf("Route replies received: %lu\r\n", mmr_stats.rrep_received);
printf("Route errors received: %lu\r\n", mmr_stats.rerr_received);
printf("\r\n");
printf("#Messages with no route found: %lu\r\n", mmr_stats.messages_no_route_found);
printf("#Messages with broken link on forward: %lu\r\n", mmr_stats.messages_broken_link_on_forward);
printf("#Messages with no route available on forward: %lu\r\n", mmr_stats.messages_no_route_avail_on_forward);
printf("\r\n");
}

View File

@ -1,171 +0,0 @@
/******************************************************************************
Copyright 2008, Freie Universitaet Berlin (FUB). All rights reserved.
These sources were developed at the Freie Universitaet Berlin, Computer Systems
and Telematics group (http://cst.mi.fu-berlin.de).
-------------------------------------------------------------------------------
This file is part of RIOT.
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
RIOT is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see http://www.gnu.org/licenses/ .
--------------------------------------------------------------------------------
For further information and questions please use the web site
http://scatterweb.mi.fu-berlin.de
and the mailinglist (subscription via web site)
scatterweb@lists.spline.inf.fu-berlin.de
*******************************************************************************/
#ifndef MMR_H_
#define MMR_H_
/**
* @file
* @internal
* @brief Micro Mesh Routing
*
* @author Freie Universität Berlin, Computer Systems & Telematics
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de>
* @version $Revision: 3854 $
*
* @note $Id: mmr.h 3854 2011-12-06 15:27:01Z hwill $
*/
#include "net-types.h"
#define MMR_TYPE_RREQ (1)
#define MMR_TYPE_RREP (2)
#define MMR_TYPE_RERR (3)
#define ADDRESS_LIST_SIZE (21)
#define RERR_NODE_UNREACHABLE (1)
/**
* Represents a Route Request (RREQ) message.
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Type | Length | Destination |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Source | Address[1..n] |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
typedef struct __attribute__((packed)) {
uint8_t type; ///< Must be first byte in struct for type detection
uint8_t length;
uint16_t destination;
uint16_t source;
uint16_t address[ADDRESS_LIST_SIZE];
} mmr_rreq_message_t;
/**
* Represents a Route Reply (RREP) message.
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Type | Length | Destination |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Source | Address[1..n] |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
typedef struct __attribute__((packed)) {
uint8_t type; ///< Must be first byte in struct for type detection
uint8_t length;
uint16_t destination;
uint16_t source;
uint16_t address[ADDRESS_LIST_SIZE];
} mmr_rrep_message_t;
/**
* Represents a Route Error (RERR) message.
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Type | Error Type | Type-Specific Information |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Valid Error Types are:
*
* 1 = NODE_UNREACHABLE
*
* Node Unreachable Type-Specific Information:
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Unreachable Node Address | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
typedef struct __attribute__((packed)) {
uint8_t type; ///< Must be first byte in struct for type detection
uint8_t error_type;
uint16_t type_specific_info;
} mmr_rerr_message_t;
/**
* @brief Initialize MMR layer.
*/
void mmr_init(void);
/**
* Called by the network layer for every incoming packet. A routing
* implementation may wish to look at these packets for informational
* purposes, but should not change their contents.
*
* @param message incoming packet
* @param packet_info Additional packet information
*/
void mmr_peek(net_message_t *message, packet_info_t *packet_info);
/**
* Called by the network layer to request transmission of a packet that
* requires routing. It is the responsibility of the routing layer to provide
* a best-effort transmission of this packet to an appropriate next hop by
* calling the networks layer sending routines once this routing information
* becomes available.
*
* @param message outgoing packet
*
* @return true if packet was successfully stored for transmission; false otherwise
* (e.g. message queue full).
*/
bool mmr_send(net_message_t *message);
/**
* Called by the network layer which forwards notifications of dropped packets
* from the link layer. Not all MAC implementations support this feature!
*
* @param message dropped network packet
* @param next_hop next hop network address of dropped packet (can be undefined)
* @param error Error type which informs about reason
*/
void mmr_packet_dropped(net_message_t *message, uint16_t next_hop, int error);
/**
* @brief Receive a message from network layer.
*
* @param msg message received
* @param msg_size Size of received message
* @param packet_info Additional packet information
*/
void mmr_receive(void *msg, int msg_size, packet_info_t *packet_info);
/**
* @brief Print routing layer statistics.
*/
void mmr_print_stats(void);
#endif /* MMR_H_ */

View File

@ -1,925 +0,0 @@
/******************************************************************************
Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved.
These sources were developed at the Freie Universitaet Berlin, Computer Systems
and Telematics group (http://cst.mi.fu-berlin.de).
-------------------------------------------------------------------------------
This file is part of RIOT.
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
RIOT is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see http://www.gnu.org/licenses/ .
--------------------------------------------------------------------------------
For further information and questions please use the web site
http://scatterweb.mi.fu-berlin.de
and the mailinglist (subscription via web site)
scatterweb@lists.spline.inf.fu-berlin.de
*******************************************************************************/
#include "configure.h"
#include "mmstack.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "utimer.h"
#include "kernel.h"
#include "thread.h"
#include "msg.h"
#include "net.h"
#include "mmr.h"
#include "trans.h"
#include "clock.h"
#include "cmdengine.h"
/**
* @file
* @brief
*
* @author Freie Universität Berlin, Computer Systems & Telematics
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de>
* @version $Revision: 3854 $
*
* @note $Id: mmstack.c 3854 2011-12-06 15:27:01Z hwill $
*/
/*---------------------------------------------------------------------------*/
// Data structures for build in ping
/*---------------------------------------------------------------------------*/
#define MMS_PING_PACKETS (4) ///< Default number of packets in a ping
#define MMS_PING_ECHO_REQUEST (8) ///< Ping type: echo request
#define MMS_PING_ECHO_REPLY (0) ///< Ping type: echo reply
/**
* Represents a ping message.
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Type | Identifier | SeqNum |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Timestamp |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
typedef struct __attribute__((packed)) {
uint8_t type; ///< Type of ping message (request or reply)
uint8_t identifier; ///< Unique identifier for ping process
uint16_t seq_num; ///< Sequence number (increasing number within that process)
uint32_t timestamp; ///< Timestamp of request message
} mms_ping_message_t;
/**
* @brief Send ping echo request to destination address.
*
* @param destination The destination address.
* @param seq Sequence number of ping message.
* @param prio Priority of ping message.
* @param ttl TTL value for network message.
*/
static void mms_ping(uint16_t destination, uint8_t seq, uint8_t prio, int ttl);
static uint8_t mms_ping_last_proc_id; ///< Random process id of last ping request
static uint8_t mms_ping_packets; ///< Number of ping replies received
static int mms_ping_dups; ///< Duplicates
static bool ping_bc_mode; ///< If option -b is set and address is BC
static bool ping_silent_mode; ///< If option -s is set
static bool *dups; ///< Helper buffer to check for DUPs
static float rtt_min; ///< Min. RTT
static float rtt_max; ///< Max. RTT
static float rtt_avg; ///< Avg. RTT
static struct utimer mms_ping_utimer; ///< utimer for ping
static uint16_t mms_ping_pid; ///< Process ID of process ping is running within
/*---------------------------------------------------------------------------*/
// Data structures for build in SSH
/*---------------------------------------------------------------------------*/
#define MMS_SSH_CON_REQUEST (1) ///< SSH type: connection request
#define MMS_SSH_CON_ACCEPT (2) ///< SSH type: connection accept
#define MMS_SSH_CON_REJECT (3) ///< SSH type: connection reject
#define MMS_SSH_CON_CLOSE (4) ///< SSH type: connection close
#define MMS_SSH_DATA (5) ///< SSH type: data packet
#define MMS_SSH_DATA_MAX (43) ///< Maximum SSH data packet size
/**
* Represents a SSH message.
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Type | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
typedef struct __attribute__((packed)) {
uint8_t type; ///< Type of SSH message
} mms_ssh_message_t;
/**
* Represents a SSH data message.
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Type | Data |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
typedef struct __attribute__((packed)) {
uint8_t type; ///< Type of SSH message
uint8_t data[MMS_SSH_DATA_MAX]; ///< Message information
} mms_ssh_data_message_t;
/**
* @brief Make SSH connection request with given node.
*
* @param destination The destination address.
*/
static void mms_ssh_connect(uint16_t destination);
/**
* @brief Accept or reject SSH connection request.
*
* @param destination The destination address.
* @param socket The socket to use or -1.
* @param accept Whether to accept or reject the connection request.
*/
static void mms_ssh_reply_connect(uint16_t destination, int socket, bool accept);
/**
* @brief Close SSH connection.
*
* @param destination The destination address.
*/
static void mms_ssh_close(uint16_t destination);
static volatile int ssh_socket = -1;
/*---------------------------------------------------------------------------*/
// Interface definitions
/*---------------------------------------------------------------------------*/
static route_interface_t r_iface = {
rt_add_route,
rt_add_fix_route,
rt_lookup_route,
mmr_peek,
mmr_send,
mmr_packet_dropped,
mmr_receive,
mmr_print_stats
};
/*---------------------------------------------------------------------------*/
// Build in MMS commands
/*---------------------------------------------------------------------------*/
//#if CMD_ISLEVEL(CMD_LEVEL_SYSTEM_DEBUG | CMD_LEVEL_HUMAN_USER | CMD_LEVEL_OPERATION)
ASCCMD(route, CMDFLAG_SERIAL, "[-adfFg] print kernel route table");
CMD_FUNCTION(route, cmdargs)
{
if (cmdargs->arg_size > 0) {
char *msg = (char *)cmdargs->args;
while (*msg == ' ') {
msg++;
}
if (*msg == '-' && *(msg + 1) == 'f') {
mms_flush_routes(false);
printf("Kernel route table flushed (non-static)!\n");
return CMD_SUCCESS;
}
else if (*msg == '-' && *(msg + 1) == 'F') {
mms_flush_routes(true);
printf("Kernel route table flushed (static)!\n");
return CMD_SUCCESS;
}
else if (*msg == '-' && *(msg + 1) == 'd') {
msg++;
msg++;
while (*msg == ' ') {
msg++;
}
uint16_t address = net_strtoaddr(msg, &msg);
if (rt_remove_static_route(address)) {
printf("Static route deleted successfully!\n");
return CMD_SUCCESS;
}
return CMD_ERROR;
}
else if (*msg == '-' && *(msg + 1) == 'g') {
msg++;
msg++;
while (*msg == ' ') {
msg++;
}
uint16_t address = net_strtoaddr(msg, &msg);
int c = rt_remove_static_gateway_routes(address);
printf("%u static route(s) deleted!\n", c);
return CMD_SUCCESS;
}
else if (*msg == '-' && *(msg + 1) == 'a') {
msg++;
msg++;
while (*msg == ' ') {
msg++;
}
uint16_t address = net_strtoaddr(msg, &msg);
uint16_t gateway = net_strtoaddr(msg, &msg);
int metric = (int)strtoul(msg, &msg, 0);
int iface = (int)strtoul(msg, &msg, 0);
if (address != 0 && gateway != 0) {
if (rt_add_static_route(address, gateway, metric, iface)) {
printf("Static route added successfully!\n");
return CMD_SUCCESS;
}
}
return CMD_ERROR;
}
else {
printf("Usage: route [-adfFg] print kernel route table\n\n");
printf(" -a <DST> <GW> <M> <IFACE>, add static route to kernel route table\n");
printf(" -d <DST>, delete static route out of kernel route table\n");
printf(" -f, flush non-static routes out of kernel route table\n");
printf(" -F, flush static routes out of kernel route table\n");
printf(" -g <GW>, delete static routes out of kernel route table with a\n"
" specific gateway\n\n");
printf(" <DST> = destination network address\n");
printf(" <GW> = gateway network address\n");
printf(" <M> = metric, e.g. number of hops\n");
printf(" <IFACE> = network interface number\n\n");
return CMD_ERROR;
}
}
else {
mms_print_routes();
return CMD_SUCCESS;
}
}
ASCCMD(ifconfig, CMDFLAG_SERIAL, "[IFACE]: print interface configuration");
CMD_FUNCTION(ifconfig, cmdargs)
{
if (cmdargs->arg_size > 0) {
char *msg;
int iface = (int)strtoul(cmdargs->args, &msg, 0);
if (cmdargs->arg_size > 1) {
while (*msg == ' ') {
msg++;
}
if (*msg == '-' && (*(msg + 1) == 'P' || *(msg + 1) == 'p')) {
msg++;
msg++;
uint8_t power = (uint8_t)strtoul(msg, &msg, 0);
if (*msg != '\0') {
return CMD_ERROR;
}
if (mms_set_output_power(iface, power)) {
printf("Output power set!\n");
return CMD_SUCCESS;
}
return CMD_ERROR;
}
else if (*msg == '-' && (*(msg + 1) == 'A' || *(msg + 1) == 'a')) {
msg++;
msg++;
while (*msg == ' ') {
msg++;
}
uint16_t address = net_strtoaddr(msg, &msg);
if (mms_set_interface_address(iface, address)) {
printf("Interface address set!\n");
return CMD_SUCCESS;
}
return CMD_ERROR;
}
else {
printf("Usage: ifconfig [IFACE] [-AP] print interface configuration\n\n");
printf(" -A <ADDR>, set interface address, e.g. ifconfig 0 -A 1.1\n");
printf(" -P <POWER>, set output power on interface\n\n");
return CMD_ERROR;
}
}
else {
mms_print_ifconfig(iface);
}
}
else {
mms_print_ifconfig(-1);
}
return CMD_SUCCESS;
}
ASCCMD(ping, CMDFLAG_SERIAL, "ping [-bchpstw] destination");
CMD_FUNCTION(ping, cmdargs)
{
if (cmdargs->arg_size > 0) {
int i;
msg m;
uint8_t count = MMS_PING_PACKETS;
uint8_t prio = PRIORITY_DATA;
bool bc = false;
ping_bc_mode = false;
ping_silent_mode = false;
int ttl = 10;
long timeout = 3;
char adrbuf[10];
const char *msg = cmdargs->args;
read_ping_cmd:
while (*msg == ' ') {
msg++;
}
if (*msg == '-' && (*(msg + 1) == 'B' || *(msg + 1) == 'b')) {
bc = true;
msg++;
msg++;
goto read_ping_cmd;
}
else if (*msg == '-' && (*(msg + 1) == 'C' || *(msg + 1) == 'c')) {
msg++;
msg++;
unsigned long tc = strtoul(msg, (char **)&msg, 0);
if (tc == 0) {
return CMD_ERROR;
}
if (tc > 255) {
puts("Not more than 255 ping messages allowed!");
return CMD_ERROR;
}
count = (uint8_t) tc;
goto read_ping_cmd;
}
else if (*msg == '-' && (*(msg + 1) == 'H' || *(msg + 1) == 'h')) {
printf("Usage: ping [-bchpstw] destination\n\n");
printf(" -b, do a broadcast ping\n");
printf(" -c <COUNT>, set number of ping messages\n");
printf(" -h, print a help synopsis\n");
printf(" -p <PRIO>, set the ping message priority\n");
printf(" PRIO = 1: alarm\n");
printf(" PRIO = 2: warning\n");
printf(" PRIO = 3: data (default)\n");
printf(" -s, silent mode (no messages printed out)\n");
printf(" -t <TTL>, TTL value of ping messages (default: 10)\n");
printf(" -w <WAIT>, time to wait for a response, in seconds (default: 3)\n\n");
return CMD_SUCCESS;
}
else if (*msg == '-' && (*(msg + 1) == 'p' || *(msg + 1) == 'P')) {
msg++;
msg++;
unsigned long tp = strtoul(msg, (char **)&msg, 0);
if (tp == 0) {
return CMD_ERROR;
}
if (tp == 1) {
prio = 0;
}
else if (tp == 2) {
prio = 1;
}
else {
prio = 2;
}
goto read_ping_cmd;
}
else if (*msg == '-' && (*(msg + 1) == 's' || *(msg + 1) == 'S')) {
ping_silent_mode = true;
msg++;
msg++;
goto read_ping_cmd;
}
else if (*msg == '-' && (*(msg + 1) == 't' || *(msg + 1) == 'T')) {
msg++;
msg++;
unsigned long to = strtoul(msg, (char **)&msg, 0);
if (to == 0 || to > 255) {
return CMD_ERROR;
}
ttl = to;
goto read_ping_cmd;
}
else if (*msg == '-' && (*(msg + 1) == 'w' || *(msg + 1) == 'W')) {
msg++;
msg++;
unsigned long to = strtoul(msg, (char **)&msg, 0);
if (to == 0) {
return CMD_ERROR;
}
timeout = to;
goto read_ping_cmd;
}
uint16_t address = net_strtoaddr((char *)msg, (char **)&msg);
if (address == 0) {
return CMD_ERROR;
}
int iface_addr = net_get_address_in_subnet(address);
/* No ping to unsupported network or own address */
if (iface_addr == 0 || iface_addr == address) {
return CMD_ERROR;
}
/* If broadcast destination address, limit TTL to one hop */
if (address == NETWORK_ADDR_BC(address)) {
if (!bc) {
puts("Do you want to ping broadcast? Then -b");
return CMD_ERROR;
}
ttl = 1;
ping_bc_mode = true;
}
/* Try to malloc duplicate detection buffer */
dups = (bool *) malloc(count * sizeof(bool));
if (dups == NULL) {
puts("Not enough system memory to fulfill your request!");
return CMD_ERROR;
}
net_addrtostr(address, adrbuf, sizeof(adrbuf));
printf("PING %s %lu bytes of data.\n", adrbuf, sizeof(mms_ping_message_t));
mms_ping_packets = 0;
mms_ping_dups = 0;
mms_ping_last_proc_id = (rand() % 255) + 1;
rtt_min = 0xffffffff;
rtt_max = 0x00000000;
rtt_avg = 0x00000000;
mms_ping_pid = fk_thread->pid;
long ts_start = (uint32_t)clock_get_systemtime();
for (i = 1; i <= count; i++) {
/* No duplicate for this sequence number possible */
dups[i - 1] = false;
/* Send ping echo request to destination */
mms_ping(address, i, prio, ttl);
/* Set timeout for next ping echo request packet to ::timeout seconds */
utimer_set_wpid(&mms_ping_utimer, timeout, mms_ping_pid, NULL);
/* Wait for ping echo reply or timeout */
msg_receive(&m);
/* Remove user timer because maybe woken up by ping response */
utimer_remove(&mms_ping_utimer);
}
ts_start = (uint32_t)clock_get_systemtime() - ts_start;
printf("--- %s ping statistics ---\n", adrbuf);
if (mms_ping_dups == 0) {
printf("%u packets transmitted, %u received, %u%% packet loss, time %lu ms\n", count,
mms_ping_packets, ((count - mms_ping_packets) * 100) / count, ts_start);
}
else {
printf("%u packets transmitted, %u received, +%i duplicates, %u%% packet loss, time %lu ms\n", count,
mms_ping_packets, mms_ping_dups, ((count - mms_ping_packets) * 100) / count, ts_start);
}
if (mms_ping_packets > 0) {
printf("rtt min/avg/max = %.2f/%.2f/%.2f ms\n", rtt_min, rtt_avg / (mms_ping_packets + mms_ping_dups), rtt_max);
}
if (!ping_bc_mode && mms_ping_packets == count) {
/* Calculate approximate throughput */
printf("--- %s throughput statistics ---\n", adrbuf);
float bw = (count * (8 + 4 + 62 + 2) * 1000) / (float)ts_start; /* for CC1100 */
printf("approximate throughput (air): %.2f byte/sec\n", 2 * bw);
bw = (count * 58 * 1000) / (float)ts_start; /* for CC1100 */
printf("approximate throughput (dll): %.2f byte/sec\n", 2 * bw);
bw = (count * NET_MESSAGE_PAYLOAD_LENGTH * 1000) / (float)ts_start;
printf("approximate throughput (net): %.2f byte/sec\n", 2 * bw);
bw = (count * UDPL_MESSAGE_LENGTH * 1000) / (float)ts_start;
printf("approximate throughput (trans/UDPL): %.2f byte/sec\n", 2 * bw);
bw = (count * TCPL_MESSAGE_LENGTH * 1000) / (float)ts_start;
printf("approximate throughput (trans/TCPL): %.2f byte/sec\n", bw);
}
/* Ping is over, clear random ping process id and buffer */
mms_ping_last_proc_id = 0;
free(dups);
return CMD_SUCCESS;
}
return CMD_ERROR;
}
ASCCMD(ssh, CMDFLAG_SERIAL, "Usage: ssh [-q] destination");
CMD_FUNCTION(ssh, cmdargs)
{
if (cmdargs->arg_size > 0) {
bool quit = false;
const char *msg = cmdargs->args;
while (*msg == ' ') {
msg++;
}
if (*msg == '-' && (*(msg + 1) == 'Q' || *(msg + 1) == 'q')) {
quit = true;
msg++;
msg++;
}
uint16_t address = net_strtoaddr((char *)msg, (char **)&msg);
if (address == 0) {
return CMD_ERROR;
}
int iface_addr = net_get_address_in_subnet(address);
/* No ssh to unsupported network or own address */
if (iface_addr == 0 || iface_addr == address) {
return CMD_ERROR;
}
/* If broadcast destination address, also exit here */
if (address == NETWORK_ADDR_BC(address)) {
return CMD_ERROR;
}
if (!quit) {
mms_ssh_connect(address);
}
else {
mms_ssh_close(address);
}
return CMD_SUCCESS;
}
return CMD_ERROR;
}
//#endif
/*---------------------------------------------------------------------------*/
// Ping message handler and send function
/*---------------------------------------------------------------------------*/
static void mms_ping_handler(void *message, int message_size,
packet_info_t *packet_info)
{
mms_ping_message_t *ping = (mms_ping_message_t *)message;
if (ping->type == MMS_PING_ECHO_REQUEST) {
ping->type = MMS_PING_ECHO_REPLY;
net_send((void *)ping, sizeof(mms_ping_message_t), packet_info->source,
LAYER_2_PROTOCOL_PING, packet_info->tos, 10);
}
else if (ping->type == MMS_PING_ECHO_REPLY) {
if (ping->identifier == mms_ping_last_proc_id) {
msg m;
bool wasDup = false;
char *msgDup;
char buf[10];
if (dups[ping->seq_num - 1]) {
wasDup = true;
mms_ping_dups++;
msgDup = "(DUP!)";
}
else {
mms_ping_packets++;
dups[ping->seq_num - 1] = true;
msgDup = "";
}
if (!ping_bc_mode && !wasDup) {
utimer_remove(&mms_ping_utimer); /* Stop timeout timer */
}
float ms = ((uint32_t)clock_get_systemtime() - ping->timestamp);
if (ms < rtt_min) {
rtt_min = ms;
}
if (ms > rtt_max) {
rtt_max = ms;
}
rtt_avg += ms;
if (!ping_silent_mode) {
net_addrtostr(packet_info->source, buf, sizeof(buf));
printf("%lu bytes from %s: seq=%u ttl=%u time=%.2f ms %s\n",
sizeof(mms_ping_message_t), buf,
ping->seq_num, *packet_info->ttl_ptr, ms, msgDup);
}
if (!ping_bc_mode && !wasDup) {
msg_send(&m, mms_ping_pid, false);
}
}
}
}
static void mms_ping(uint16_t destination, uint8_t seq, uint8_t prio, int ttl)
{
mms_ping_message_t ping_request;
ping_request.type = MMS_PING_ECHO_REQUEST;
ping_request.identifier = 0;
ping_request.identifier = mms_ping_last_proc_id;
ping_request.seq_num = seq;
ping_request.timestamp = (uint32_t)clock_get_systemtime();
net_send((void *)&ping_request, sizeof(mms_ping_message_t),
destination, LAYER_2_PROTOCOL_PING, prio, ttl);
}
/*---------------------------------------------------------------------------*/
// SSH message handler and send functions
/*---------------------------------------------------------------------------*/
static void mms_ssh_connect(uint16_t destination)
{
mms_ssh_message_t ssh;
ssh.type = MMS_SSH_CON_REQUEST;
mms_send((void *)&ssh, sizeof(mms_ssh_message_t), destination,
LAYER_3_PROTOCOL_SSH, PRIORITY_DATA);
}
static void mms_ssh_reply_connect(uint16_t destination, int socket, bool accept)
{
mms_ssh_message_t ssh;
ssh.type = accept ? MMS_SSH_CON_ACCEPT : MMS_SSH_CON_REJECT;
trans_sendto(socket, (void *)&ssh, sizeof(mms_ssh_message_t),
LAYER_3_PROTOCOL_SSH, PRIORITY_DATA, destination);
}
static void mms_ssh_close(uint16_t destination)
{
mms_ssh_message_t ssh;
ssh.type = MMS_SSH_CON_CLOSE;
mms_send((void *)&ssh, sizeof(mms_ssh_message_t), destination,
LAYER_3_PROTOCOL_SSH, PRIORITY_DATA);
}
static void mms_ssh_handler(void *message, int message_size,
packet_info_t *packet_info)
{
char adrbuf[10];
mms_ssh_message_t *ssh = (mms_ssh_message_t *)message;
if (ssh->type == MMS_SSH_CON_REQUEST) {
if (ssh_socket > -1) {
mms_ssh_reply_connect(packet_info->source, -1, false);
return;
}
ssh_socket = trans_socket(SOCK_TCPL);
if (ssh_socket < 0) {
mms_ssh_reply_connect(packet_info->source, -1, false);
return;
}
trans_connect(ssh_socket, packet_info->source);
mms_ssh_reply_connect(packet_info->source, ssh_socket, true);
}
else if (ssh->type == MMS_SSH_CON_ACCEPT) {
net_addrtostr(packet_info->source, adrbuf, sizeof(adrbuf));
printf("SSH connection accepted by %s\n", adrbuf);
}
else if (ssh->type == MMS_SSH_CON_REJECT) {
net_addrtostr(packet_info->source, adrbuf, sizeof(adrbuf));
printf("SSH connection rejected by %s\n", adrbuf);
}
else if (ssh->type == MMS_SSH_CON_CLOSE) {
if (ssh_socket > -1) {
uint16_t peer;
trans_getpeername(ssh_socket, &peer);
if (peer == packet_info->source) {
if (trans_close(ssh_socket, CLOSE_IMMEDIATE) == 1) {
ssh_socket = -1;
}
}
}
}
else if (ssh->type == MMS_SSH_DATA) {
mms_ssh_data_message_t *ssh_data = (mms_ssh_data_message_t *)message;
printf((char *)ssh_data->data);
fflush(stderr);
}
}
void mms_net_printf(const char *format)
{
if (ssh_socket > -1) {
mms_ssh_data_message_t ssh_data;
ssh_data.type = MMS_SSH_DATA;
int i = 0;
int len = strlen(format);
while (i < len) {
int chunk = len - i > (MMS_SSH_DATA_MAX - 1) ? (MMS_SSH_DATA_MAX - 1) : len - i;
memset(ssh_data.data, 0, sizeof(ssh_data.data));
memcpy(ssh_data.data, format + i, chunk);
if (trans_send(ssh_socket, (void *)&ssh_data, sizeof(mms_ssh_data_message_t),
LAYER_3_PROTOCOL_SSH, PRIORITY_DATA) < 0) {
break;
}
i += chunk;
}
}
else {
printf(format);
}
}
/*---------------------------------------------------------------------------*/
// Micro Mesh Stack API
/*---------------------------------------------------------------------------*/
void mms_init(void)
{
mms_initp(LAYER_2_PROTOCOL_MMR, &r_iface);
}
void mms_initp(protocol_t rp, route_interface_t *ri)
{
/* Initialize routing & network layer */
mmr_init();
net_init(ri);
/* Initialize transport layer */
trans_init();
/* Add routing as protocol handler for given route messages */
net_set_protocol_handler(rp, ri->receive);
/* Add transport as protocol handler for UDPL and TCPL messages */
net_set_protocol_handler(LAYER_2_PROTOCOL_UDPL, trans_receive_udpl);
net_set_protocol_handler(LAYER_2_PROTOCOL_TCPL, trans_receive_tcpl);
/* Add MMS ping handler */
net_set_protocol_handler(LAYER_2_PROTOCOL_PING, mms_ping_handler);
/* Add SSH handler */
trans_set_protocol_handler(LAYER_3_PROTOCOL_SSH, mms_ssh_handler);
}
/*---------------------------------------------------------------------------*/
int mms_add_interface(const char *name, uint16_t addr, const radio_t *radio)
{
return net_add_interface(name, addr, radio);
}
/*---------------------------------------------------------------------------*/
uint16_t mms_get_interface_address(int interface_id)
{
return net_get_interface_address(interface_id);
}
/*---------------------------------------------------------------------------*/
bool mms_set_interface_address(int interface_id, uint16_t addr)
{
return net_set_interface_address(interface_id, addr);
}
/*---------------------------------------------------------------------------*/
bool mms_set_output_power(int interface_id, uint8_t pa_idx)
{
return net_set_output_power(interface_id, pa_idx);
}
/*---------------------------------------------------------------------------*/
int mms_set_protocol_handler(protocol_t protocol, packet_handler_t handler)
{
return trans_set_protocol_handler(protocol, handler);
}
/*---------------------------------------------------------------------------*/
void mms_receive(void *msg, int msg_size, packet_info_t *packet_info)
{
net_receive(msg, msg_size, packet_info);
}
/*---------------------------------------------------------------------------*/
int mms_socket(int type)
{
return trans_socket(type);
}
/*---------------------------------------------------------------------------*/
int mms_connect(int socket, uint16_t dest_addr)
{
return trans_connect(socket, dest_addr);
}
/*---------------------------------------------------------------------------*/
int mms_sock_send(int socket, void *buffer, int length, protocol_t protocol,
uint8_t priority)
{
return trans_send(socket, buffer, length, protocol, priority);
}
/*---------------------------------------------------------------------------*/
int mms_sock_sendto(int socket, void *buffer, int length, protocol_t protocol,
uint8_t priority, uint16_t dest_addr)
{
return trans_sendto(socket, buffer, length, protocol, priority, dest_addr);
}
/*---------------------------------------------------------------------------*/
int mms_send(void *msg, int msg_len, uint16_t dst, protocol_t protocol,
uint8_t priority)
{
return trans_sendto(-1, msg, msg_len, protocol, priority, dst);
}
/*---------------------------------------------------------------------------*/
int mms_poll(int socket)
{
return trans_poll(socket);
}
/*---------------------------------------------------------------------------*/
int mms_close(int socket, int how)
{
return trans_close(socket, how);
}
/*---------------------------------------------------------------------------*/
void mms_flush_routes(bool flush_static)
{
rt_flush_routes(flush_static);
}
/*---------------------------------------------------------------------------*/
void mms_print_routes(void)
{
rt_print_routes();
}
/*---------------------------------------------------------------------------*/
void mms_print_ifconfig(int iface)
{
net_print_ifconfig(iface);
}
/*---------------------------------------------------------------------------*/
void mms_print_stats(void)
{
net_print_stats();
printf("\r\n");
r_iface.print_stats();
}

View File

@ -1,214 +0,0 @@
/******************************************************************************
Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved.
These sources were developed at the Freie Universitaet Berlin, Computer Systems
and Telematics group (http://cst.mi.fu-berlin.de).
-------------------------------------------------------------------------------
This file is part of RIOT.
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
RIOT is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see http://www.gnu.org/licenses/ .
--------------------------------------------------------------------------------
For further information and questions please use the web site
http://scatterweb.mi.fu-berlin.de
and the mailinglist (subscription via web site)
scatterweb@lists.spline.inf.fu-berlin.de
*******************************************************************************/
#ifndef MMSTACK_H_
#define MMSTACK_H_
/**
* @defgroup net_mmstack Micro Mesh Stack
* @ingroup net
*
* @{
*/
/**
* @file
* @brief
*
* @author Freie Universität Berlin, Computer Systems & Telematics
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de>
* @version $Revision: 3854 $
*
* @note $Id: mmstack.h 3854 2011-12-06 15:27:01Z hwill $
*/
#include "radio.h"
#include "net-types.h"
/**
* @brief Initialize micro mesh stack.
*/
void mms_init(void);
/**
* @brief Initialize micro mesh stack.
*
* @param rp Routing protocol type identifier.
* @param ri Pointer to route interface.
*/
void mms_initp(protocol_t rp, route_interface_t *ri);
/**
* @brief Add network interface.
*
* @param name Network layer name on this interface (maximum 5 characters).
* @param addr Network layer address on this interface.
* @param radio Radio layer API access.
*
* @return Interface identifier or -1 if an error occurs.
*/
int mms_add_interface(const char *name, uint16_t addr, const radio_t *radio);
/**
* @brief Get the address of the network interface with given id.
*
* @param interface_id The network interface id.
*
* @return The address of the network interface with given id
* or 0 if no interface with given id is found.
*/
uint16_t mms_get_interface_address(int interface_id);
/**
* @brief Set the address of the network interface with the given id.
*
* @param interface_id The network interface id.
* @param addr The new address to set.
*
* @return true if address was successfully set; false otherwise (e.g.
* wrong interface, invalid address etc.)
*/
bool mms_set_interface_address(int interface_id, uint16_t addr);
/**
* @brief Set the output power of the radio device on the network
* interface with the given id.
*
* @param interface_id The network interface id.
* @param pa_idx Output power value from 0 (lowest output power) to
* X (highest output power).
*
* @return true if output power was successfully set; false otherwise
* (e.g. wrong interface, invalid output power value etc.)
*/
bool mms_set_output_power(int interface_id, uint8_t pa_idx);
/**
* @brief Set a protocol handler for a given protocol.
*
* @param protocol The protocol identifier (must be unique).
* @param handler The packet handler called if a packet of given protocol is received.
*
* @return -1 if an error occurs (e.g. handler table full) else >= 0.
*/
int mms_set_protocol_handler(protocol_t protocol, packet_handler_t handler);
/**
* @see ::trans_socket(int)
*/
int mms_socket(int type);
/**
* @see ::trans_connect(int,uint16_t)
*/
int mms_connect(int socket, uint16_t dest_addr);
/**
* @see ::trans_send(int,void*,int,protocol_t,uint8_t)
*/
int mms_sock_send(int socket, void *buffer, int length, protocol_t protocol,
uint8_t priority);
/**
* @see ::trans_sendto(int,void*,int,protocol_t,uint8_t,uint16_t)
*/
int mms_sock_sendto(int socket, void *buffer, int length, protocol_t protocol,
uint8_t priority, uint16_t dest_addr);
/**
* @brief Convenience function to send a message via UDPL socket.
*
* @param msg packet payload
* @param msg_len the size of the packet payload in bytes (max. 46 bytes).
* @param dst packet destination address
* @param protocol packet protocol identifier
* @param priority packet priority
*
* @return Upon successful completion, mms_send() returns a value greater zero.
* Otherwise, a negative value is returned to indicate the error.
*/
int mms_send(void *msg, int msg_len, uint16_t dst, protocol_t protocol,
uint8_t priority);
/**
* @see ::trans_poll(int)
*/
int mms_poll(int socket);
/**
* @see ::trans_close(int,int)
*/
int mms_close(int socket, int how);
/**
* @brief Receive function for incoming packets.
*
* This function is the protocol handler function for micro mesh messages received
* on the lower layers.
*
* @param msg Incoming packet.
* @param msg_size Size of incoming packet.
* @param packet_info Additional packet information.
*/
void mms_receive(void *msg, int msg_size, packet_info_t *packet_info);
/**
* @brief Flush kernel route table.
*
* @param flush_static Whether to flush static routes also
*/
void mms_flush_routes(bool flush_static);
/**
* @brief Writes to the standard output (stdout) a sequence of data formatted as
* the format argument specifies.
*
* If a SSH connection is active, the output is redirected to the node who
* initialized the SSH connection.
*
* @param format String that contains the text to be written to stdout.
*/
void mms_net_printf(const char *format);
/**
* @brief Print kernel route table.
*/
void mms_print_routes(void);
/**
* @brief Print interface configuration.
*
* @param iface Optional interface parameter.
*/
void mms_print_ifconfig(int iface);
/**
* @brief Print Micro Mesh stack statistics.
*/
void mms_print_stats(void);
/** @} */
#endif /* MMSTACK_H_ */