Browse Source

sys: net: Initial import of a basic MAC protocol layer

dev/timer
Martin Lenders 9 years ago committed by Martine Lenders
parent
commit
96502e2fd4
  1. 3
      sys/Makefile
  2. 3
      sys/Makefile.include
  3. 4
      sys/auto_init/Makefile
  4. 8
      sys/auto_init/auto_init.c
  5. 107
      sys/net/include/nomac.h
  6. 1
      sys/net/link_layer/nomac/Makefile
  7. 295
      sys/net/link_layer/nomac/nomac.c

3
sys/Makefile

@ -16,6 +16,9 @@ endif
ifneq (,$(filter l2_ping,$(USEMODULE)))
DIRS += net/link_layer/ping
endif
ifneq (,$(filter nomac,$(USEMODULE)))
DIRS += net/link_layer/nomac
endif
ifneq (,$(filter transport_layer,$(USEMODULE)))
USEMODULE += udp
USEMODULE += tcp

3
sys/Makefile.include

@ -1,3 +1,6 @@
ifneq (,$(filter nomac,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/include
endif
ifneq (,$(filter transport_layer,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/sys/net/include
endif

4
sys/auto_init/Makefile

@ -2,4 +2,8 @@ ifneq (,$(filter net_if,$(USEMODULE)))
INCLUDES += -I$(RIOTBASE)/sys/net/include/
endif
ifneq (,$(filter nomac,$(USEMODULE)))
INCLUDES += -I$(RIOTBASE)/sys/net/include/
endif
include $(RIOTBASE)/Makefile.base

8
sys/auto_init/auto_init.c

@ -67,6 +67,10 @@
#include "tcp.h"
#endif
#ifdef MODULE_NOMAC
#include "nomac.h"
#endif
#ifdef MODULE_NET_IF
#include "cpu-conf.h"
#include "cpu.h"
@ -241,6 +245,10 @@ void auto_init(void)
DEBUG("Auto init net_if module.\n");
l2_ping_init();
#endif
#ifdef MODULE_NOMAC
DEBUG("Auto init nomac module.\n");
nomac_init_module();
#endif
#ifdef MODULE_NET_IF
DEBUG("Auto init net_if module.\n");
auto_init_net_if();

107
sys/net/include/nomac.h

@ -0,0 +1,107 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup nomac Link layer with no medium access
* @ingroup net
* @brief Link layer protocol to speak with any transceiver driver
* directly without any medium access.
* @{
*
* @file
* @brief Link layer protocol to speak with any transceiver driver
* directly without any medium access.
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef __NOMAC_H_
#define __NOMAC_H_
#include <stdlib.h>
#include "netdev/base.h"
#include "netapi.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef NOMAC_REGISTRY_SIZE
/**
* @brief The size of NOMAC's registry of receiving threads.
*/
#define NOMAC_REGISTRY_SIZE (1)
#endif
/**
* @brief Recommended stack size for a NOMAC thread
* TODO: determine real minimal size based on thread_print_all() output
*/
#define NOMAC_CONTROL_STACKSIZE (KERNEL_CONF_STACKSIZE_DEFAULT)
/**
* @brief Basic configuration types
*
* @extends netapi_conf_type_t
*/
typedef enum {
NOMAC_PROTO = NETAPI_CONF_PROTO, /**< Set or get protocol */
NOMAC_CHANNEL = NETAPI_CONF_CARRIER, /**< Set or get channel */
NOMAC_ADDRESS = NETAPI_CONF_ADDRESS, /**< Set or get address */
NOMAC_NID = NETAPI_CONF_SUBNETS, /**< Set or get network id
* (e.g. PAN ID in 802.15.4)*/
NOMAC_MAX_PACKET_SIZE = NETAPI_CONF_MAX_PACKET_SIZE, /**< Set or get maximum
* packet size */
NOMAC_SRC_LEN = NETAPI_CONF_SRC_LEN, /**< Set or get default source length */
NOMAC_REGISTRY = NETAPI_CONF_REGISTRY, /**< get registered threads */
NOMAC_ADDRESS2 = NETDEV_OPT_ADDRESS_LONG, /**< Set or get alternative address
* format (e.g EUI-64 in 802.15.4) */
} nomac_conf_type_t;
/**
* @brief Initializes the module
*/
void nomac_init_module(void);
/**
* @brief Initialize new NOMAC layer.
*
* @param[in] stack Stack for the control thread
* @param[in] stacksize Size of *stack*
* @param[in] priority Priority for the control thread
* @param[in] name Name for the control thread
* @param[in] dev An *initialized* network device to use with this MAC
* layer
*
* @see @ref thread_create
*
* @return PID of NOMAC control thread on success
* @return -EINVAL if priority is invalid
* @return -EOVERFLOW if no slot for the new thread is available
*/
kernel_pid_t nomac_init(char *stack, int stacksize, char priority,
const char *name, netdev_t *dev);
#ifdef MODULE_NETDEV_DUMMY
/**
* @brief Re-updates the receive callback of a network device for testing
* purposes
*
* @param[in] dev A network device
*/
void nomac_update_callback(netdev_t *dev);
#endif
#ifdef __cplusplus
}
#endif
#endif /* __NOMAC_H_ */
/** @} */

1
sys/net/link_layer/nomac/Makefile

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

295
sys/net/link_layer/nomac/nomac.c

@ -0,0 +1,295 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include <errno.h>
#include <string.h>
#include "netapi.h"
#include "msg.h"
#include "netdev/base.h"
#include "thread.h"
#include "nomac.h"
#ifdef MODULE_NETDEV_DUMMY
#include "netdev_dummy.h"
#endif
#define ENABLE_DEBUG (0)
#include "debug.h"
#define NOMAC_MSG_QUEUE_SIZE (16)
static struct {
kernel_pid_t registrar_pid; /**< Thread recipient is registered to */
kernel_pid_t recipient_pid; /**< Registered recipient thread */
} _nomac_registry[NOMAC_REGISTRY_SIZE];
static int _nomac_recv_cb(netdev_t *dev, void *src, size_t src_len, void *dest,
size_t dest_len, void *payload, size_t payload_len)
{
(void)dev;
kernel_pid_t current_pid = thread_getpid();
size_t offset;
netapi_rcv_pkt_t packet;
netapi_ack_t ack_mem;
msg_t msg_pkt, msg_ack;
packet.type = NETAPI_CMD_RCV;
packet.ack = &ack_mem;
packet.src = src;
packet.src_len = src_len;
packet.dest = dest;
packet.dest_len = dest_len;
msg_pkt.type = NETAPI_MSG_TYPE;
msg_pkt.content.ptr = (char *)(&packet);
for (unsigned int i = 0; i < NOMAC_REGISTRY_SIZE; i++) {
if (_nomac_registry[i].registrar_pid == current_pid) {
offset = 0;
while (offset < payload_len) {
netapi_ack_t *ack;
packet.data = (void *)(((char *)payload) + offset);
packet.data_len = payload_len - offset;
msg_send_receive(&msg_pkt, &msg_ack,
_nomac_registry[i].recipient_pid);
ack = (netapi_ack_t *)(msg_ack.content.ptr);
if ((msg_ack.type == NETAPI_MSG_TYPE) &&
(ack->type == NETAPI_CMD_ACK) &&
(ack->orig == NETAPI_CMD_RCV)) {
if (ack->result > 0) {
offset += (ack->result);
}
else {
DEBUG("Error code received for registrar %" PRIkernel_pid
" with recipient %" PRIkernel_pid ": %d",
_nomac_registry[i].registrar_pid,
_nomac_registry[i].recipient_pid,
-(ack->result));
return ack->result;
}
}
else {
DEBUG("Unexpected msg instead of ACK. Abort for registrar "
"\"%s\" with recipient \"%s\": msg.type = %d, "
"ack->type = %d, ack->orig = %d",
thread_getname(_nomac_registry[i].registrar_pid),
thread_getname(_nomac_registry[i].recipient_pid),
msg_ack.type, ack->type, ack->orig);
return -ENOMSG;
}
}
}
}
return payload_len;
}
static inline int _nomac_send(netdev_t *dev, netapi_snd_pkt_t *pkt)
{
return dev->driver->send_data(dev, pkt->dest, pkt->dest_len, pkt->ulh,
pkt->data, pkt->data_len);
}
static int _nomac_get_registry(netapi_conf_t *conf)
{
kernel_pid_t current_pid = thread_getpid();
kernel_pid_t registry[NOMAC_REGISTRY_SIZE];
uint8_t size = 0;
for (int i = 0; i < NOMAC_REGISTRY_SIZE; i++) {
if ((size * sizeof(kernel_pid_t)) > (conf->data_len)) {
return -EOVERFLOW;
}
if (_nomac_registry[i].registrar_pid == current_pid) {
registry[size++] = _nomac_registry[i].recipient_pid;
}
}
conf->data_len = size * sizeof(kernel_pid_t);
memcpy(conf->data, registry, conf->data_len);
return 0;
}
static int _nomac_get_option(netdev_t *dev, netapi_conf_t *conf)
{
int res;
switch ((nomac_conf_type_t)conf->param) {
case NOMAC_PROTO:
case NOMAC_CHANNEL:
case NOMAC_ADDRESS:
case NOMAC_NID:
case NOMAC_MAX_PACKET_SIZE:
case NOMAC_ADDRESS2:
if ((res = dev->driver->get_option(dev, (netdev_opt_t)conf->param,
conf->data, &(conf->data_len))
) == 0) {
return (int)conf->data_len;
}
else {
return res;
}
case NOMAC_REGISTRY:
return _nomac_get_registry(conf);
default:
break;
}
return -ENOTSUP;
}
static int _nomac_set_option(netdev_t *dev, netapi_conf_t *conf)
{
switch ((nomac_conf_type_t)(conf->param)) {
case NOMAC_PROTO:
case NOMAC_CHANNEL:
case NOMAC_ADDRESS:
case NOMAC_NID:
case NOMAC_ADDRESS2:
return dev->driver->set_option(dev, (netdev_opt_t)conf->param,
conf->data, conf->data_len);
default:
break;
}
return -ENOTSUP;
}
static void *_nomac_runner(void *args)
{
netdev_t *dev = (netdev_t *)args;
msg_t msg_cmd, msg_ack, msg_queue[NOMAC_MSG_QUEUE_SIZE];
netapi_cmd_t *cmd;
netapi_ack_t *ack;
msg_ack.type = NETAPI_MSG_TYPE;
msg_init_queue(msg_queue, NOMAC_MSG_QUEUE_SIZE);
dev->driver->init(dev);
dev->driver->add_receive_data_callback(dev, _nomac_recv_cb);
while (1) {
msg_receive(&msg_cmd);
if (msg_cmd.type == NETDEV_MSG_EVENT_TYPE) {
dev->driver->event(dev, msg_cmd.content.value);
}
else if (msg_cmd.type == NETAPI_MSG_TYPE) {
cmd = (netapi_cmd_t *)(msg_cmd.content.ptr);
ack = cmd->ack;
msg_ack.content.ptr = (char *)ack;
switch (cmd->type) {
case NETAPI_CMD_SND:
ack->result = _nomac_send(dev, (netapi_snd_pkt_t *)cmd);
break;
case NETAPI_CMD_GET:
ack->result = _nomac_get_option(dev, (netapi_conf_t *)cmd);
break;
case NETAPI_CMD_SET:
ack->result = _nomac_set_option(dev, (netapi_conf_t *)cmd);
break;
case NETAPI_CMD_REG:
ack->result = -ENOBUFS;
for (int i = 0; i < NOMAC_REGISTRY_SIZE; i++) {
if (_nomac_registry[i].registrar_pid == KERNEL_PID_UNDEF) {
netapi_reg_t *reg = (netapi_reg_t *)cmd;
_nomac_registry[i].registrar_pid = thread_getpid();
_nomac_registry[i].recipient_pid = reg->reg_pid;
ack->result = NETAPI_STATUS_OK;
break;
}
}
break;
case NETAPI_CMD_UNREG:
ack->result = NETAPI_STATUS_OK;
for (int i = 0; i < NOMAC_REGISTRY_SIZE; i++) {
netapi_reg_t *reg = (netapi_reg_t *)cmd;
if (_nomac_registry[i].registrar_pid == thread_getpid() &&
_nomac_registry[i].recipient_pid == reg->reg_pid) {
_nomac_registry[i].recipient_pid = KERNEL_PID_UNDEF;
break;
}
}
break;
#ifdef MODULE_NETDEV_DUMMY
case NETAPI_CMD_FIRE_RCV:
ack->result = unittest_netdev_dummy_fire_rcv_event(dev,
((netapi_rcv_pkt_t *)cmd)->src,
((netapi_rcv_pkt_t *)cmd)->src_len,
((netapi_rcv_pkt_t *)cmd)->dest,
((netapi_rcv_pkt_t *)cmd)->dest_len,
((netapi_rcv_pkt_t *)cmd)->data,
((netapi_rcv_pkt_t *)cmd)->data_len);
break;
#endif
default:
ack->result = -ENOTSUP;
break;
}
ack->type = NETAPI_CMD_ACK;
ack->orig = cmd->type;
msg_reply(&msg_cmd, &msg_ack);
}
}
/* never reached */
return NULL;
}
void nomac_init_module(void)
{
for (int i = 0; i < NOMAC_REGISTRY_SIZE; i++) {
_nomac_registry[i].registrar_pid = KERNEL_PID_UNDEF;
_nomac_registry[i].recipient_pid = KERNEL_PID_UNDEF;
}
}
kernel_pid_t nomac_init(char *stack, int stacksize, char priority,
const char *name, netdev_t *dev)
{
return thread_create(stack, stacksize, priority, CREATE_STACKTEST,
_nomac_runner, (void *)dev, name);
}
#ifdef MODULE_NETDEV_DUMMY
void nomac_update_callback(netdev_t *dev)
{
dev->driver->add_receive_data_callback(dev, _nomac_recv_cb);
}
#endif
Loading…
Cancel
Save