

10 changed files with 682 additions and 0 deletions
@ -0,0 +1,3 @@
|
||||
MODULE = gnrc_sock
|
||||
|
||||
include $(RIOTBASE)/Makefile.base |
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* 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> |
||||
|
||||
#include "net/af.h" |
||||
#include "net/ipv6/hdr.h" |
||||
#include "net/gnrc/ipv6/hdr.h" |
||||
#include "net/gnrc/ipv6/netif.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" |
||||
|
||||
#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 |
||||
|
||||
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); |
||||
gnrc_netreg_entry_init_mbox(®->entry, demux_ctx, ®->mbox); |
||||
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) |
||||
{ |
||||
gnrc_pktsnip_t *pkt, *ip, *netif; |
||||
msg_t msg; |
||||
|
||||
#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 |
||||
default: |
||||
return -EINTR; |
||||
} |
||||
/* TODO: discern NETTYPE from remote->family (set in caller), when IPv4
|
||||
* was implemented */ |
||||
ipv6_hdr_t *ipv6_hdr; |
||||
ip = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6); |
||||
assert((ip != NULL) && (ip->size >= 40)); |
||||
ipv6_hdr = ip->data; |
||||
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 */ |
||||
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); |
||||
|
||||
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 |
||||
gnrc_neterr_reg(pkt); /* no error should occur since pkt was created here */ |
||||
#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 |
||||
msg_t err_report; |
||||
err_report.type = 0; |
||||
|
||||
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); |
||||
} |
||||
} |
||||
if (err_report.content.value != GNRC_NETERR_SUCCESS) { |
||||
return (int)(-err_report.content.value); |
||||
} |
||||
#endif |
||||
return payload_len; |
||||
} |
||||
|
||||
/** @} */ |
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup net_gnrc_sock GNRC-specific implementation of the sock API |
||||
* @ingroup net_gnrc |
||||
* @brief Provides an implementation of the @ref net_sock by the |
||||
* @ref net_gnrc |
||||
* |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief GNRC-specific types and function definitions |
||||
* |
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de> |
||||
*/ |
||||
#ifndef GNRC_SOCK_INTERNAL_H_ |
||||
#define GNRC_SOCK_INTERNAL_H_ |
||||
|
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
#include "mbox.h" |
||||
#include "net/af.h" |
||||
#include "net/gnrc.h" |
||||
#include "net/gnrc/netreg.h" |
||||
#include "net/sock/ip.h" |
||||
|
||||
#include "sock_types.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Internal helper functions for GNRC |
||||
* @internal |
||||
* @{ |
||||
*/ |
||||
/**
|
||||
* @brief Checks if address family is not supported |
||||
* @internal |
||||
*/ |
||||
static inline bool gnrc_af_not_supported(int af) |
||||
{ |
||||
/* TODO: add AF_INET support */ |
||||
return (af != AF_INET6); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Check if end point points to any address |
||||
* @internal |
||||
*/ |
||||
static inline bool gnrc_ep_addr_any(const sock_ip_ep_t *ep) |
||||
{ |
||||
assert(ep != NULL); |
||||
const uint8_t *p = (uint8_t *)&ep->addr; |
||||
for (uint8_t i = 0; i < sizeof(ep->addr); i++) { |
||||
if (p[i] != 0) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Create a sock internally |
||||
* @internal |
||||
*/ |
||||
void gnrc_sock_create(gnrc_sock_reg_t *reg, gnrc_nettype_t type, uint32_t demux_ctx); |
||||
|
||||
/**
|
||||
* @brief Receive a packet internally |
||||
* @internal |
||||
*/ |
||||
ssize_t gnrc_sock_recv(gnrc_sock_reg_t *reg, gnrc_pktsnip_t **pkt, uint32_t timeout, |
||||
sock_ip_ep_t *remote); |
||||
|
||||
/**
|
||||
* @brief Send a packet internally |
||||
* @internal |
||||
*/ |
||||
ssize_t gnrc_sock_send(gnrc_pktsnip_t *payload, sock_ip_ep_t *local, |
||||
const sock_ip_ep_t *remote, uint8_t nh); |
||||
/**
|
||||
* @} |
||||
*/ |
||||
|
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* GNRC_SOCK_INTERNAL_H_ */ |
||||
/** @} */ |
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup net_gnrc_sock GNRC-specific implementation of the sock API |
||||
* @ingroup net_gnrc |
||||
* @brief Provides an implementation of the @ref net_sock by the |
||||
* @ref net_gnrc |
||||
* |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief GNRC-specific types and function definitions |
||||
* |
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de> |
||||
*/ |
||||
#ifndef SOCK_TYPES_H_ |
||||
#define SOCK_TYPES_H_ |
||||
|
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
#include "mbox.h" |
||||
#include "net/gnrc.h" |
||||
#include "net/gnrc/netreg.h" |
||||
#include "net/sock/ip.h" |
||||
#include "net/sock/udp.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#ifndef SOCK_MBOX_SIZE |
||||
#define SOCK_MBOX_SIZE (8) /**< Size for gnrc_sock_reg_t::mbox_queue */ |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief sock @ref net_gnrc_netreg info |
||||
* @internal |
||||
*/ |
||||
typedef struct gnrc_sock_reg { |
||||
#ifdef MODULE_GNRC_SOCK_CHECK_REUSE |
||||
struct gnrc_sock_reg *next; /**< list-like for internal storage */ |
||||
#endif |
||||
gnrc_netreg_entry_t entry; /**< @ref net_gnrc_netreg entry for mbox */ |
||||
mbox_t mbox; /**< @ref core_mbox target for the sock */ |
||||
msg_t mbox_queue[SOCK_MBOX_SIZE]; /**< queue for gnrc_sock_reg_t::mbox */ |
||||
} gnrc_sock_reg_t; |
||||
|
||||
/**
|
||||
* @brief UDP sock type |
||||
* @internal |
||||
*/ |
||||
struct sock_udp { |
||||
gnrc_sock_reg_t reg; /**< netreg info */ |
||||
sock_udp_ep_t local; /**< local end-point */ |
||||
sock_udp_ep_t remote; /**< remote end-point */ |
||||
uint16_t flags; /**< option flags */ |
||||
}; |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* SOCK_TYPES_H_ */ |
||||
/** @} */ |
@ -0,0 +1,3 @@
|
||||
MODULE = gnrc_sock_udp
|
||||
|
||||
include $(RIOTBASE)/Makefile.base |
@ -0,0 +1,277 @@
|
||||
/*
|
||||
* 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 |
||||
* @brief GNRC implementation of @ref net_sock_udp |
||||
* |
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de> |
||||
*/ |
||||
|
||||
#include <errno.h> |
||||
|
||||
#include "byteorder.h" |
||||
#include "net/af.h" |
||||
#include "net/protnum.h" |
||||
#include "net/gnrc/ipv6.h" |
||||
#include "net/gnrc/udp.h" |
||||
#include "net/sock/udp.h" |
||||
#include "net/udp.h" |
||||
#include "random.h" |
||||
|
||||
#include "gnrc_sock_internal.h" |
||||
|
||||
#ifdef MODULE_GNRC_SOCK_CHECK_REUSE |
||||
static sock_udp_t *_udp_socks = NULL; |
||||
#endif |
||||
|
||||
int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local, |
||||
const sock_udp_ep_t *remote, uint16_t flags) |
||||
{ |
||||
assert(sock); |
||||
assert(local == NULL || local->port != 0); |
||||
assert(remote == NULL || remote->port != 0); |
||||
if ((local != NULL) && (remote != NULL) && |
||||
(local->netif != SOCK_ADDR_ANY_NETIF) && |
||||
(remote->netif != SOCK_ADDR_ANY_NETIF) && |
||||
(local->netif != remote->netif)) { |
||||
return -EINVAL; |
||||
} |
||||
memset(&sock->local, 0, sizeof(sock_udp_ep_t)); |
||||
if (local != NULL) { |
||||
#ifdef MODULE_GNRC_SOCK_CHECK_REUSE |
||||
if (!(flags & SOCK_FLAGS_REUSE_EP)) { |
||||
for (sock_udp_t *ptr = _udp_socks; ptr != NULL; |
||||
ptr = (sock_udp_t *)ptr->reg.next) { |
||||
if (memcmp(&ptr->local, local, sizeof(sock_udp_ep_t)) == 0) { |
||||
return -EADDRINUSE; |
||||
} |
||||
} |
||||
} |
||||
/* prepend to current socks */ |
||||
sock->reg.next = (gnrc_sock_reg_t *)_udp_socks; |
||||
_udp_socks = sock; |
||||
#endif |
||||
if (gnrc_af_not_supported(local->family)) { |
||||
return -EAFNOSUPPORT; |
||||
} |
||||
memcpy(&sock->local, local, sizeof(sock_udp_ep_t)); |
||||
} |
||||
memset(&sock->remote, 0, sizeof(sock_udp_ep_t)); |
||||
if (remote != NULL) { |
||||
if (gnrc_af_not_supported(remote->family)) { |
||||
return -EAFNOSUPPORT; |
||||
} |
||||
if (gnrc_ep_addr_any((const sock_ip_ep_t *)remote)) { |
||||
return -EINVAL; |
||||
} |
||||
memcpy(&sock->remote, remote, sizeof(sock_udp_ep_t)); |
||||
} |
||||
if (local != NULL) { |
||||
/* listen only with local given */ |
||||
gnrc_sock_create(&sock->reg, GNRC_NETTYPE_UDP, |
||||
local->port); |
||||
} |
||||
sock->flags = flags; |
||||
return 0; |
||||
} |
||||
|
||||
void sock_udp_close(sock_udp_t *sock) |
||||
{ |
||||
assert(sock != NULL); |
||||
gnrc_netreg_unregister(GNRC_NETTYPE_UDP, &sock->reg.entry); |
||||
#ifdef MODULE_GNRC_SOCK_CHECK_REUSE |
||||
if (_udp_socks != NULL) { |
||||
gnrc_sock_reg_t *head = (gnrc_sock_reg_t *)_udp_socks; |
||||
LL_DELETE(head, (gnrc_sock_reg_t *)sock); |
||||
} |
||||
#endif |
||||
} |
||||
|
||||
int sock_udp_get_local(sock_udp_t *sock, sock_udp_ep_t *local) |
||||
{ |
||||
assert(sock && local); |
||||
if (sock->local.family == AF_UNSPEC) { |
||||
return -EADDRNOTAVAIL; |
||||
} |
||||
memcpy(local, &sock->local, sizeof(sock_udp_ep_t)); |
||||
return 0; |
||||
} |
||||
|
||||
int sock_udp_get_remote(sock_udp_t *sock, sock_udp_ep_t *remote) |
||||
{ |
||||
assert(sock && remote); |
||||
if (sock->remote.family == AF_UNSPEC) { |
||||
return -ENOTCONN; |
||||
} |
||||
memcpy(remote, &sock->remote, sizeof(sock_udp_ep_t)); |
||||
return 0; |
||||
} |
||||
|
||||
ssize_t sock_udp_recv(sock_udp_t *sock, void *data, size_t max_len, |
||||
uint32_t timeout, sock_udp_ep_t *remote) |
||||
{ |
||||
gnrc_pktsnip_t *pkt, *udp; |
||||
udp_hdr_t *hdr; |
||||
sock_ip_ep_t tmp; |
||||
int res; |
||||
|
||||
assert((sock != NULL) && (data != NULL) && (max_len > 0)); |
||||
if (sock->local.family == AF_UNSPEC) { |
||||
return -EADDRNOTAVAIL; |
||||
} |
||||
tmp.family = sock->local.family; |
||||
res = gnrc_sock_recv((gnrc_sock_reg_t *)sock, &pkt, timeout, &tmp); |
||||
if (res < 0) { |
||||
return res; |
||||
} |
||||
if (pkt->size > max_len) { |
||||
gnrc_pktbuf_release(pkt); |
||||
return -ENOBUFS; |
||||
} |
||||
udp = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_UDP); |
||||
assert(udp); |
||||
hdr = udp->data; |
||||
if (remote != NULL) { |
||||
/* return remote to possibly block if wrong remote */ |
||||
memcpy(remote, &tmp, sizeof(tmp)); |
||||
remote->port = byteorder_ntohs(hdr->src_port); |
||||
} |
||||
if ((sock->remote.family != AF_UNSPEC) && /* check remote end-point if set */ |
||||
((sock->remote.port != byteorder_ntohs(hdr->src_port)) || |
||||
/* We only have IPv6 for now, so just comparing the whole end point
|
||||
* should suffice */ |
||||
((memcmp(&sock->remote.addr, &ipv6_addr_unspecified, |
||||
sizeof(ipv6_addr_t)) != 0) && |
||||
(memcmp(&sock->remote.addr, &tmp.addr, sizeof(ipv6_addr_t)) != 0)))) { |
||||
gnrc_pktbuf_release(pkt); |
||||
return -EPROTO; |
||||
} |
||||
memcpy(data, pkt->data, pkt->size); |
||||
gnrc_pktbuf_release(pkt); |
||||
return (int)pkt->size; |
||||
} |
||||
|
||||
ssize_t sock_udp_send(sock_udp_t *sock, const void *data, size_t len, |
||||
const sock_udp_ep_t *remote) |
||||
{ |
||||
int res; |
||||
gnrc_pktsnip_t *payload, *pkt; |
||||
uint16_t src_port = 0, dst_port; |
||||
sock_ip_ep_t local; |
||||
sock_ip_ep_t rem; |
||||
|
||||
assert((sock != NULL) || (remote != NULL)); |
||||
assert((len == 0) || (data != NULL)); /* (len != 0) => (data != NULL) */ |
||||
if ((remote != NULL) && (sock != NULL) && |
||||
(sock->local.netif != SOCK_ADDR_ANY_NETIF) && |
||||
(remote->netif != SOCK_ADDR_ANY_NETIF) && |
||||
(sock->local.netif != remote->netif)) { |
||||
return -EINVAL; |
||||
} |
||||
if ((remote != NULL) && ((remote->port == 0) || |
||||
gnrc_ep_addr_any((const sock_ip_ep_t *)remote))) { |
||||
return -EINVAL; |
||||
} |
||||
if ((remote == NULL) && |
||||
/* sock can't be NULL as per assertion above */ |
||||
(sock->remote.port == AF_UNSPEC)) { |
||||
return -ENOTCONN; |
||||
} |
||||
/* compiler evaluates lazily so this isn't a redundundant check and cppcheck
|
||||
* is being weird here anyways */ |
||||
/* cppcheck-suppress nullPointerRedundantCheck */ |
||||
/* cppcheck-suppress nullPointer */ |
||||
if ((sock == NULL) || (sock->local.family == AF_UNSPEC)) { |
||||
/* no sock or sock currently unbound */ |
||||
while (src_port == 0) { |
||||
src_port = (uint16_t)(random_uint32() & UINT16_MAX); |
||||
#ifdef MODULE_GNRC_SOCK_CHECK_REUSE |
||||
if ((sock == NULL) || !(sock->flags & SOCK_FLAGS_REUSE_EP)) { |
||||
/* check if port already registered somewhere */ |
||||
for (sock_udp_t *ptr = _udp_socks; ptr != NULL; |
||||
ptr = (sock_udp_t *)ptr->reg.next) { |
||||
bool spec_addr = false; |
||||
for (unsigned i = 0; i < sizeof(ptr->local.addr); i++) { |
||||
const uint8_t *const p = (uint8_t *)&ptr->local.addr; |
||||
if (p[i] != 0) { |
||||
spec_addr = true; |
||||
} |
||||
} |
||||
if (spec_addr) { |
||||
continue; |
||||
} |
||||
if (ptr->local.port == src_port) { |
||||
/* we already have one of this port registered
|
||||
* => generate a new one */ |
||||
src_port = 0; |
||||
} |
||||
} |
||||
} |
||||
#endif |
||||
} |
||||
memset(&local, 0, sizeof(local)); |
||||
if (sock != NULL) { |
||||
/* bind sock object implicitly */ |
||||
sock->local.port = src_port; |
||||
#ifdef MODULE_GNRC_SOCK_CHECK_REUSE |
||||
/* prepend to current socks */ |
||||
sock->reg.next = (gnrc_sock_reg_t *)_udp_socks; |
||||
_udp_socks = sock; |
||||
#endif |
||||
} |
||||
} |
||||
else { |
||||
src_port = sock->local.port; |
||||
memcpy(&local, &sock->local, sizeof(local)); |
||||
} |
||||
if (remote == NULL) { |
||||
/* sock can't be NULL at this point */ |
||||
memcpy(&rem, &sock->remote, sizeof(rem)); |
||||
dst_port = sock->remote.port; |
||||
} |
||||
else { |
||||
memcpy(&rem, remote, sizeof(rem)); |
||||
dst_port = remote->port; |
||||
} |
||||
if ((remote != NULL) && (remote->family == AF_UNSPEC) && |
||||
(sock->remote.family != AF_UNSPEC)) { |
||||
/* remote was set on create so take its family */ |
||||
rem.family = sock->remote.family; |
||||
} |
||||
else if ((remote != NULL) && gnrc_af_not_supported(remote->family)) { |
||||
return -EAFNOSUPPORT; |
||||
} |
||||
else if ((local.family == AF_UNSPEC) && (rem.family != AF_UNSPEC)) { |
||||
/* local was set to 0 above */ |
||||
local.family = rem.family; |
||||
} |
||||
else if ((local.family != AF_UNSPEC) && (rem.family == AF_UNSPEC)) { |
||||
/* local was given on create, but remote family wasn't given by user and
|
||||
* there was no remote given on create, take from local */ |
||||
rem.family = local.family; |
||||
} |
||||
payload = gnrc_pktbuf_add(NULL, (void *)data, len, GNRC_NETTYPE_UNDEF); |
||||
if (payload == NULL) { |
||||
return -ENOMEM; |
||||
} |
||||
pkt = gnrc_udp_hdr_build(payload, src_port, dst_port); |
||||
if (pkt == NULL) { |
||||
gnrc_pktbuf_release(payload); |
||||
return -ENOMEM; |
||||
} |
||||
res = gnrc_sock_send(pkt, &local, &rem, PROTNUM_UDP); |
||||
if (res <= 0) { |
||||
return res; |
||||
} |
||||
return res - sizeof(udp_hdr_t); |
||||
} |
||||
|
||||
/** @} */ |
Loading…
Reference in new issue