

5 changed files with 387 additions and 0 deletions
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 sys_net_udp UDP |
||||
* @ingroup net |
||||
* @brief RIOT's implementation of the UDP protocol |
||||
* |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief UDP interface definition |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
*/ |
||||
|
||||
#ifndef NG_UDP_H_ |
||||
#define NG_UDP_H_ |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include "byteorder.h" |
||||
#include "net/ng_netbase.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Default message queue size for the UDP thread |
||||
*/ |
||||
#ifndef NG_UDP_MSG_QUEUE_SIZE |
||||
#define NG_UDP_MSG_QUEUE_SIZE (8U) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Priority of the pktdump thread |
||||
*/ |
||||
#ifndef NG_UDP_PRIO |
||||
#define NG_UDP_PRIO (PRIORITY_MAIN - 2) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Default stack size to use for the UDP thread |
||||
*/ |
||||
#ifndef NG_UDP_STACK_SIZE |
||||
#define NG_UDP_STACK_SIZE (KERNEL_CONF_STACKSIZE_DEFAULT) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief UDP header definition |
||||
*/ |
||||
typedef struct __attribute__((packed)) { |
||||
network_uint16_t src_port; /**< source port, in network byte order */ |
||||
network_uint16_t dst_port; /**< destination port, network byte order */ |
||||
network_uint16_t length; /**< payload length (including the header),
|
||||
* network byte order */ |
||||
network_uint16_t checksum; /**< checksum */ |
||||
} ng_udp_hdr_t; |
||||
|
||||
/**
|
||||
* @brief Calculate the checksum for the given packet |
||||
* |
||||
* @param[in] hdr Pointer to the UDP header |
||||
* @param[in] pseudo_hdr Pointer to the network layer header |
||||
* |
||||
* @return 0 on success |
||||
* @return -EBADMSG if @p pkt is not of type NG_NETTYPE_UDP |
||||
* @return -EFAULT if @p pkt or @p pseudo_hdr is NULL |
||||
* @return -ENOENT if @p pseudo_hdr_type is not known |
||||
*/ |
||||
int ng_udp_calc_csum(ng_pktsnip_t *hdr, ng_pktsnip_t *pseudo_hdr); |
||||
|
||||
/**
|
||||
* @brief Allocate and initialize a fresh UDP header in the packet buffer |
||||
* |
||||
* @param[in] payload Payload contained in the UDP packet |
||||
* @param[in] src Source port in host byte order |
||||
* @param[in] src_len Length of @p src, must be 2 |
||||
* @param[in] dst Destination port in host byte order |
||||
* @param[in] dst_len Length of @p dst, must be 2 |
||||
* |
||||
* @return pointer to the newly created (and allocated) header |
||||
* @return NULL on error |
||||
*/ |
||||
ng_pktsnip_t *ng_udp_hdr_build(ng_pktsnip_t *payload, |
||||
uint8_t *src, size_t src_len, |
||||
uint8_t *dst, size_t dst_len); |
||||
|
||||
/**
|
||||
* @brief Initialize and start UDP |
||||
* |
||||
* @return PID of the UDP thread |
||||
* @return negative value on error |
||||
*/ |
||||
int ng_udp_init(void); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* NG_UDP_H_ */ |
||||
/** @} */ |
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base |
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup net_ng_udp |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief UDP implementation |
||||
* |
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de> |
||||
* @} |
||||
*/ |
||||
|
||||
#include <stdint.h> |
||||
#include <errno.h> |
||||
|
||||
#include "kernel.h" |
||||
#include "byteorder.h" |
||||
#include "msg.h" |
||||
#include "thread.h" |
||||
#include "utlist.h" |
||||
#include "net/ng_udp.h" |
||||
#include "net/ng_netbase.h" |
||||
#include "net/ng_inet_csum.h" |
||||
|
||||
#ifdef MODULE_NG_IPV6 |
||||
#include "net/ng_ipv6/hdr.h" |
||||
#endif |
||||
|
||||
#define ENABLE_DEBUG (0) |
||||
#include "debug.h" |
||||
|
||||
/**
|
||||
* @brief Save the UDP's thread PID for later reference |
||||
*/ |
||||
static kernel_pid_t _pid = KERNEL_PID_UNDEF; |
||||
|
||||
/**
|
||||
* @brief Allocate memory for the UDP thread's stack |
||||
*/ |
||||
static char _stack[NG_UDP_STACK_SIZE]; |
||||
|
||||
/**
|
||||
* @brief Calculate the UDP checksum dependent on the network protocol |
||||
* |
||||
* @note If the checksum turns out to be 0x0000, the function returns 0xffff |
||||
* as specified in RFC768 |
||||
* |
||||
* @param[in] pkt pointer to the packet in the packet buffer |
||||
* @param[in] pseudo_hdr pointer to the network layer header |
||||
* @param[in] payload pointer to the payload |
||||
* |
||||
* @return the checksum of the pkt in host byte order |
||||
* @return 0 on error |
||||
*/ |
||||
static uint16_t _calc_csum(ng_pktsnip_t *hdr, ng_pktsnip_t *pseudo_hdr, |
||||
ng_pktsnip_t *payload) |
||||
{ |
||||
uint16_t csum = 0; |
||||
uint16_t len = (uint16_t)hdr->size; |
||||
|
||||
/* process the payload */ |
||||
while (payload && payload != hdr) { |
||||
csum = ng_inet_csum(csum, (uint8_t *)(payload->data), payload->size); |
||||
len += (uint16_t)payload->size; |
||||
payload = payload->next; |
||||
} |
||||
/* process applicable UDP header bytes */ |
||||
csum = ng_inet_csum(csum, (uint8_t *)hdr->data, 6); |
||||
|
||||
switch (pseudo_hdr->type) { |
||||
#ifdef MODULE_NG_IPV6 |
||||
case NG_NETTYPE_IPV6: |
||||
csum = ng_ipv6_hdr_inet_csum(csum, pseudo_hdr->data, |
||||
NG_PROTNUM_UDP, len); |
||||
break; |
||||
#endif |
||||
default: |
||||
(void)len; |
||||
return 0; |
||||
} |
||||
/* return inverted results */ |
||||
return ~csum; |
||||
} |
||||
|
||||
static void _receive(ng_pktsnip_t *pkt) |
||||
{ |
||||
ng_pktsnip_t *udp; |
||||
ng_udp_hdr_t *hdr; |
||||
uint16_t csum; |
||||
uint32_t port; |
||||
ng_netreg_entry_t *sendto; |
||||
|
||||
/* mark UDP header */ |
||||
udp = ng_pktbuf_start_write(pkt); |
||||
if (udp == NULL) { |
||||
DEBUG("udp: unable to get write access to packet\n"); |
||||
ng_pktbuf_release(pkt); |
||||
return; |
||||
} |
||||
pkt = udp; |
||||
udp = ng_pktbuf_add(pkt, pkt->data, sizeof(ng_udp_hdr_t), NG_NETTYPE_UDP); |
||||
if (udp == NULL) { |
||||
DEBUG("udp: error marking UDP header, dropping packet\n"); |
||||
ng_pktbuf_release(pkt); |
||||
return; |
||||
} |
||||
hdr = (ng_udp_hdr_t *)udp->data; |
||||
|
||||
/* validate checksum */ |
||||
csum = _calc_csum(udp, udp->next, pkt); /* TODO: what about extension headers? */ |
||||
if (byteorder_ntohs(hdr->checksum) != csum) { |
||||
DEBUG("udp: received packet with invalid checksum, dropping it\n"); |
||||
ng_pktbuf_release(pkt); |
||||
return; |
||||
} |
||||
|
||||
/* get port (netreg demux context) */ |
||||
port = (uint32_t)byteorder_ntohs(hdr->dst_port); |
||||
|
||||
/* send payload to receivers */ |
||||
sendto = ng_netreg_lookup(NG_NETTYPE_UDP, port); |
||||
if (sendto == NULL) { |
||||
DEBUG("udp: unable to forward packet as no one is interested in it\n"); |
||||
ng_pktbuf_release(pkt); |
||||
return; |
||||
} |
||||
ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_UDP, port) - 1); |
||||
while (sendto != NULL) { |
||||
ng_netapi_receive(sendto->pid, pkt); |
||||
sendto = ng_netreg_getnext(sendto); |
||||
} |
||||
} |
||||
|
||||
static void _send(ng_pktsnip_t *pkt) |
||||
{ |
||||
ng_udp_hdr_t *hdr; |
||||
ng_pktsnip_t *udp_snip; |
||||
ng_netreg_entry_t *sendto; |
||||
|
||||
/* get udp snip and hdr */ |
||||
LL_SEARCH_SCALAR(pkt, udp_snip, type, NG_NETTYPE_UDP); |
||||
udp_snip = ng_pktbuf_start_write(udp_snip); |
||||
if (udp_snip == NULL) { |
||||
DEBUG("udp: cannot send packet, no UDP header found\n"); |
||||
ng_pktbuf_release(pkt); |
||||
return; |
||||
} |
||||
hdr = (ng_udp_hdr_t *)udp_snip->data; |
||||
/* fill in size field */ |
||||
hdr->length = byteorder_htons(sizeof(ng_udp_hdr_t) + ng_pkt_len(udp_snip)); |
||||
|
||||
/* and forward packet to the network layer */ |
||||
sendto = ng_netreg_lookup(pkt->type, NG_NETREG_DEMUX_CTX_ALL); |
||||
/* throw away packet if no one is interested */ |
||||
if (sendto == NULL) { |
||||
DEBUG("udp: cannot send packet because network layer not found\n"); |
||||
ng_pktbuf_release(pkt); |
||||
return; |
||||
} |
||||
/* send packet to network layer */ |
||||
ng_pktbuf_hold(pkt, ng_netreg_num(pkt->type, NG_NETREG_DEMUX_CTX_ALL) - 1); |
||||
while (sendto != NULL) { |
||||
ng_netapi_send(sendto->pid, pkt); |
||||
sendto = ng_netreg_getnext(sendto); |
||||
} |
||||
} |
||||
|
||||
static void *_event_loop(void *arg) |
||||
{ |
||||
(void)arg; |
||||
msg_t msg, reply; |
||||
msg_t msg_queue[NG_UDP_MSG_QUEUE_SIZE]; |
||||
ng_netreg_entry_t netreg; |
||||
|
||||
/* preset reply message */ |
||||
reply.type = NG_NETAPI_MSG_TYPE_ACK; |
||||
reply.content.value = (uint32_t)-ENOTSUP; |
||||
/* initialize message queue */ |
||||
msg_init_queue(msg_queue, NG_UDP_MSG_QUEUE_SIZE); |
||||
/* register UPD at netreg */ |
||||
netreg.demux_ctx = NG_NETREG_DEMUX_CTX_ALL; |
||||
netreg.pid = thread_getpid(); |
||||
ng_netreg_register(NG_NETTYPE_UDP, &netreg); |
||||
|
||||
/* dispatch NETAPI messages */ |
||||
while (1) { |
||||
msg_receive(&msg); |
||||
switch (msg.type) { |
||||
case NG_NETAPI_MSG_TYPE_RCV: |
||||
DEBUG("udp: NG_NETAPI_MSG_TYPE_RCV\n"); |
||||
_receive((ng_pktsnip_t *)msg.content.ptr); |
||||
break; |
||||
case NG_NETAPI_MSG_TYPE_SND: |
||||
DEBUG("udp: NG_NETAPI_MSG_TYPE_SND\n"); |
||||
_send((ng_pktsnip_t *)msg.content.ptr); |
||||
break; |
||||
case NG_NETAPI_MSG_TYPE_SET: |
||||
case NG_NETAPI_MSG_TYPE_GET: |
||||
msg_reply(&msg, &reply); |
||||
break; |
||||
default: |
||||
DEBUG("udp: received unidentified message\n"); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/* never reached */ |
||||
return NULL; |
||||
} |
||||
|
||||
int ng_udp_calc_csum(ng_pktsnip_t *hdr, ng_pktsnip_t *pseudo_hdr) |
||||
{ |
||||
uint16_t csum; |
||||
|
||||
if (hdr == NULL || hdr->next == NULL) { |
||||
return -EFAULT; |
||||
} |
||||
if (hdr->type != NG_NETTYPE_UDP) { |
||||
return -EBADMSG; |
||||
} |
||||
|
||||
csum = _calc_csum(hdr, pseudo_hdr, hdr->next); |
||||
if (csum == 0) { |
||||
return -ENOENT; |
||||
} |
||||
((ng_udp_hdr_t *)hdr->data)->checksum = byteorder_htons(csum); |
||||
return 0; |
||||
} |
||||
|
||||
ng_pktsnip_t *ng_udp_hdr_build(ng_pktsnip_t *payload, |
||||
uint8_t *src, size_t src_len, |
||||
uint8_t *dst, size_t dst_len) { |
||||
ng_pktsnip_t *res; |
||||
ng_udp_hdr_t *hdr; |
||||
|
||||
/* check parameters */ |
||||
if (src == NULL || dst == NULL || |
||||
src_len != sizeof(uint16_t) || dst_len != sizeof(uint16_t)) { |
||||
return NULL; |
||||
} |
||||
/* allocate header */ |
||||
res = ng_pktbuf_add(payload, NULL, sizeof(ng_udp_hdr_t), NG_NETTYPE_UDP); |
||||
if (res == NULL) { |
||||
return NULL; |
||||
} |
||||
/* initialize header */ |
||||
hdr = (ng_udp_hdr_t *)res->data; |
||||
hdr->src_port = byteorder_htons(*((uint16_t *)src)); |
||||
hdr->dst_port = byteorder_htons(*((uint16_t *)dst)); |
||||
hdr->checksum = byteorder_htons(0); |
||||
return res; |
||||
} |
||||
|
||||
int ng_udp_init(void) |
||||
{ |
||||
/* check if thread is already running */ |
||||
if (_pid == KERNEL_PID_UNDEF) { |
||||
/* start UDP thread */ |
||||
_pid = thread_create(_stack, sizeof(_stack), NG_UDP_PRIO, 0, |
||||
_event_loop, NULL, "udp"); |
||||
} |
||||
return _pid; |
||||
} |
Loading…
Reference in new issue