Browse Source

gnrc_sock_udp: get source port from dynmic port range

- get a new source port from a predefined range
    - check if port already in use, if required
    - refinded consistency checks for params of send()
pr/spi.typo
smlng 6 years ago
parent
commit
e2cf221a58
  1. 146
      sys/net/gnrc/sock/udp/gnrc_sock_udp.c

146
sys/net/gnrc/sock/udp/gnrc_sock_udp.c

@ -24,7 +24,6 @@
#include "net/gnrc/udp.h"
#include "net/sock/udp.h"
#include "net/udp.h"
#include "random.h"
#include "gnrc_sock_internal.h"
@ -32,6 +31,59 @@
static sock_udp_t *_udp_socks = NULL;
#endif
static uint16_t _dyn_port_next = 0;
/**
* @brief Checks if a given UDP port is already used by another sock
*/
static bool _dyn_port_used(uint16_t port)
{
#ifdef MODULE_GNRC_SOCK_CHECK_REUSE
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 == port) {
/* port already in use by another sock */
return true;
}
}
#else
(void) port;
#endif /* MODULE_GNRC_SOCK_CHECK_REUSE */
return false;
}
/**
* @brief returns a UDP port, and checks for reuse if required
*
* complies to RFC 6056, see https://tools.ietf.org/html/rfc6056#section-3.3.3
*/
static uint16_t _get_dyn_port(sock_udp_t *sock)
{
uint16_t port;
unsigned count = GNRC_SOCK_DYN_PORTRANGE_NUM;
do {
port = GNRC_SOCK_DYN_PORTRANGE_MIN +
(_dyn_port_next * GNRC_SOCK_DYN_PORTRANGE_OFF) % GNRC_SOCK_DYN_PORTRANGE_NUM;
_dyn_port_next++;
if ((sock == NULL) || (sock->flags & SOCK_FLAGS_REUSE_EP) ||
!_dyn_port_used(port)) {
return port;
}
--count;
} while (count > 0);
return GNRC_SOCK_DYN_PORTRANGE_ERR;
}
int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local,
const sock_udp_ep_t *remote, uint16_t flags)
{
@ -76,8 +128,7 @@ int sock_udp_create(sock_udp_t *sock, const sock_udp_ep_t *local,
}
if (local != NULL) {
/* listen only with local given */
gnrc_sock_create(&sock->reg, GNRC_NETTYPE_UDP,
local->port);
gnrc_sock_create(&sock->reg, GNRC_NETTYPE_UDP, local->port);
}
sock->flags = flags;
return 0;
@ -170,19 +221,25 @@ ssize_t sock_udp_send(sock_udp_t *sock, const void *data, size_t len,
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) {
if (remote->port == 0) {
return -EINVAL;
}
else if (gnrc_ep_addr_any((const sock_ip_ep_t *)remote)) {
return -EINVAL;
}
else if (gnrc_af_not_supported(remote->family)) {
return -EAFNOSUPPORT;
}
else if ((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) &&
/* sock can't be NULL as per assertion above */
(sock->remote.family == AF_UNSPEC)) {
else if (sock->remote.family == AF_UNSPEC) {
return -ENOTCONN;
}
/* compiler evaluates lazily so this isn't a redundundant check and cppcheck
@ -191,33 +248,10 @@ ssize_t sock_udp_send(sock_udp_t *sock, const void *data, size_t len,
/* 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 ((src_port = _get_dyn_port(sock)) == GNRC_SOCK_DYN_PORTRANGE_ERR) {
return -EINVAL;
}
if (sock != NULL) {
/* bind sock object implicitly */
sock->local.port = src_port;
@ -227,20 +261,20 @@ ssize_t sock_udp_send(sock_udp_t *sock, const void *data, size_t len,
else {
sock->local.family = remote->family;
}
gnrc_sock_create(&sock->reg, GNRC_NETTYPE_UDP, 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
gnrc_sock_create(&sock->reg, GNRC_NETTYPE_UDP, src_port);
#endif /* MODULE_GNRC_SOCK_CHECK_REUSE */
}
}
else {
src_port = sock->local.port;
memcpy(&local, &sock->local, sizeof(local));
}
/* sock can't be NULL at this point */
if (remote == NULL) {
/* sock can't be NULL at this point */
memcpy(&rem, &sock->remote, sizeof(rem));
dst_port = sock->remote.port;
}
@ -248,23 +282,17 @@ ssize_t sock_udp_send(sock_udp_t *sock, const void *data, size_t len,
memcpy(&rem, remote, sizeof(rem));
dst_port = remote->port;
}
if ((remote != NULL) && (remote->family == AF_UNSPEC) &&
(sock != NULL) && (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 */
/* check for matching address families in local and remote */
if ((local.family == AF_UNSPEC) && (rem.family != AF_UNSPEC)) {
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;
}
else if (local.family != rem.family) {
return -EINVAL;
}
/* generate payload and header snips */
payload = gnrc_pktbuf_add(NULL, (void *)data, len, GNRC_NETTYPE_UNDEF);
if (payload == NULL) {
return -ENOMEM;
@ -275,10 +303,10 @@ ssize_t sock_udp_send(sock_udp_t *sock, const void *data, size_t len,
return -ENOMEM;
}
res = gnrc_sock_send(pkt, &local, &rem, PROTNUM_UDP);
if (res <= 0) {
return res;
if (res > 0) {
res -= sizeof(udp_hdr_t);
}
return res - sizeof(udp_hdr_t);
return res;
}
/** @} */

Loading…
Cancel
Save