2016-06-09 11:08:53 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2016 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
|
|
|
|
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <errno.h>
|
2020-01-17 17:06:09 +01:00
|
|
|
#include <stdlib.h>
|
2016-06-09 11:08:53 +02:00
|
|
|
|
2019-10-31 15:33:28 +01:00
|
|
|
#include "log.h"
|
2016-06-09 11:08:53 +02:00
|
|
|
#include "net/af.h"
|
|
|
|
#include "net/ipv6/hdr.h"
|
2018-09-28 13:02:31 +02:00
|
|
|
#include "net/gnrc/ipv6.h"
|
2016-06-09 11:08:53 +02:00
|
|
|
#include "net/gnrc/ipv6/hdr.h"
|
|
|
|
#include "net/gnrc/netreg.h"
|
|
|
|
#include "net/udp.h"
|
|
|
|
#include "utlist.h"
|
|
|
|
#include "xtimer.h"
|
|
|
|
|
|
|
|
#include "sock_types.h"
|
|
|
|
#include "gnrc_sock_internal.h"
|
|
|
|
|
2020-01-17 17:06:09 +01:00
|
|
|
#ifdef MODULE_FUZZING
|
|
|
|
extern gnrc_pktsnip_t *gnrc_pktbuf_fuzzptr;
|
|
|
|
#endif
|
|
|
|
|
2016-06-09 11:08:53 +02:00
|
|
|
#ifdef MODULE_XTIMER
|
|
|
|
#define _TIMEOUT_MAGIC (0xF38A0B63U)
|
|
|
|
#define _TIMEOUT_MSG_TYPE (0x8474)
|
|
|
|
|
|
|
|
static void _callback_put(void *arg)
|
|
|
|
{
|
|
|
|
msg_t timeout_msg = { .sender_pid = KERNEL_PID_UNDEF,
|
|
|
|
.type = _TIMEOUT_MSG_TYPE,
|
|
|
|
.content = { .value = _TIMEOUT_MAGIC } };
|
|
|
|
gnrc_sock_reg_t *reg = arg;
|
|
|
|
|
|
|
|
/* should be safe, because otherwise if mbox were filled this callback is
|
|
|
|
* senseless */
|
|
|
|
mbox_try_put(®->mbox, &timeout_msg);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-10-31 15:33:28 +01:00
|
|
|
#ifdef SOCK_HAS_ASYNC
|
|
|
|
static void _netapi_cb(uint16_t cmd, gnrc_pktsnip_t *pkt, void *ctx)
|
|
|
|
{
|
|
|
|
if (cmd == GNRC_NETAPI_MSG_TYPE_RCV) {
|
|
|
|
msg_t msg = { .type = GNRC_NETAPI_MSG_TYPE_RCV,
|
|
|
|
.content = { .ptr = pkt } };
|
|
|
|
gnrc_sock_reg_t *reg = ctx;
|
|
|
|
|
|
|
|
if (mbox_try_put(®->mbox, &msg) < 1) {
|
|
|
|
LOG_WARNING("gnrc_sock: dropped message to %p (was full)\n",
|
|
|
|
(void *)®->mbox);
|
2020-05-15 18:24:42 +02:00
|
|
|
/* packet could not be delivered so it should be dropped */
|
|
|
|
gnrc_pktbuf_release(pkt);
|
|
|
|
return;
|
2019-10-31 15:33:28 +01:00
|
|
|
}
|
|
|
|
if (reg->async_cb.generic) {
|
2020-03-11 12:22:10 +01:00
|
|
|
reg->async_cb.generic(reg, SOCK_ASYNC_MSG_RECV, reg->async_cb_arg);
|
2019-10-31 15:33:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* SOCK_HAS_ASYNC */
|
|
|
|
|
2016-06-09 11:08:53 +02:00
|
|
|
void gnrc_sock_create(gnrc_sock_reg_t *reg, gnrc_nettype_t type, uint32_t demux_ctx)
|
|
|
|
{
|
|
|
|
mbox_init(®->mbox, reg->mbox_queue, SOCK_MBOX_SIZE);
|
2019-10-31 15:33:28 +01:00
|
|
|
#ifdef SOCK_HAS_ASYNC
|
|
|
|
reg->async_cb.generic = NULL;
|
|
|
|
reg->netreg_cb.cb = _netapi_cb;
|
|
|
|
reg->netreg_cb.ctx = reg;
|
|
|
|
gnrc_netreg_entry_init_cb(®->entry, demux_ctx, ®->netreg_cb);
|
|
|
|
#else /* SOCK_HAS_ASYNC */
|
2016-06-09 11:08:53 +02:00
|
|
|
gnrc_netreg_entry_init_mbox(®->entry, demux_ctx, ®->mbox);
|
2019-10-31 15:33:28 +01:00
|
|
|
#endif /* SOCK_HAS_ASYNC */
|
2016-06-09 11:08:53 +02:00
|
|
|
gnrc_netreg_register(type, ®->entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt_out,
|
|
|
|
uint32_t timeout, sock_ip_ep_t *remote)
|
|
|
|
{
|
2018-09-28 13:02:31 +02:00
|
|
|
gnrc_pktsnip_t *pkt, *netif;
|
2016-06-09 11:08:53 +02:00
|
|
|
msg_t msg;
|
|
|
|
|
2020-01-17 17:06:09 +01:00
|
|
|
#ifdef MODULE_FUZZING
|
|
|
|
static gnrc_pktsnip_t *prevpkt;
|
|
|
|
if (prevpkt && prevpkt == gnrc_pktbuf_fuzzptr) {
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-06-12 13:53:11 +02:00
|
|
|
if (reg->mbox.cib.mask != (SOCK_MBOX_SIZE - 1)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2016-06-09 11:08:53 +02:00
|
|
|
#ifdef MODULE_XTIMER
|
|
|
|
xtimer_t timeout_timer;
|
|
|
|
|
|
|
|
if ((timeout != SOCK_NO_TIMEOUT) && (timeout != 0)) {
|
|
|
|
timeout_timer.callback = _callback_put;
|
|
|
|
timeout_timer.arg = reg;
|
|
|
|
xtimer_set(&timeout_timer, timeout);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (timeout != 0) {
|
|
|
|
mbox_get(®->mbox, &msg);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (!mbox_try_get(®->mbox, &msg)) {
|
|
|
|
return -EAGAIN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef MODULE_XTIMER
|
|
|
|
xtimer_remove(&timeout_timer);
|
|
|
|
#endif
|
|
|
|
switch (msg.type) {
|
|
|
|
case GNRC_NETAPI_MSG_TYPE_RCV:
|
|
|
|
pkt = msg.content.ptr;
|
|
|
|
break;
|
|
|
|
#ifdef MODULE_XTIMER
|
|
|
|
case _TIMEOUT_MSG_TYPE:
|
|
|
|
if (msg.content.value == _TIMEOUT_MAGIC) {
|
|
|
|
return -ETIMEDOUT;
|
|
|
|
}
|
|
|
|
#endif
|
2017-07-25 21:12:30 +02:00
|
|
|
/* Falls Through. */
|
2016-06-09 11:08:53 +02:00
|
|
|
default:
|
2017-06-12 13:53:11 +02:00
|
|
|
return -EINVAL;
|
2016-06-09 11:08:53 +02:00
|
|
|
}
|
|
|
|
/* TODO: discern NETTYPE from remote->family (set in caller), when IPv4
|
|
|
|
* was implemented */
|
2018-09-28 13:02:31 +02:00
|
|
|
ipv6_hdr_t *ipv6_hdr = gnrc_ipv6_get_header(pkt);
|
|
|
|
assert(ipv6_hdr != NULL);
|
2016-06-09 11:08:53 +02:00
|
|
|
memcpy(&remote->addr, &ipv6_hdr->src, sizeof(ipv6_addr_t));
|
|
|
|
remote->family = AF_INET6;
|
|
|
|
netif = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF);
|
|
|
|
if (netif == NULL) {
|
|
|
|
remote->netif = SOCK_ADDR_ANY_NETIF;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
gnrc_netif_hdr_t *netif_hdr = netif->data;
|
|
|
|
/* TODO: use API in #5511 */
|
|
|
|
remote->netif = (uint16_t)netif_hdr->if_pid;
|
|
|
|
}
|
|
|
|
*pkt_out = pkt; /* set out parameter */
|
2020-01-17 17:06:09 +01:00
|
|
|
|
2020-05-12 14:01:30 +02:00
|
|
|
#if IS_ACTIVE(SOCK_HAS_ASYNC)
|
|
|
|
if (reg->async_cb.generic && cib_avail(®->mbox.cib)) {
|
|
|
|
reg->async_cb.generic(reg, SOCK_ASYNC_MSG_RECV, reg->async_cb_arg);
|
|
|
|
}
|
|
|
|
#endif
|
2020-01-17 17:06:09 +01:00
|
|
|
#ifdef MODULE_FUZZING
|
|
|
|
prevpkt = pkt;
|
|
|
|
#endif
|
|
|
|
|
2016-06-09 11:08:53 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t gnrc_sock_send(gnrc_pktsnip_t *payload, sock_ip_ep_t *local,
|
|
|
|
const sock_ip_ep_t *remote, uint8_t nh)
|
|
|
|
{
|
|
|
|
gnrc_pktsnip_t *pkt;
|
|
|
|
kernel_pid_t iface = KERNEL_PID_UNDEF;
|
|
|
|
gnrc_nettype_t type;
|
|
|
|
size_t payload_len = gnrc_pkt_len(payload);
|
2019-11-10 12:45:48 +01:00
|
|
|
#ifdef MODULE_GNRC_NETERR
|
|
|
|
unsigned status_subs = 0;
|
|
|
|
#endif
|
2016-06-09 11:08:53 +02:00
|
|
|
|
|
|
|
if (local->family != remote->family) {
|
|
|
|
gnrc_pktbuf_release(payload);
|
|
|
|
return -EAFNOSUPPORT;
|
|
|
|
}
|
|
|
|
switch (local->family) {
|
|
|
|
#ifdef SOCK_HAS_IPV6
|
|
|
|
case AF_INET6: {
|
|
|
|
ipv6_hdr_t *hdr;
|
|
|
|
pkt = gnrc_ipv6_hdr_build(payload, (ipv6_addr_t *)&local->addr.ipv6,
|
|
|
|
(ipv6_addr_t *)&remote->addr.ipv6);
|
|
|
|
if (pkt == NULL) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
if (payload->type == GNRC_NETTYPE_UNDEF) {
|
|
|
|
payload->type = GNRC_NETTYPE_IPV6;
|
|
|
|
type = GNRC_NETTYPE_IPV6;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
type = payload->type;
|
|
|
|
}
|
|
|
|
hdr = pkt->data;
|
|
|
|
hdr->nh = nh;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
(void)nh;
|
|
|
|
gnrc_pktbuf_release(payload);
|
|
|
|
return -EAFNOSUPPORT;
|
|
|
|
}
|
|
|
|
if (local->netif != SOCK_ADDR_ANY_NETIF) {
|
|
|
|
/* TODO: use API in #5511 */
|
|
|
|
iface = (kernel_pid_t)local->netif;
|
|
|
|
}
|
|
|
|
else if (remote->netif != SOCK_ADDR_ANY_NETIF) {
|
|
|
|
/* TODO: use API in #5511 */
|
|
|
|
iface = (kernel_pid_t)remote->netif;
|
|
|
|
}
|
|
|
|
if (iface != KERNEL_PID_UNDEF) {
|
|
|
|
gnrc_pktsnip_t *netif = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
|
|
|
|
gnrc_netif_hdr_t *netif_hdr;
|
|
|
|
|
|
|
|
if (netif == NULL) {
|
|
|
|
gnrc_pktbuf_release(pkt);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
netif_hdr = netif->data;
|
|
|
|
netif_hdr->if_pid = iface;
|
|
|
|
LL_PREPEND(pkt, netif);
|
|
|
|
}
|
|
|
|
#ifdef MODULE_GNRC_NETERR
|
2019-11-10 12:45:48 +01:00
|
|
|
/* cppcheck-suppress uninitvar
|
|
|
|
* (reason: pkt is initialized in AF_INET6 case above, otherwise function
|
|
|
|
* will return early) */
|
|
|
|
for (gnrc_pktsnip_t *ptr = pkt; ptr != NULL; ptr = ptr->next) {
|
|
|
|
/* no error should occur since pkt was created here */
|
|
|
|
gnrc_neterr_reg(ptr);
|
|
|
|
status_subs++;
|
|
|
|
}
|
2016-06-09 11:08:53 +02:00
|
|
|
#endif
|
|
|
|
if (!gnrc_netapi_dispatch_send(type, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) {
|
|
|
|
/* this should not happen, but just in case */
|
|
|
|
gnrc_pktbuf_release(pkt);
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
#ifdef MODULE_GNRC_NETERR
|
2019-11-10 12:45:48 +01:00
|
|
|
uint32_t last_status = GNRC_NETERR_SUCCESS;
|
|
|
|
|
|
|
|
while (status_subs--) {
|
|
|
|
msg_t err_report;
|
|
|
|
err_report.type = 0;
|
2016-06-09 11:08:53 +02:00
|
|
|
|
2019-11-10 12:45:48 +01:00
|
|
|
while (err_report.type != GNRC_NETERR_MSG_TYPE) {
|
|
|
|
msg_try_receive(&err_report);
|
|
|
|
if (err_report.type != GNRC_NETERR_MSG_TYPE) {
|
|
|
|
msg_try_send(&err_report, sched_active_pid);
|
|
|
|
}
|
2016-06-09 11:08:53 +02:00
|
|
|
}
|
2019-11-10 12:45:48 +01:00
|
|
|
if (err_report.content.value != last_status) {
|
|
|
|
int res = (int)(-err_report.content.value);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < status_subs; i++) {
|
|
|
|
err_report.type = 0;
|
|
|
|
/* remove remaining status reports from queue */
|
|
|
|
while (err_report.type != GNRC_NETERR_MSG_TYPE) {
|
|
|
|
msg_try_receive(&err_report);
|
|
|
|
if (err_report.type != GNRC_NETERR_MSG_TYPE) {
|
|
|
|
msg_try_send(&err_report, sched_active_pid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
last_status = err_report.content.value;
|
2016-06-09 11:08:53 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return payload_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @} */
|