1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 04:52:59 +01:00

net: added NG_UDP implementation

This commit is contained in:
haukepetersen 2015-04-24 15:06:14 +02:00 committed by Hauke Petersen
parent 8921a370dc
commit b1d8752711
5 changed files with 387 additions and 0 deletions

View File

@ -91,6 +91,11 @@ ifneq (,$(filter ng_ipv6_netif,$(USEMODULE)))
USEMODULE += ng_netif
endif
ifneq (,$(filter ng_udp,$(USEMODULE)))
USEMODULE += ng_netbase
USEMODULE += ng_inet_csum
endif
ifneq (,$(filter ng_netbase,$(USEMODULE)))
USEMODULE += ng_netapi
USEMODULE += ng_netreg

View File

@ -125,6 +125,9 @@ endif
ifneq (,$(filter fib,$(USEMODULE)))
DIRS += net/network_layer/fib
endif
ifneq (,$(filter ng_udp,$(USEMODULE)))
DIRS += net/transport_layer/ng_udp
endif
DIRS += $(dir $(wildcard $(addsuffix /Makefile, ${USEMODULE})))

108
sys/include/net/ng_udp.h Normal file
View File

@ -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_ */
/** @} */

View File

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

View File

@ -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;
}