2015-03-16 17:52:19 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @{
|
|
|
|
*
|
|
|
|
* @file
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kernel_types.h"
|
|
|
|
#include "net/ng_netbase.h"
|
|
|
|
#include "thread.h"
|
|
|
|
#include "utlist.h"
|
|
|
|
|
|
|
|
#include "net/ng_sixlowpan.h"
|
2015-04-08 11:56:10 +02:00
|
|
|
#include "net/ng_sixlowpan/frag.h"
|
2015-03-16 17:52:19 +01:00
|
|
|
#include "net/ng_sixlowpan/netif.h"
|
|
|
|
|
|
|
|
#define ENABLE_DEBUG (0)
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
static kernel_pid_t _pid = KERNEL_PID_UNDEF;
|
|
|
|
static char _stack[NG_SIXLOWPAN_STACK_SIZE];
|
|
|
|
|
|
|
|
/* handles NG_NETAPI_MSG_TYPE_RCV commands */
|
|
|
|
void _receive(ng_pktsnip_t *pkt);
|
|
|
|
/* handles NG_NETAPI_MSG_TYPE_SND commands */
|
|
|
|
void _send(ng_pktsnip_t *pkt);
|
|
|
|
/* Main event loop for 6LoWPAN */
|
|
|
|
static void *_event_loop(void *args);
|
|
|
|
|
|
|
|
kernel_pid_t ng_sixlowpan_init(void)
|
|
|
|
{
|
|
|
|
if (_pid > KERNEL_PID_UNDEF) {
|
|
|
|
return _pid;
|
|
|
|
}
|
|
|
|
|
2015-05-09 20:48:53 +02:00
|
|
|
_pid = thread_create(_stack, sizeof(_stack), NG_SIXLOWPAN_PRIO,
|
2015-03-16 17:52:19 +01:00
|
|
|
CREATE_STACKTEST, _event_loop, NULL, "6lo");
|
|
|
|
|
|
|
|
return _pid;
|
|
|
|
}
|
|
|
|
|
|
|
|
void _receive(ng_pktsnip_t *pkt)
|
|
|
|
{
|
|
|
|
ng_pktsnip_t *payload;
|
|
|
|
uint8_t *dispatch;
|
|
|
|
ng_netreg_entry_t *entry;
|
|
|
|
|
|
|
|
LL_SEARCH_SCALAR(pkt, payload, type, NG_NETTYPE_SIXLOWPAN);
|
|
|
|
|
|
|
|
if ((payload == NULL) || (payload->size < 1)) {
|
|
|
|
DEBUG("6lo: Received packet has no 6LoWPAN payload\n");
|
|
|
|
ng_pktbuf_release(pkt);
|
|
|
|
}
|
|
|
|
|
|
|
|
dispatch = payload->data;
|
|
|
|
|
|
|
|
if (dispatch[0] == NG_SIXLOWPAN_UNCOMPRESSED) {
|
|
|
|
ng_pktsnip_t *sixlowpan;
|
|
|
|
DEBUG("6lo: received uncompressed IPv6 packet\n");
|
|
|
|
payload = ng_pktbuf_start_write(payload);
|
|
|
|
|
|
|
|
if (payload == NULL) {
|
|
|
|
DEBUG("6lo: can not get write access on received packet\n");
|
|
|
|
#if defined(DEVELHELP) && defined(ENABLE_DEBUG)
|
|
|
|
ng_pktbuf_stats();
|
|
|
|
#endif
|
|
|
|
ng_pktbuf_release(pkt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* packet is uncompressed: just mark and remove the dispatch */
|
|
|
|
sixlowpan = ng_pktbuf_add(payload, payload->data, sizeof(uint8_t),
|
|
|
|
NG_NETTYPE_SIXLOWPAN);
|
2015-04-28 14:51:06 +02:00
|
|
|
|
|
|
|
if (sixlowpan == NULL) {
|
|
|
|
DEBUG("6lo: can not mark 6LoWPAN dispatch\n");
|
|
|
|
ng_pktbuf_release(pkt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pkt = ng_pktbuf_remove_snip(pkt, sixlowpan);
|
2015-03-16 17:52:19 +01:00
|
|
|
}
|
2015-04-08 11:56:10 +02:00
|
|
|
#ifdef MODULE_NG_SIXLOWPAN_FRAG
|
|
|
|
else if (ng_sixlowpan_frag_is((ng_sixlowpan_frag_t *)dispatch)) {
|
|
|
|
DEBUG("6lo: received 6LoWPAN fragment\n");
|
|
|
|
ng_sixlowpan_frag_handle_pkt(pkt);
|
2015-04-28 13:44:20 +02:00
|
|
|
return;
|
2015-04-08 11:56:10 +02:00
|
|
|
}
|
|
|
|
#endif
|
2015-03-16 17:52:19 +01:00
|
|
|
else {
|
|
|
|
DEBUG("6lo: dispatch %02x ... is not supported\n",
|
|
|
|
dispatch[0]);
|
|
|
|
ng_pktbuf_release(pkt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
payload->type = NG_NETTYPE_IPV6;
|
|
|
|
|
|
|
|
entry = ng_netreg_lookup(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL);
|
|
|
|
|
|
|
|
if (entry == NULL) {
|
|
|
|
DEBUG("ipv6: No receivers for this packet found\n");
|
|
|
|
ng_pktbuf_release(pkt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL) - 1);
|
|
|
|
|
|
|
|
while (entry) {
|
|
|
|
DEBUG("6lo: Send receive command for %p to %" PRIu16 "\n",
|
|
|
|
(void *)pkt, entry->pid);
|
|
|
|
ng_netapi_receive(entry->pid, pkt);
|
|
|
|
entry = ng_netreg_getnext(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void _send(ng_pktsnip_t *pkt)
|
|
|
|
{
|
|
|
|
ng_netif_hdr_t *hdr;
|
|
|
|
ng_pktsnip_t *ipv6, *sixlowpan;
|
|
|
|
ng_sixlowpan_netif_t *iface;
|
|
|
|
/* cppcheck: datagram_size will be read by frag */
|
|
|
|
/* cppcheck-suppress unreadVariable */
|
|
|
|
size_t payload_len, datagram_size;
|
|
|
|
uint16_t max_frag_size;
|
|
|
|
uint8_t *disp;
|
|
|
|
|
|
|
|
if ((pkt == NULL) || (pkt->size < sizeof(ng_netif_hdr_t))) {
|
|
|
|
DEBUG("6lo: Sending packet has no netif header\n");
|
|
|
|
ng_pktbuf_release(pkt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
hdr = pkt->data;
|
|
|
|
ipv6 = pkt->next;
|
|
|
|
|
|
|
|
if ((ipv6 == NULL) || (ipv6->type != NG_NETTYPE_IPV6)) {
|
|
|
|
DEBUG("6lo: Sending packet has no IPv6 header\n");
|
|
|
|
ng_pktbuf_release(pkt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* payload length and datagram size are different in that the payload
|
|
|
|
* length is the length of the IPv6 datagram + 6LoWPAN dispatches,
|
|
|
|
* while the datagram size is the size of only the IPv6 datagram */
|
|
|
|
payload_len = ng_pkt_len(ipv6);
|
|
|
|
datagram_size = (uint16_t)payload_len;
|
|
|
|
|
|
|
|
/* use sixlowpan packet snip as temporary one */
|
|
|
|
sixlowpan = ng_pktbuf_start_write(pkt);
|
|
|
|
|
|
|
|
if (sixlowpan == NULL) {
|
|
|
|
DEBUG("6lo: no space left in packet buffer\n");
|
|
|
|
ng_pktbuf_release(pkt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pkt = sixlowpan;
|
|
|
|
|
|
|
|
DEBUG("6lo: Send uncompressed\n");
|
|
|
|
|
|
|
|
sixlowpan = ng_pktbuf_add(NULL, NULL, sizeof(uint8_t), NG_NETTYPE_SIXLOWPAN);
|
|
|
|
|
|
|
|
if (sixlowpan == NULL) {
|
|
|
|
DEBUG("6lo: no space left in packet buffer\n");
|
|
|
|
ng_pktbuf_release(pkt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sixlowpan->next = ipv6;
|
|
|
|
pkt->next = sixlowpan;
|
|
|
|
disp = sixlowpan->data;
|
|
|
|
disp[0] = NG_SIXLOWPAN_UNCOMPRESSED;
|
|
|
|
payload_len++;
|
|
|
|
|
|
|
|
iface = ng_sixlowpan_netif_get(hdr->if_pid);
|
|
|
|
|
|
|
|
if (iface == NULL) {
|
|
|
|
if (ng_netapi_get(hdr->if_pid, NETCONF_OPT_MAX_PACKET_SIZE,
|
|
|
|
0, &max_frag_size, sizeof(max_frag_size)) < 0) {
|
|
|
|
/* if error we assume it works */
|
|
|
|
DEBUG("6lo: can not get max packet size from interface %"
|
|
|
|
PRIkernel_pid "\n", hdr->if_pid);
|
|
|
|
max_frag_size = UINT16_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
ng_sixlowpan_netif_add(hdr->if_pid, max_frag_size);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
max_frag_size = iface->max_frag_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG("6lo: max_frag_size = %" PRIu16 " for interface %"
|
|
|
|
PRIkernel_pid "\n", max_frag_size, hdr->if_pid);
|
|
|
|
|
|
|
|
/* IP should not send anything here if it is not a 6LoWPAN interface,
|
|
|
|
* so we don't need to check for NULL pointers */
|
|
|
|
if (payload_len <= max_frag_size) {
|
|
|
|
DEBUG("6lo: Send SND command for %p to %" PRIu16 "\n",
|
|
|
|
(void *)pkt, hdr->if_pid);
|
|
|
|
ng_netapi_send(hdr->if_pid, pkt);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2015-04-08 11:56:10 +02:00
|
|
|
#ifdef MODULE_NG_SIXLOWPAN_FRAG
|
|
|
|
else {
|
|
|
|
DEBUG("6lo: Send fragmented (%u > %" PRIu16 ")\n",
|
|
|
|
(unsigned int)payload_len, max_frag_size);
|
|
|
|
ng_sixlowpan_frag_send(hdr->if_pid, pkt, payload_len, datagram_size);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
(void)datagram_size;
|
2015-03-16 17:52:19 +01:00
|
|
|
DEBUG("6lo: packet too big (%u> %" PRIu16 ")\n",
|
|
|
|
(unsigned int)payload_len, max_frag_size);
|
2015-04-08 11:56:10 +02:00
|
|
|
#endif
|
2015-03-16 17:52:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void *_event_loop(void *args)
|
|
|
|
{
|
|
|
|
msg_t msg, reply, msg_q[NG_SIXLOWPAN_MSG_QUEUE_SIZE];
|
|
|
|
ng_netreg_entry_t me_reg;
|
|
|
|
|
|
|
|
(void)args;
|
|
|
|
msg_init_queue(msg_q, NG_SIXLOWPAN_MSG_QUEUE_SIZE);
|
|
|
|
|
|
|
|
me_reg.demux_ctx = NG_NETREG_DEMUX_CTX_ALL;
|
|
|
|
me_reg.pid = thread_getpid();
|
|
|
|
|
|
|
|
/* register interest in all 6LoWPAN packets */
|
|
|
|
ng_netreg_register(NG_NETTYPE_SIXLOWPAN, &me_reg);
|
|
|
|
|
|
|
|
/* preinitialize ACK */
|
|
|
|
reply.type = NG_NETAPI_MSG_TYPE_ACK;
|
|
|
|
|
|
|
|
/* start event loop */
|
|
|
|
while (1) {
|
|
|
|
DEBUG("6lo: waiting for incoming message.\n");
|
|
|
|
msg_receive(&msg);
|
|
|
|
|
|
|
|
switch (msg.type) {
|
|
|
|
case NG_NETAPI_MSG_TYPE_RCV:
|
|
|
|
DEBUG("6lo: NG_NETDEV_MSG_TYPE_RCV received\n");
|
|
|
|
_receive((ng_pktsnip_t *)msg.content.ptr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NG_NETAPI_MSG_TYPE_SND:
|
|
|
|
DEBUG("6lo: NG_NETDEV_MSG_TYPE_SND received\n");
|
|
|
|
_send((ng_pktsnip_t *)msg.content.ptr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NG_NETAPI_MSG_TYPE_GET:
|
|
|
|
case NG_NETAPI_MSG_TYPE_SET:
|
|
|
|
DEBUG("6lo: reply to unsupported get/set\n");
|
|
|
|
reply.content.value = -ENOTSUP;
|
|
|
|
msg_reply(&msg, &reply);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
DEBUG("6lo: operation not supported\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @} */
|