2016-05-09 14:49:48 +02:00
|
|
|
/** @file
|
2016-06-22 15:44:55 +02:00
|
|
|
* @brief Network context API
|
|
|
|
*
|
|
|
|
* An API for applications to define a network connection.
|
2016-05-09 14:49:48 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2016 Intel Corporation
|
|
|
|
*
|
2017-01-19 02:01:01 +01:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2016-05-09 14:49:48 +02:00
|
|
|
*/
|
|
|
|
|
2018-11-30 11:54:56 +01:00
|
|
|
#include <logging/log.h>
|
|
|
|
LOG_MODULE_REGISTER(net_ctx, CONFIG_NET_CONTEXT_LOG_LEVEL);
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2016-11-09 17:09:27 +01:00
|
|
|
#include <kernel.h>
|
2020-06-12 06:28:55 +02:00
|
|
|
#include <random/rand32.h>
|
2016-05-09 14:49:48 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
2017-04-03 17:14:35 +02:00
|
|
|
#include <net/net_pkt.h>
|
2016-05-09 14:49:48 +02:00
|
|
|
#include <net/net_ip.h>
|
2019-06-27 16:57:01 +02:00
|
|
|
#include <net/socket.h>
|
2016-05-09 14:49:48 +02:00
|
|
|
#include <net/net_context.h>
|
2017-03-09 15:08:19 +01:00
|
|
|
#include <net/net_offload.h>
|
2019-01-28 14:45:28 +01:00
|
|
|
#include <net/ethernet.h>
|
2019-01-24 13:13:42 +01:00
|
|
|
#include <net/socket_can.h>
|
2016-05-09 14:49:48 +02:00
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
#include "connection.h"
|
|
|
|
#include "net_private.h"
|
|
|
|
|
2016-06-27 11:27:49 +02:00
|
|
|
#include "ipv6.h"
|
|
|
|
#include "ipv4.h"
|
2017-06-30 16:46:01 +02:00
|
|
|
#include "udp_internal.h"
|
2018-03-02 23:20:51 +01:00
|
|
|
#include "tcp_internal.h"
|
2017-05-16 14:27:27 +02:00
|
|
|
#include "net_stats.h"
|
2016-06-27 11:27:49 +02:00
|
|
|
|
2019-10-19 09:08:06 +02:00
|
|
|
#if IS_ENABLED(CONFIG_NET_TCP2)
|
|
|
|
#include "tcp2.h"
|
|
|
|
#endif
|
|
|
|
|
2017-08-15 00:13:16 +02:00
|
|
|
#ifndef EPFNOSUPPORT
|
|
|
|
/* Some old versions of newlib haven't got this defined in errno.h,
|
|
|
|
* Just use EPROTONOSUPPORT in this case
|
|
|
|
*/
|
|
|
|
#define EPFNOSUPPORT EPROTONOSUPPORT
|
|
|
|
#endif
|
|
|
|
|
2018-12-13 14:05:21 +01:00
|
|
|
#define PKT_WAIT_TIME K_SECONDS(1)
|
|
|
|
|
2016-05-09 14:49:48 +02:00
|
|
|
#define NET_MAX_CONTEXT CONFIG_NET_MAX_CONTEXTS
|
|
|
|
|
|
|
|
static struct net_context contexts[NET_MAX_CONTEXT];
|
2016-06-22 15:44:55 +02:00
|
|
|
|
|
|
|
/* We need to lock the contexts array as these APIs are typically called
|
|
|
|
* from applications which are usually run in task context.
|
|
|
|
*/
|
2016-11-09 17:09:27 +01:00
|
|
|
static struct k_sem contexts_lock;
|
2016-05-09 14:49:48 +02:00
|
|
|
|
2019-02-07 14:00:44 +01:00
|
|
|
#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP)
|
2017-02-03 12:49:00 +01:00
|
|
|
static int check_used_port(enum net_ip_protocol ip_proto,
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t local_port,
|
2017-02-03 12:49:00 +01:00
|
|
|
const struct sockaddr *local_addr)
|
|
|
|
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_MAX_CONTEXT; i++) {
|
|
|
|
if (!net_context_is_used(&contexts[i])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(net_context_get_ip_proto(&contexts[i]) == ip_proto &&
|
|
|
|
net_sin((struct sockaddr *)&
|
|
|
|
contexts[i].local)->sin_port == local_port)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6) &&
|
|
|
|
local_addr->sa_family == AF_INET6) {
|
2017-02-03 12:49:00 +01:00
|
|
|
if (net_ipv6_addr_cmp(
|
|
|
|
net_sin6_ptr(&contexts[i].local)->
|
|
|
|
sin6_addr,
|
|
|
|
&((struct sockaddr_in6 *)
|
|
|
|
local_addr)->sin6_addr)) {
|
|
|
|
return -EEXIST;
|
|
|
|
}
|
2019-04-29 10:32:31 +02:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_IPV4) &&
|
|
|
|
local_addr->sa_family == AF_INET) {
|
2017-02-03 12:49:00 +01:00
|
|
|
if (net_ipv4_addr_cmp(
|
|
|
|
net_sin_ptr(&contexts[i].local)->
|
|
|
|
sin_addr,
|
|
|
|
&((struct sockaddr_in *)
|
|
|
|
local_addr)->sin_addr)) {
|
|
|
|
return -EEXIST;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static uint16_t find_available_port(struct net_context *context,
|
2017-02-03 12:49:00 +01:00
|
|
|
const struct sockaddr *addr)
|
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t local_port;
|
2017-02-03 12:49:00 +01:00
|
|
|
|
2017-10-27 08:46:06 +02:00
|
|
|
do {
|
|
|
|
local_port = sys_rand32_get() | 0x8000;
|
2019-03-27 02:57:45 +01:00
|
|
|
if (local_port <= 1023U) {
|
2017-10-27 08:46:06 +02:00
|
|
|
/* 0 - 1023 ports are reserved */
|
|
|
|
continue;
|
|
|
|
}
|
2019-04-29 10:32:31 +02:00
|
|
|
} while (check_used_port(net_context_get_ip_proto(context),
|
|
|
|
htons(local_port), addr) == -EEXIST);
|
2017-02-03 12:49:00 +01:00
|
|
|
|
2017-10-27 08:46:06 +02:00
|
|
|
return htons(local_port);
|
2017-02-03 12:49:00 +01:00
|
|
|
}
|
2019-04-29 10:32:31 +02:00
|
|
|
#else
|
|
|
|
#define check_used_port(...) 0
|
|
|
|
#define find_available_port(...) 0
|
2019-02-07 14:00:44 +01:00
|
|
|
#endif
|
2017-02-03 12:49:00 +01:00
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
int net_context_get(sa_family_t family,
|
|
|
|
enum net_sock_type type,
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t ip_proto,
|
2016-06-22 15:44:55 +02:00
|
|
|
struct net_context **context)
|
|
|
|
{
|
|
|
|
int i, ret = -ENOENT;
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_CONTEXT_CHECK)) {
|
|
|
|
if (!IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) {
|
|
|
|
NET_DBG("IPv4 disabled");
|
|
|
|
return -EPFNOSUPPORT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) {
|
|
|
|
NET_DBG("IPv6 disabled");
|
|
|
|
return -EPFNOSUPPORT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IS_ENABLED(CONFIG_NET_SOCKETS_CAN) && family == AF_CAN) {
|
|
|
|
NET_DBG("AF_CAN disabled");
|
|
|
|
return -EPFNOSUPPORT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type == SOCK_RAW) {
|
|
|
|
if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
|
|
|
|
IS_ENABLED(CONFIG_NET_SOCKETS_CAN)) {
|
|
|
|
if (family != AF_PACKET && family != AF_CAN) {
|
|
|
|
NET_DBG("Invalid family");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
|
|
|
|
!IS_ENABLED(CONFIG_NET_SOCKETS_CAN)) {
|
|
|
|
if (family != AF_PACKET) {
|
|
|
|
NET_DBG("Invalid family");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
} else if (!IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
|
|
|
|
IS_ENABLED(CONFIG_NET_SOCKETS_CAN)) {
|
|
|
|
if (family != AF_CAN) {
|
|
|
|
NET_DBG("Invalid family");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2019-01-28 14:45:28 +01:00
|
|
|
}
|
2019-04-29 10:32:31 +02:00
|
|
|
} else {
|
|
|
|
if (family == AF_PACKET || family == AF_CAN) {
|
|
|
|
NET_DBG("Invalid family");
|
|
|
|
return -EPROTOTYPE;
|
2019-01-28 14:45:28 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (!IS_ENABLED(CONFIG_NET_UDP)) {
|
|
|
|
if (type == SOCK_DGRAM) {
|
|
|
|
NET_DBG("Datagram context disabled");
|
|
|
|
return -EPROTOTYPE;
|
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (ip_proto == IPPROTO_UDP) {
|
|
|
|
NET_DBG("UDP disabled");
|
|
|
|
return -EPROTONOSUPPORT;
|
|
|
|
}
|
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (!IS_ENABLED(CONFIG_NET_TCP)) {
|
|
|
|
if (type == SOCK_STREAM) {
|
|
|
|
NET_DBG("Stream context disabled");
|
|
|
|
return -EPROTOTYPE;
|
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (ip_proto == IPPROTO_TCP) {
|
|
|
|
NET_DBG("TCP disabled");
|
|
|
|
return -EPROTONOSUPPORT;
|
|
|
|
}
|
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (family != AF_INET && family != AF_INET6 &&
|
|
|
|
family != AF_PACKET && family != AF_CAN) {
|
|
|
|
NET_DBG("Unknown address family %d", family);
|
|
|
|
return -EAFNOSUPPORT;
|
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (type != SOCK_DGRAM && type != SOCK_STREAM &&
|
|
|
|
type != SOCK_RAW) {
|
|
|
|
NET_DBG("Unknown context type");
|
|
|
|
return -EPROTOTYPE;
|
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (type != SOCK_RAW && ip_proto != IPPROTO_UDP &&
|
|
|
|
ip_proto != IPPROTO_TCP) {
|
|
|
|
NET_DBG("Unknown IP protocol %d", ip_proto);
|
|
|
|
return -EPROTONOSUPPORT;
|
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if ((type == SOCK_STREAM && ip_proto == IPPROTO_UDP) ||
|
|
|
|
(type == SOCK_DGRAM && ip_proto == IPPROTO_TCP)) {
|
|
|
|
NET_DBG("Context type and protocol mismatch,"
|
|
|
|
" type %d proto %d", type, ip_proto);
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (!context) {
|
|
|
|
NET_DBG("Invalid context");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
}
|
|
|
|
|
2016-11-09 17:09:27 +01:00
|
|
|
k_sem_take(&contexts_lock, K_FOREVER);
|
2016-06-22 15:44:55 +02:00
|
|
|
|
|
|
|
for (i = 0; i < NET_MAX_CONTEXT; i++) {
|
|
|
|
if (net_context_is_used(&contexts[i])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-09-17 13:22:29 +02:00
|
|
|
memset(&contexts[i], 0, sizeof(contexts[i]));
|
2019-09-05 04:30:41 +02:00
|
|
|
/* FIXME - Figure out a way to get the correct network interface
|
|
|
|
* as it is not known at this point yet.
|
|
|
|
*/
|
|
|
|
if (!net_if_is_ip_offloaded(net_if_get_default())
|
|
|
|
&& ip_proto == IPPROTO_TCP) {
|
2018-03-21 11:14:07 +01:00
|
|
|
if (net_tcp_get(&contexts[i]) < 0) {
|
2017-11-23 08:11:03 +01:00
|
|
|
break;
|
2016-08-18 09:08:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-04 14:55:23 +01:00
|
|
|
contexts[i].iface = -1;
|
2019-03-27 02:57:45 +01:00
|
|
|
contexts[i].flags = 0U;
|
2017-01-26 00:14:59 +01:00
|
|
|
atomic_set(&contexts[i].refcount, 1);
|
2016-06-22 15:44:55 +02:00
|
|
|
|
|
|
|
net_context_set_family(&contexts[i], family);
|
|
|
|
net_context_set_type(&contexts[i], type);
|
|
|
|
net_context_set_ip_proto(&contexts[i], ip_proto);
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6) ||
|
|
|
|
IS_ENABLED(CONFIG_NET_IPV4)) {
|
|
|
|
(void)memset(&contexts[i].remote, 0,
|
|
|
|
sizeof(struct sockaddr));
|
|
|
|
(void)memset(&contexts[i].local, 0,
|
|
|
|
sizeof(struct sockaddr_ptr));
|
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) {
|
2017-02-03 12:49:00 +01:00
|
|
|
struct sockaddr_in6 *addr6 = (struct sockaddr_in6
|
|
|
|
*)&contexts[i].local;
|
|
|
|
addr6->sin6_port = find_available_port(&contexts[i],
|
|
|
|
(struct sockaddr *)addr6);
|
|
|
|
|
|
|
|
if (!addr6->sin6_port) {
|
2017-11-23 08:11:03 +01:00
|
|
|
ret = -EADDRINUSE;
|
|
|
|
break;
|
2017-02-03 12:49:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) {
|
2017-02-03 12:49:00 +01:00
|
|
|
struct sockaddr_in *addr = (struct sockaddr_in
|
|
|
|
*)&contexts[i].local;
|
|
|
|
addr->sin_port = find_available_port(&contexts[i],
|
|
|
|
(struct sockaddr *)addr);
|
|
|
|
|
|
|
|
if (!addr->sin_port) {
|
2017-11-23 08:11:03 +01:00
|
|
|
ret = -EADDRINUSE;
|
|
|
|
break;
|
2017-02-03 12:49:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
#if defined(CONFIG_NET_CONTEXT_SYNC_RECV)
|
2017-07-27 19:59:06 +02:00
|
|
|
k_sem_init(&contexts[i].recv_data_wait, 1, UINT_MAX);
|
2016-06-22 15:44:55 +02:00
|
|
|
#endif /* CONFIG_NET_CONTEXT_SYNC_RECV */
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_init(&contexts[i].lock);
|
|
|
|
|
2017-11-23 08:11:03 +01:00
|
|
|
contexts[i].flags |= NET_CONTEXT_IN_USE;
|
2016-06-22 15:44:55 +02:00
|
|
|
*context = &contexts[i];
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-11-09 17:09:27 +01:00
|
|
|
k_sem_give(&contexts_lock);
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2016-11-15 19:06:22 +01:00
|
|
|
/* FIXME - Figure out a way to get the correct network interface
|
|
|
|
* as it is not known at this point yet.
|
|
|
|
*/
|
2019-04-29 10:32:31 +02:00
|
|
|
if (!ret && IS_ENABLED(CONFIG_NET_OFFLOAD) &&
|
|
|
|
net_if_is_ip_offloaded(net_if_get_default())) {
|
2017-03-09 15:08:19 +01:00
|
|
|
ret = net_offload_get(net_if_get_default(),
|
|
|
|
family,
|
|
|
|
type,
|
|
|
|
ip_proto,
|
|
|
|
context);
|
2016-11-15 19:06:22 +01:00
|
|
|
if (ret < 0) {
|
|
|
|
(*context)->flags &= ~NET_CONTEXT_IN_USE;
|
|
|
|
*context = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-01-26 00:14:59 +01:00
|
|
|
int net_context_ref(struct net_context *context)
|
|
|
|
{
|
|
|
|
int old_rc = atomic_inc(&context->refcount);
|
|
|
|
|
|
|
|
return old_rc + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int net_context_unref(struct net_context *context)
|
|
|
|
{
|
|
|
|
int old_rc = atomic_dec(&context->refcount);
|
|
|
|
|
|
|
|
if (old_rc != 1) {
|
|
|
|
return old_rc - 1;
|
|
|
|
}
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_lock(&context->lock, K_FOREVER);
|
2017-01-26 00:14:59 +01:00
|
|
|
|
2018-03-21 11:14:07 +01:00
|
|
|
net_tcp_unref(context);
|
2017-01-26 00:14:59 +01:00
|
|
|
|
|
|
|
if (context->conn_handler) {
|
2019-06-18 14:35:45 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_TCP) || IS_ENABLED(CONFIG_NET_UDP) ||
|
|
|
|
IS_ENABLED(CONFIG_NET_SOCKETS_CAN)) {
|
2019-04-29 10:32:31 +02:00
|
|
|
net_conn_unregister(context->conn_handler);
|
|
|
|
}
|
|
|
|
|
2017-04-17 07:19:25 +02:00
|
|
|
context->conn_handler = NULL;
|
2017-01-26 00:14:59 +01:00
|
|
|
}
|
|
|
|
|
2017-06-09 13:27:29 +02:00
|
|
|
net_context_set_state(context, NET_CONTEXT_UNCONNECTED);
|
|
|
|
|
2017-01-26 00:14:59 +01:00
|
|
|
context->flags &= ~NET_CONTEXT_IN_USE;
|
|
|
|
|
2017-06-02 14:28:53 +02:00
|
|
|
NET_DBG("Context %p released", context);
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_unlock(&context->lock);
|
2017-01-26 00:14:59 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
int net_context_put(struct net_context *context)
|
|
|
|
{
|
2018-06-28 15:40:10 +02:00
|
|
|
int ret = 0;
|
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
NET_ASSERT(context);
|
|
|
|
|
2016-11-22 19:08:34 +01:00
|
|
|
if (!PART_OF_ARRAY(contexts, context)) {
|
2016-06-22 15:44:55 +02:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_lock(&context->lock, K_FOREVER);
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_OFFLOAD) &&
|
|
|
|
net_if_is_ip_offloaded(net_context_get_iface(context))) {
|
2016-11-15 19:06:22 +01:00
|
|
|
context->flags &= ~NET_CONTEXT_IN_USE;
|
2019-04-29 10:32:31 +02:00
|
|
|
ret = net_offload_put(net_context_get_iface(context), context);
|
2018-06-28 15:40:10 +02:00
|
|
|
goto unlock;
|
2016-11-15 19:06:22 +01:00
|
|
|
}
|
|
|
|
|
2017-01-27 18:34:30 +01:00
|
|
|
context->connect_cb = NULL;
|
|
|
|
context->recv_cb = NULL;
|
|
|
|
context->send_cb = NULL;
|
|
|
|
|
2019-02-22 20:29:32 +01:00
|
|
|
/* Decrement refcount on user app's behalf */
|
2017-01-26 00:14:59 +01:00
|
|
|
net_context_unref(context);
|
2018-06-28 15:40:10 +02:00
|
|
|
|
2019-02-22 20:29:32 +01:00
|
|
|
/* net_tcp_put() will handle decrementing refcount on stack's behalf */
|
|
|
|
net_tcp_put(context);
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&context->lock);
|
|
|
|
|
|
|
|
return ret;
|
2016-06-22 15:44:55 +02:00
|
|
|
}
|
|
|
|
|
2017-07-17 12:51:37 +02:00
|
|
|
/* If local address is not bound, bind it to INADDR_ANY and random port. */
|
|
|
|
static int bind_default(struct net_context *context)
|
|
|
|
{
|
|
|
|
sa_family_t family = net_context_get_family(context);
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) {
|
2017-07-17 12:51:37 +02:00
|
|
|
struct sockaddr_in6 addr6;
|
|
|
|
|
|
|
|
if (net_sin6_ptr(&context->local)->sin6_addr) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr6.sin6_family = AF_INET6;
|
|
|
|
memcpy(&addr6.sin6_addr, net_ipv6_unspecified_address(),
|
|
|
|
sizeof(addr6.sin6_addr));
|
|
|
|
addr6.sin6_port =
|
|
|
|
find_available_port(context,
|
|
|
|
(struct sockaddr *)&addr6);
|
|
|
|
|
|
|
|
return net_context_bind(context, (struct sockaddr *)&addr6,
|
|
|
|
sizeof(addr6));
|
|
|
|
}
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) {
|
2017-07-17 12:51:37 +02:00
|
|
|
struct sockaddr_in addr4;
|
|
|
|
|
|
|
|
if (net_sin_ptr(&context->local)->sin_addr) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr4.sin_family = AF_INET;
|
|
|
|
addr4.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
addr4.sin_port =
|
|
|
|
find_available_port(context,
|
|
|
|
(struct sockaddr *)&addr4);
|
|
|
|
|
|
|
|
return net_context_bind(context, (struct sockaddr *)&addr4,
|
|
|
|
sizeof(addr4));
|
|
|
|
}
|
|
|
|
|
2019-01-28 14:45:28 +01:00
|
|
|
if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) && family == AF_PACKET) {
|
|
|
|
struct sockaddr_ll ll_addr;
|
|
|
|
|
2020-02-28 09:25:18 +01:00
|
|
|
if (net_sll_ptr(&context->local)->sll_addr) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-28 14:45:28 +01:00
|
|
|
ll_addr.sll_family = AF_PACKET;
|
|
|
|
ll_addr.sll_protocol = ETH_P_ALL;
|
|
|
|
ll_addr.sll_ifindex = net_if_get_by_iface(net_if_get_default());
|
|
|
|
|
|
|
|
return net_context_bind(context, (struct sockaddr *)&ll_addr,
|
|
|
|
sizeof(ll_addr));
|
|
|
|
}
|
|
|
|
|
2019-01-24 13:13:42 +01:00
|
|
|
if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) && family == AF_CAN) {
|
|
|
|
struct sockaddr_can can_addr;
|
|
|
|
|
2019-02-04 14:55:23 +01:00
|
|
|
if (context->iface >= 0) {
|
2019-01-24 13:13:42 +01:00
|
|
|
return 0;
|
|
|
|
} else {
|
2019-08-06 16:12:24 +02:00
|
|
|
#if defined(CONFIG_NET_L2_CANBUS_RAW)
|
2019-01-24 13:13:42 +01:00
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
iface = net_if_get_first_by_type(
|
2019-08-06 16:12:24 +02:00
|
|
|
&NET_L2_GET_NAME(CANBUS_RAW));
|
2019-01-24 13:13:42 +01:00
|
|
|
if (!iface) {
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
can_addr.can_ifindex = net_if_get_by_iface(iface);
|
|
|
|
context->iface = can_addr.can_ifindex;
|
|
|
|
#else
|
|
|
|
return -ENOENT;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
can_addr.can_family = AF_CAN;
|
|
|
|
|
|
|
|
return net_context_bind(context, (struct sockaddr *)&can_addr,
|
|
|
|
sizeof(can_addr));
|
|
|
|
}
|
|
|
|
|
2017-07-17 12:51:37 +02:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2016-08-29 09:37:43 +02:00
|
|
|
int net_context_bind(struct net_context *context, const struct sockaddr *addr,
|
|
|
|
socklen_t addrlen)
|
2016-06-22 15:44:55 +02:00
|
|
|
{
|
2016-11-22 19:08:34 +01:00
|
|
|
NET_ASSERT(addr);
|
|
|
|
NET_ASSERT(PART_OF_ARRAY(contexts, context));
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2017-03-01 20:22:25 +01:00
|
|
|
/* If we already have connection handler, then it effectively
|
|
|
|
* means that it's already bound to an interface/port, and we
|
|
|
|
* don't support rebinding connection to new address/port in
|
|
|
|
* the code below.
|
|
|
|
* TODO: Support rebinding.
|
|
|
|
*/
|
|
|
|
if (context->conn_handler) {
|
|
|
|
return -EISCONN;
|
|
|
|
}
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6) && addr->sa_family == AF_INET6) {
|
2017-02-09 16:26:00 +01:00
|
|
|
struct net_if *iface = NULL;
|
2016-06-22 15:44:55 +02:00
|
|
|
struct in6_addr *ptr;
|
|
|
|
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
|
2017-02-04 02:31:12 +01:00
|
|
|
int ret;
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2016-08-29 09:37:43 +02:00
|
|
|
if (addrlen < sizeof(struct sockaddr_in6)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2018-11-02 15:05:58 +01:00
|
|
|
if (net_ipv6_is_addr_mcast(&addr6->sin6_addr)) {
|
2016-06-22 15:44:55 +02:00
|
|
|
struct net_if_mcast_addr *maddr;
|
|
|
|
|
|
|
|
maddr = net_if_ipv6_maddr_lookup(&addr6->sin6_addr,
|
|
|
|
&iface);
|
|
|
|
if (!maddr) {
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = &maddr->address.in6_addr;
|
|
|
|
|
2018-11-02 15:05:58 +01:00
|
|
|
} else if (net_ipv6_is_addr_unspecified(&addr6->sin6_addr)) {
|
2018-09-13 14:06:35 +02:00
|
|
|
iface = net_if_ipv6_select_src_iface(
|
|
|
|
&net_sin6(&context->remote)->sin6_addr);
|
2016-11-04 15:05:16 +01:00
|
|
|
|
|
|
|
ptr = (struct in6_addr *)net_ipv6_unspecified_address();
|
2016-06-22 15:44:55 +02:00
|
|
|
} else {
|
|
|
|
struct net_if_addr *ifaddr;
|
|
|
|
|
|
|
|
ifaddr = net_if_ipv6_addr_lookup(&addr6->sin6_addr,
|
|
|
|
&iface);
|
|
|
|
if (!ifaddr) {
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = &ifaddr->address.in6_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!iface) {
|
2017-02-07 18:05:10 +01:00
|
|
|
NET_ERR("Cannot bind to %s",
|
2018-10-02 13:57:55 +02:00
|
|
|
log_strdup(net_sprint_ipv6_addr(
|
|
|
|
&addr6->sin6_addr)));
|
2016-06-22 15:44:55 +02:00
|
|
|
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
}
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_OFFLOAD) &&
|
|
|
|
net_if_is_ip_offloaded(iface)) {
|
2016-11-15 19:06:22 +01:00
|
|
|
net_context_set_iface(context, iface);
|
|
|
|
|
2017-03-09 15:08:19 +01:00
|
|
|
return net_offload_bind(iface,
|
|
|
|
context,
|
|
|
|
addr,
|
|
|
|
addrlen);
|
2016-11-15 19:06:22 +01:00
|
|
|
}
|
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
net_context_set_iface(context, iface);
|
|
|
|
|
2016-11-23 11:50:24 +01:00
|
|
|
net_sin6_ptr(&context->local)->sin6_family = AF_INET6;
|
2016-08-18 09:08:04 +02:00
|
|
|
net_sin6_ptr(&context->local)->sin6_addr = ptr;
|
2017-02-04 02:31:12 +01:00
|
|
|
if (addr6->sin6_port) {
|
|
|
|
ret = check_used_port(AF_INET6, addr6->sin6_port,
|
|
|
|
addr);
|
|
|
|
if (!ret) {
|
|
|
|
net_sin6_ptr(&context->local)->sin6_port =
|
|
|
|
addr6->sin6_port;
|
|
|
|
} else {
|
|
|
|
NET_ERR("Port %d is in use!",
|
|
|
|
ntohs(addr6->sin6_port));
|
|
|
|
return ret;
|
|
|
|
}
|
2017-03-20 22:54:13 +01:00
|
|
|
} else {
|
|
|
|
addr6->sin6_port =
|
|
|
|
net_sin6_ptr(&context->local)->sin6_port;
|
2017-02-04 02:31:12 +01:00
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2017-03-12 17:15:51 +01:00
|
|
|
NET_DBG("Context %p binding to %s [%s]:%d iface %p",
|
|
|
|
context,
|
2019-02-06 14:16:50 +01:00
|
|
|
net_proto2str(AF_INET6,
|
|
|
|
net_context_get_ip_proto(context)),
|
2018-10-02 13:57:55 +02:00
|
|
|
log_strdup(net_sprint_ipv6_addr(ptr)),
|
|
|
|
ntohs(addr6->sin6_port), iface);
|
2016-06-22 15:44:55 +02:00
|
|
|
|
|
|
|
return 0;
|
2016-05-09 14:49:48 +02:00
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV4) && addr->sa_family == AF_INET) {
|
2016-06-22 15:44:55 +02:00
|
|
|
struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
|
2017-09-21 22:09:38 +02:00
|
|
|
struct net_if *iface = NULL;
|
2016-11-04 15:05:16 +01:00
|
|
|
struct net_if_addr *ifaddr;
|
|
|
|
struct in_addr *ptr;
|
2017-02-04 02:31:12 +01:00
|
|
|
int ret;
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2016-08-29 09:37:43 +02:00
|
|
|
if (addrlen < sizeof(struct sockaddr_in)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2018-11-02 15:05:58 +01:00
|
|
|
if (net_ipv4_is_addr_mcast(&addr4->sin_addr)) {
|
2017-09-21 22:09:38 +02:00
|
|
|
struct net_if_mcast_addr *maddr;
|
|
|
|
|
|
|
|
maddr = net_if_ipv4_maddr_lookup(&addr4->sin_addr,
|
|
|
|
&iface);
|
|
|
|
if (!maddr) {
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = &maddr->address.in_addr;
|
|
|
|
|
|
|
|
} else if (addr4->sin_addr.s_addr == INADDR_ANY) {
|
2018-09-13 14:06:35 +02:00
|
|
|
iface = net_if_ipv4_select_src_iface(
|
|
|
|
&net_sin(&context->remote)->sin_addr);
|
2016-11-04 15:05:16 +01:00
|
|
|
|
|
|
|
ptr = (struct in_addr *)net_ipv4_unspecified_address();
|
|
|
|
} else {
|
|
|
|
ifaddr = net_if_ipv4_addr_lookup(&addr4->sin_addr,
|
|
|
|
&iface);
|
|
|
|
if (!ifaddr) {
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = &ifaddr->address.in_addr;
|
2016-06-22 15:44:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!iface) {
|
2017-02-07 18:05:10 +01:00
|
|
|
NET_ERR("Cannot bind to %s",
|
2018-10-02 13:57:55 +02:00
|
|
|
log_strdup(net_sprint_ipv4_addr(
|
|
|
|
&addr4->sin_addr)));
|
2016-06-22 15:44:55 +02:00
|
|
|
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
}
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_OFFLOAD) &&
|
|
|
|
net_if_is_ip_offloaded(iface)) {
|
2016-11-15 19:06:22 +01:00
|
|
|
net_context_set_iface(context, iface);
|
|
|
|
|
2017-03-09 15:08:19 +01:00
|
|
|
return net_offload_bind(iface,
|
|
|
|
context,
|
|
|
|
addr,
|
|
|
|
addrlen);
|
2016-11-15 19:06:22 +01:00
|
|
|
}
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_lock(&context->lock, K_FOREVER);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
net_context_set_iface(context, iface);
|
|
|
|
|
2016-11-23 11:50:24 +01:00
|
|
|
net_sin_ptr(&context->local)->sin_family = AF_INET;
|
2016-11-04 15:05:16 +01:00
|
|
|
net_sin_ptr(&context->local)->sin_addr = ptr;
|
2017-02-04 02:31:12 +01:00
|
|
|
if (addr4->sin_port) {
|
|
|
|
ret = check_used_port(AF_INET, addr4->sin_port,
|
|
|
|
addr);
|
|
|
|
if (!ret) {
|
|
|
|
net_sin_ptr(&context->local)->sin_port =
|
|
|
|
addr4->sin_port;
|
|
|
|
} else {
|
|
|
|
NET_ERR("Port %d is in use!",
|
|
|
|
ntohs(addr4->sin_port));
|
2018-06-28 15:40:10 +02:00
|
|
|
goto unlock;
|
2017-02-04 02:31:12 +01:00
|
|
|
}
|
2017-03-20 22:54:13 +01:00
|
|
|
} else {
|
|
|
|
addr4->sin_port =
|
|
|
|
net_sin_ptr(&context->local)->sin_port;
|
2017-02-04 02:31:12 +01:00
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2017-03-12 17:15:51 +01:00
|
|
|
NET_DBG("Context %p binding to %s %s:%d iface %p",
|
|
|
|
context,
|
2019-02-06 14:16:50 +01:00
|
|
|
net_proto2str(AF_INET,
|
|
|
|
net_context_get_ip_proto(context)),
|
2018-10-02 13:57:55 +02:00
|
|
|
log_strdup(net_sprint_ipv4_addr(ptr)),
|
2016-06-22 15:44:55 +02:00
|
|
|
ntohs(addr4->sin_port), iface);
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&context->lock);
|
|
|
|
|
|
|
|
return ret;
|
2016-05-09 14:49:48 +02:00
|
|
|
}
|
|
|
|
|
2019-01-28 14:45:28 +01:00
|
|
|
if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
|
|
|
|
addr->sa_family == AF_PACKET) {
|
|
|
|
struct sockaddr_ll *ll_addr = (struct sockaddr_ll *)addr;
|
|
|
|
struct net_if *iface = NULL;
|
|
|
|
|
|
|
|
if (addrlen < sizeof(struct sockaddr_ll)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ll_addr->sll_ifindex < 0) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface = net_if_get_by_index(ll_addr->sll_ifindex);
|
|
|
|
if (!iface) {
|
|
|
|
NET_ERR("Cannot bind to interface index %d",
|
|
|
|
ll_addr->sll_ifindex);
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
}
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_OFFLOAD) &&
|
|
|
|
net_if_is_ip_offloaded(iface)) {
|
2019-01-28 14:45:28 +01:00
|
|
|
net_context_set_iface(context, iface);
|
|
|
|
|
|
|
|
return net_offload_bind(iface,
|
|
|
|
context,
|
|
|
|
addr,
|
|
|
|
addrlen);
|
|
|
|
}
|
|
|
|
|
|
|
|
net_context_set_iface(context, iface);
|
|
|
|
|
|
|
|
net_sll_ptr(&context->local)->sll_family = AF_PACKET;
|
|
|
|
net_sll_ptr(&context->local)->sll_ifindex =
|
|
|
|
ll_addr->sll_ifindex;
|
|
|
|
net_sll_ptr(&context->local)->sll_protocol =
|
|
|
|
ll_addr->sll_protocol;
|
|
|
|
net_sll_ptr(&context->local)->sll_addr =
|
|
|
|
net_if_get_link_addr(iface)->addr;
|
|
|
|
|
|
|
|
NET_DBG("Context %p binding to %d iface[%d] %p addr %s",
|
|
|
|
context, net_context_get_ip_proto(context),
|
|
|
|
ll_addr->sll_ifindex, iface,
|
2020-05-18 17:55:47 +02:00
|
|
|
log_strdup(net_sprint_ll_addr(
|
|
|
|
net_if_get_link_addr(iface)->addr,
|
|
|
|
net_if_get_link_addr(iface)->len)));
|
2019-01-28 14:45:28 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-01-24 13:13:42 +01:00
|
|
|
if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) && addr->sa_family == AF_CAN) {
|
|
|
|
struct sockaddr_can *can_addr = (struct sockaddr_can *)addr;
|
|
|
|
struct net_if *iface = NULL;
|
|
|
|
|
|
|
|
if (addrlen < sizeof(struct sockaddr_can)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (can_addr->can_ifindex < 0) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface = net_if_get_by_index(can_addr->can_ifindex);
|
|
|
|
if (!iface) {
|
|
|
|
NET_ERR("Cannot bind to interface index %d",
|
|
|
|
can_addr->can_ifindex);
|
|
|
|
return -EADDRNOTAVAIL;
|
|
|
|
}
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_OFFLOAD) &&
|
|
|
|
net_if_is_ip_offloaded(iface)) {
|
2019-01-24 13:13:42 +01:00
|
|
|
net_context_set_iface(context, iface);
|
|
|
|
|
|
|
|
return net_offload_bind(iface,
|
|
|
|
context,
|
|
|
|
addr,
|
|
|
|
addrlen);
|
|
|
|
}
|
|
|
|
|
|
|
|
net_context_set_iface(context, iface);
|
|
|
|
net_context_set_family(context, AF_CAN);
|
|
|
|
|
|
|
|
net_can_ptr(&context->local)->can_family = AF_CAN;
|
|
|
|
net_can_ptr(&context->local)->can_ifindex =
|
|
|
|
can_addr->can_ifindex;
|
|
|
|
|
|
|
|
NET_DBG("Context %p binding to %d iface[%d] %p",
|
|
|
|
context, net_context_get_ip_proto(context),
|
|
|
|
can_addr->can_ifindex, iface);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2016-08-18 09:08:04 +02:00
|
|
|
static inline struct net_context *find_context(void *conn_handler)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NET_MAX_CONTEXT; i++) {
|
|
|
|
if (!net_context_is_used(&contexts[i])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (contexts[i].conn_handler == conn_handler) {
|
|
|
|
return &contexts[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
int net_context_listen(struct net_context *context, int backlog)
|
|
|
|
{
|
|
|
|
ARG_UNUSED(backlog);
|
|
|
|
|
2016-11-22 19:08:34 +01:00
|
|
|
NET_ASSERT(PART_OF_ARRAY(contexts, context));
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2016-08-18 09:08:04 +02:00
|
|
|
if (!net_context_is_used(context)) {
|
2017-06-04 13:28:04 +02:00
|
|
|
return -EBADF;
|
2016-08-18 09:08:04 +02:00
|
|
|
}
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_OFFLOAD) &&
|
|
|
|
net_if_is_ip_offloaded(net_context_get_iface(context))) {
|
|
|
|
return net_offload_listen(net_context_get_iface(context),
|
|
|
|
context, backlog);
|
2016-11-15 19:06:22 +01:00
|
|
|
}
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_lock(&context->lock, K_FOREVER);
|
|
|
|
|
2018-03-20 14:06:49 +01:00
|
|
|
if (net_tcp_listen(context) >= 0) {
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_unlock(&context->lock);
|
2016-09-19 20:49:22 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_unlock(&context->lock);
|
|
|
|
|
2016-09-19 20:49:22 +02:00
|
|
|
return -EOPNOTSUPP;
|
2016-08-18 09:08:04 +02:00
|
|
|
}
|
|
|
|
|
2018-06-29 10:33:56 +02:00
|
|
|
#if defined(CONFIG_NET_IPV4)
|
2019-01-14 10:57:42 +01:00
|
|
|
int net_context_create_ipv4_new(struct net_context *context,
|
|
|
|
struct net_pkt *pkt,
|
|
|
|
const struct in_addr *src,
|
|
|
|
const struct in_addr *dst)
|
2018-12-13 14:05:21 +01:00
|
|
|
{
|
|
|
|
if (!src) {
|
2020-04-03 12:55:28 +02:00
|
|
|
NET_ASSERT(((
|
|
|
|
struct sockaddr_in_ptr *)&context->local)->sin_addr);
|
|
|
|
|
2018-12-13 14:05:21 +01:00
|
|
|
src = ((struct sockaddr_in_ptr *)&context->local)->sin_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_ipv4_is_addr_unspecified(src)
|
|
|
|
|| net_ipv4_is_addr_mcast(src)) {
|
|
|
|
src = net_if_ipv4_select_src_addr(net_pkt_iface(pkt),
|
|
|
|
(struct in_addr *)dst);
|
|
|
|
/* If src address is still unspecified, do not create pkt */
|
|
|
|
if (net_ipv4_is_addr_unspecified(src)) {
|
|
|
|
NET_DBG("DROP: src addr is unspecified");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-15 09:45:09 +01:00
|
|
|
net_pkt_set_ipv4_ttl(pkt, net_context_get_ipv4_ttl(context));
|
|
|
|
|
2019-02-20 08:54:58 +01:00
|
|
|
return net_ipv4_create(pkt, src, dst);
|
2018-12-13 14:05:21 +01:00
|
|
|
}
|
2018-06-29 10:33:56 +02:00
|
|
|
#endif /* CONFIG_NET_IPV4 */
|
|
|
|
|
2018-06-29 10:56:15 +02:00
|
|
|
#if defined(CONFIG_NET_IPV6)
|
2019-01-14 10:57:42 +01:00
|
|
|
int net_context_create_ipv6_new(struct net_context *context,
|
|
|
|
struct net_pkt *pkt,
|
|
|
|
const struct in6_addr *src,
|
|
|
|
const struct in6_addr *dst)
|
2018-12-19 15:30:00 +01:00
|
|
|
{
|
|
|
|
if (!src) {
|
2020-04-03 12:55:28 +02:00
|
|
|
NET_ASSERT(((
|
|
|
|
struct sockaddr_in6_ptr *)&context->local)->sin6_addr);
|
|
|
|
|
2018-12-19 15:30:00 +01:00
|
|
|
src = ((struct sockaddr_in6_ptr *)&context->local)->sin6_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (net_ipv6_is_addr_unspecified(src)
|
|
|
|
|| net_ipv6_is_addr_mcast(src)) {
|
|
|
|
src = net_if_ipv6_select_src_addr(net_pkt_iface(pkt),
|
|
|
|
(struct in6_addr *)dst);
|
|
|
|
}
|
|
|
|
|
2019-02-15 09:45:09 +01:00
|
|
|
net_pkt_set_ipv6_hop_limit(pkt,
|
|
|
|
net_context_get_ipv6_hop_limit(context));
|
|
|
|
|
2019-02-20 08:58:08 +01:00
|
|
|
return net_ipv6_create(pkt, src, dst);
|
2018-12-19 15:30:00 +01:00
|
|
|
}
|
2018-06-29 10:56:15 +02:00
|
|
|
#endif /* CONFIG_NET_IPV6 */
|
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
int net_context_connect(struct net_context *context,
|
|
|
|
const struct sockaddr *addr,
|
2016-08-29 09:37:43 +02:00
|
|
|
socklen_t addrlen,
|
2016-06-22 15:44:55 +02:00
|
|
|
net_context_connect_cb_t cb,
|
2020-04-03 09:48:00 +02:00
|
|
|
k_timeout_t timeout,
|
2016-06-22 15:44:55 +02:00
|
|
|
void *user_data)
|
|
|
|
{
|
2016-08-18 09:08:04 +02:00
|
|
|
struct sockaddr *laddr = NULL;
|
2019-04-29 10:32:31 +02:00
|
|
|
struct sockaddr local_addr __unused;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t lport, rport;
|
2017-07-17 12:51:37 +02:00
|
|
|
int ret;
|
2016-08-18 09:08:04 +02:00
|
|
|
|
2016-11-22 19:08:34 +01:00
|
|
|
NET_ASSERT(addr);
|
|
|
|
NET_ASSERT(PART_OF_ARRAY(contexts, context));
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_lock(&context->lock, K_FOREVER);
|
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
if (!net_context_is_used(context)) {
|
2018-06-28 15:40:10 +02:00
|
|
|
ret = -EBADF;
|
|
|
|
goto unlock;
|
2016-06-22 15:44:55 +02:00
|
|
|
}
|
|
|
|
|
2017-08-18 09:03:46 +02:00
|
|
|
if (addr->sa_family != net_context_get_family(context)) {
|
2020-01-08 08:42:23 +01:00
|
|
|
NET_ASSERT(addr->sa_family == net_context_get_family(context),
|
|
|
|
"Family mismatch %d should be %d",
|
|
|
|
addr->sa_family,
|
|
|
|
net_context_get_family(context));
|
2018-06-28 15:40:10 +02:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto unlock;
|
2016-06-22 15:44:55 +02:00
|
|
|
}
|
2016-05-09 14:49:48 +02:00
|
|
|
|
2019-01-28 14:45:28 +01:00
|
|
|
if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
|
|
|
|
addr->sa_family == AF_PACKET) {
|
2020-04-05 18:38:39 +02:00
|
|
|
ret = -EOPNOTSUPP;
|
|
|
|
goto unlock;
|
2019-01-28 14:45:28 +01:00
|
|
|
}
|
|
|
|
|
2016-08-18 09:08:04 +02:00
|
|
|
if (net_context_get_state(context) == NET_CONTEXT_LISTENING) {
|
2018-06-28 15:40:10 +02:00
|
|
|
ret = -EOPNOTSUPP;
|
|
|
|
goto unlock;
|
2016-08-18 09:08:04 +02:00
|
|
|
}
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6) &&
|
|
|
|
net_context_get_family(context) == AF_INET6) {
|
2016-06-22 15:44:55 +02:00
|
|
|
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)
|
|
|
|
&context->remote;
|
|
|
|
|
2016-08-29 09:37:43 +02:00
|
|
|
if (addrlen < sizeof(struct sockaddr_in6)) {
|
2018-06-28 15:40:10 +02:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto unlock;
|
2016-08-29 09:37:43 +02:00
|
|
|
}
|
|
|
|
|
2018-03-20 14:06:51 +01:00
|
|
|
if (net_context_get_ip_proto(context) == IPPROTO_TCP &&
|
2018-11-02 15:05:58 +01:00
|
|
|
net_ipv6_is_addr_mcast(&addr6->sin6_addr)) {
|
2018-06-28 15:40:10 +02:00
|
|
|
ret = -EADDRNOTAVAIL;
|
|
|
|
goto unlock;
|
2016-08-18 09:08:04 +02:00
|
|
|
}
|
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
memcpy(&addr6->sin6_addr, &net_sin6(addr)->sin6_addr,
|
|
|
|
sizeof(struct in6_addr));
|
|
|
|
|
|
|
|
addr6->sin6_port = net_sin6(addr)->sin6_port;
|
|
|
|
addr6->sin6_family = AF_INET6;
|
|
|
|
|
2018-11-02 15:05:58 +01:00
|
|
|
if (!net_ipv6_is_addr_unspecified(&addr6->sin6_addr)) {
|
2016-06-22 15:44:55 +02:00
|
|
|
context->flags |= NET_CONTEXT_REMOTE_ADDR_SET;
|
|
|
|
} else {
|
|
|
|
context->flags &= ~NET_CONTEXT_REMOTE_ADDR_SET;
|
2016-05-09 14:49:48 +02:00
|
|
|
}
|
2016-08-18 09:08:04 +02:00
|
|
|
|
|
|
|
rport = addr6->sin6_port;
|
|
|
|
|
2018-09-13 14:06:35 +02:00
|
|
|
/* The binding must be done after we have set the remote
|
|
|
|
* address but before checking the local address. Otherwise
|
|
|
|
* the laddr might not be set properly which would then cause
|
|
|
|
* issues when doing net_tcp_connect(). This issue was seen
|
|
|
|
* with socket tests and when connecting to loopback interface.
|
|
|
|
*/
|
|
|
|
ret = bind_default(context);
|
|
|
|
if (ret) {
|
2018-06-28 15:40:10 +02:00
|
|
|
goto unlock;
|
2018-09-13 14:06:35 +02:00
|
|
|
}
|
|
|
|
|
2016-08-18 09:08:04 +02:00
|
|
|
net_sin6_ptr(&context->local)->sin6_family = AF_INET6;
|
2017-01-10 18:14:01 +01:00
|
|
|
net_sin6(&local_addr)->sin6_family = AF_INET6;
|
2016-08-18 09:08:04 +02:00
|
|
|
net_sin6(&local_addr)->sin6_port = lport =
|
|
|
|
net_sin6((struct sockaddr *)&context->local)->sin6_port;
|
|
|
|
|
|
|
|
if (net_sin6_ptr(&context->local)->sin6_addr) {
|
|
|
|
net_ipaddr_copy(&net_sin6(&local_addr)->sin6_addr,
|
|
|
|
net_sin6_ptr(&context->local)->sin6_addr);
|
|
|
|
|
|
|
|
laddr = &local_addr;
|
|
|
|
}
|
2019-04-29 10:32:31 +02:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_IPV4) &&
|
|
|
|
net_context_get_family(context) == AF_INET) {
|
2016-06-22 15:44:55 +02:00
|
|
|
struct sockaddr_in *addr4 = (struct sockaddr_in *)
|
|
|
|
&context->remote;
|
|
|
|
|
2016-08-29 09:37:43 +02:00
|
|
|
if (addrlen < sizeof(struct sockaddr_in)) {
|
2018-06-28 15:40:10 +02:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto unlock;
|
2016-08-29 09:37:43 +02:00
|
|
|
}
|
|
|
|
|
2016-08-18 09:08:04 +02:00
|
|
|
/* FIXME - Add multicast and broadcast address check */
|
|
|
|
|
2018-03-21 11:14:07 +01:00
|
|
|
addr4 = (struct sockaddr_in *)&context->remote;
|
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
memcpy(&addr4->sin_addr, &net_sin(addr)->sin_addr,
|
|
|
|
sizeof(struct in_addr));
|
|
|
|
|
|
|
|
addr4->sin_port = net_sin(addr)->sin_port;
|
|
|
|
addr4->sin_family = AF_INET;
|
|
|
|
|
2017-06-12 20:24:12 +02:00
|
|
|
if (addr4->sin_addr.s_addr) {
|
2016-06-22 15:44:55 +02:00
|
|
|
context->flags |= NET_CONTEXT_REMOTE_ADDR_SET;
|
|
|
|
} else {
|
|
|
|
context->flags &= ~NET_CONTEXT_REMOTE_ADDR_SET;
|
|
|
|
}
|
2016-08-18 09:08:04 +02:00
|
|
|
|
|
|
|
rport = addr4->sin_port;
|
|
|
|
|
2018-09-13 14:06:35 +02:00
|
|
|
ret = bind_default(context);
|
|
|
|
if (ret) {
|
2019-02-04 13:49:17 +01:00
|
|
|
goto unlock;
|
2018-09-13 14:06:35 +02:00
|
|
|
}
|
|
|
|
|
2016-08-18 09:08:04 +02:00
|
|
|
net_sin_ptr(&context->local)->sin_family = AF_INET;
|
2017-01-10 18:14:01 +01:00
|
|
|
net_sin(&local_addr)->sin_family = AF_INET;
|
2016-08-18 09:08:04 +02:00
|
|
|
net_sin(&local_addr)->sin_port = lport =
|
|
|
|
net_sin((struct sockaddr *)&context->local)->sin_port;
|
|
|
|
|
|
|
|
if (net_sin_ptr(&context->local)->sin_addr) {
|
|
|
|
net_ipaddr_copy(&net_sin(&local_addr)->sin_addr,
|
|
|
|
net_sin_ptr(&context->local)->sin_addr);
|
|
|
|
|
|
|
|
laddr = &local_addr;
|
|
|
|
}
|
2019-04-29 10:32:31 +02:00
|
|
|
} else {
|
2018-06-28 15:40:10 +02:00
|
|
|
ret = -EINVAL; /* Not IPv4 or IPv6 */
|
|
|
|
goto unlock;
|
2016-05-09 14:49:48 +02:00
|
|
|
}
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_OFFLOAD) &&
|
|
|
|
net_if_is_ip_offloaded(net_context_get_iface(context))) {
|
2019-03-14 03:54:29 +01:00
|
|
|
ret = net_offload_connect(
|
|
|
|
net_context_get_iface(context),
|
|
|
|
context,
|
|
|
|
addr,
|
|
|
|
addrlen,
|
|
|
|
cb,
|
|
|
|
timeout,
|
|
|
|
user_data);
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_UDP) &&
|
|
|
|
net_context_get_type(context) == SOCK_DGRAM) {
|
2016-06-22 15:44:55 +02:00
|
|
|
if (cb) {
|
2017-01-19 15:58:35 +01:00
|
|
|
cb(context, 0, user_data);
|
2016-05-09 14:49:48 +02:00
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
ret = 0;
|
2019-04-29 10:32:31 +02:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_TCP) &&
|
|
|
|
net_context_get_type(context) == SOCK_STREAM) {
|
2018-06-28 15:40:10 +02:00
|
|
|
ret = net_tcp_connect(context, addr, laddr, rport, lport,
|
|
|
|
timeout, cb, user_data);
|
2019-04-29 10:32:31 +02:00
|
|
|
} else {
|
2018-06-28 15:40:10 +02:00
|
|
|
ret = -ENOTSUP;
|
2016-08-18 09:08:04 +02:00
|
|
|
}
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&context->lock);
|
|
|
|
|
|
|
|
return ret;
|
2016-08-18 09:08:04 +02:00
|
|
|
}
|
2017-01-26 00:14:59 +01:00
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
int net_context_accept(struct net_context *context,
|
2017-01-19 23:53:41 +01:00
|
|
|
net_tcp_accept_cb_t cb,
|
2020-04-03 09:48:00 +02:00
|
|
|
k_timeout_t timeout,
|
2016-06-22 15:44:55 +02:00
|
|
|
void *user_data)
|
2016-05-09 14:49:48 +02:00
|
|
|
{
|
2018-06-28 15:40:10 +02:00
|
|
|
int ret = 0;
|
|
|
|
|
2016-11-22 19:08:34 +01:00
|
|
|
NET_ASSERT(PART_OF_ARRAY(contexts, context));
|
2016-06-22 15:44:55 +02:00
|
|
|
|
|
|
|
if (!net_context_is_used(context)) {
|
2017-06-04 13:28:04 +02:00
|
|
|
return -EBADF;
|
2016-05-09 14:49:48 +02:00
|
|
|
}
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_lock(&context->lock, K_FOREVER);
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_OFFLOAD) &&
|
|
|
|
net_if_is_ip_offloaded(net_context_get_iface(context))) {
|
2018-06-28 15:40:10 +02:00
|
|
|
ret = net_offload_accept(
|
2016-11-15 19:06:22 +01:00
|
|
|
net_context_get_iface(context),
|
|
|
|
context,
|
|
|
|
cb,
|
|
|
|
timeout,
|
|
|
|
user_data);
|
2018-06-28 15:40:10 +02:00
|
|
|
goto unlock;
|
2016-11-15 19:06:22 +01:00
|
|
|
}
|
|
|
|
|
2016-08-18 09:08:04 +02:00
|
|
|
if ((net_context_get_state(context) != NET_CONTEXT_LISTENING) &&
|
2016-06-22 15:44:55 +02:00
|
|
|
(net_context_get_type(context) != SOCK_STREAM)) {
|
2016-08-18 09:08:04 +02:00
|
|
|
NET_DBG("Invalid socket, state %d type %d",
|
|
|
|
net_context_get_state(context),
|
|
|
|
net_context_get_type(context));
|
2018-06-28 15:40:10 +02:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto unlock;
|
2016-06-22 15:44:55 +02:00
|
|
|
}
|
2016-05-09 14:49:48 +02:00
|
|
|
|
2017-01-19 23:53:41 +01:00
|
|
|
if (net_context_get_ip_proto(context) == IPPROTO_TCP) {
|
2018-06-28 15:40:10 +02:00
|
|
|
ret = net_tcp_accept(context, cb, user_data);
|
|
|
|
goto unlock;
|
2017-01-19 23:53:41 +01:00
|
|
|
}
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&context->lock);
|
|
|
|
|
|
|
|
return ret;
|
2016-06-22 15:44:55 +02:00
|
|
|
}
|
|
|
|
|
2016-11-14 22:37:41 +01:00
|
|
|
|
2019-03-07 09:23:25 +01:00
|
|
|
static int get_context_priority(struct net_context *context,
|
|
|
|
void *value, size_t *len)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_NET_CONTEXT_PRIORITY)
|
2020-05-27 18:26:57 +02:00
|
|
|
*((uint8_t *)value) = context->options.priority;
|
2019-03-07 09:23:25 +01:00
|
|
|
|
|
|
|
if (len) {
|
2020-05-27 18:26:57 +02:00
|
|
|
*len = sizeof(uint8_t);
|
2019-03-07 09:23:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
return -ENOTSUP;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-03-07 11:20:43 +01:00
|
|
|
static int get_context_timepstamp(struct net_context *context,
|
|
|
|
void *value, size_t *len)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_NET_CONTEXT_TIMESTAMP)
|
|
|
|
*((bool *)value) = context->options.timestamp;
|
|
|
|
|
|
|
|
if (len) {
|
|
|
|
*len = sizeof(bool);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
return -ENOTSUP;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-01 15:00:54 +02:00
|
|
|
static int get_context_proxy(struct net_context *context,
|
|
|
|
void *value, size_t *len)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_SOCKS)
|
|
|
|
struct sockaddr *addr = (struct sockaddr *)value;
|
|
|
|
|
|
|
|
if (!value || !len) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*len < context->options.proxy.addrlen) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*len = MIN(context->options.proxy.addrlen, *len);
|
|
|
|
|
|
|
|
memcpy(addr, &context->options.proxy.addr, *len);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
return -ENOTSUP;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-05-30 12:32:07 +02:00
|
|
|
#if defined(CONFIG_NET_CONTEXT_TIMESTAMP)
|
|
|
|
int net_context_get_timestamp(struct net_context *context,
|
|
|
|
struct net_pkt *pkt,
|
|
|
|
struct net_ptp_time *timestamp)
|
|
|
|
{
|
|
|
|
bool is_timestamped;
|
|
|
|
|
|
|
|
get_context_timepstamp(context, &is_timestamped, NULL);
|
|
|
|
if (is_timestamped) {
|
|
|
|
memcpy(timestamp, net_pkt_timestamp(pkt), sizeof(*timestamp));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_CONTEXT_TIMESTAMP */
|
|
|
|
|
2019-06-27 16:57:01 +02:00
|
|
|
static int get_context_txtime(struct net_context *context,
|
|
|
|
void *value, size_t *len)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_NET_CONTEXT_TXTIME)
|
|
|
|
*((bool *)value) = context->options.txtime;
|
|
|
|
|
|
|
|
if (len) {
|
|
|
|
*len = sizeof(bool);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
return -ENOTSUP;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-06-27 16:48:10 +02:00
|
|
|
/* If buf is not NULL, then use it. Otherwise read the data to be written
|
|
|
|
* to net_pkt from msghdr.
|
|
|
|
*/
|
|
|
|
static int context_write_data(struct net_pkt *pkt, const void *buf,
|
|
|
|
int buf_len, const struct msghdr *msghdr)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (msghdr) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < msghdr->msg_iovlen; i++) {
|
|
|
|
ret = net_pkt_write(pkt, msghdr->msg_iov[i].iov_base,
|
|
|
|
msghdr->msg_iov[i].iov_len);
|
|
|
|
if (ret < 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ret = net_pkt_write(pkt, buf, buf_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-12-13 14:05:21 +01:00
|
|
|
static int context_setup_udp_packet(struct net_context *context,
|
|
|
|
struct net_pkt *pkt,
|
|
|
|
const void *buf,
|
|
|
|
size_t len,
|
2019-06-27 16:48:10 +02:00
|
|
|
const struct msghdr *msg,
|
2018-12-13 14:05:21 +01:00
|
|
|
const struct sockaddr *dst_addr,
|
|
|
|
socklen_t addrlen)
|
|
|
|
{
|
|
|
|
int ret = -EINVAL;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t dst_port = 0U;
|
2018-12-13 14:05:21 +01:00
|
|
|
|
2019-05-02 21:18:39 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6) &&
|
|
|
|
net_context_get_family(context) == AF_INET6) {
|
2018-12-19 15:30:00 +01:00
|
|
|
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)dst_addr;
|
|
|
|
|
|
|
|
dst_port = addr6->sin6_port;
|
|
|
|
|
2019-01-14 10:57:42 +01:00
|
|
|
ret = net_context_create_ipv6_new(context, pkt,
|
|
|
|
NULL, &addr6->sin6_addr);
|
2019-05-02 21:18:39 +02:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_IPV4) &&
|
|
|
|
net_context_get_family(context) == AF_INET) {
|
|
|
|
struct sockaddr_in *addr4 = (struct sockaddr_in *)dst_addr;
|
|
|
|
|
|
|
|
dst_port = addr4->sin_port;
|
|
|
|
|
|
|
|
ret = net_context_create_ipv4_new(context, pkt,
|
|
|
|
NULL, &addr4->sin_addr);
|
2018-12-13 14:05:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = bind_default(context);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = net_udp_create(pkt,
|
|
|
|
net_sin((struct sockaddr *)
|
|
|
|
&context->local)->sin_port,
|
|
|
|
dst_port);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-06-27 16:48:10 +02:00
|
|
|
ret = context_write_data(pkt, buf, len, msg);
|
2018-12-13 14:05:21 +01:00
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-02-11 09:10:13 +01:00
|
|
|
return 0;
|
2018-12-13 14:05:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void context_finalize_packet(struct net_context *context,
|
|
|
|
struct net_pkt *pkt)
|
|
|
|
{
|
|
|
|
/* This function is meant to be temporary: once all moved to new
|
|
|
|
* API, it will be up to net_send_data() to finalize the packet.
|
|
|
|
*/
|
|
|
|
|
|
|
|
net_pkt_cursor_init(pkt);
|
|
|
|
|
2019-05-02 21:18:39 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6) &&
|
|
|
|
net_context_get_family(context) == AF_INET6) {
|
2019-02-01 21:29:39 +01:00
|
|
|
net_ipv6_finalize(pkt, net_context_get_ip_proto(context));
|
2019-05-02 21:18:39 +02:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_IPV4) &&
|
|
|
|
net_context_get_family(context) == AF_INET) {
|
|
|
|
net_ipv4_finalize(pkt, net_context_get_ip_proto(context));
|
2018-12-13 14:05:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-08 10:43:30 +01:00
|
|
|
static struct net_pkt *context_alloc_pkt(struct net_context *context,
|
2020-04-03 09:48:00 +02:00
|
|
|
size_t len, k_timeout_t timeout)
|
2019-03-08 10:43:30 +01:00
|
|
|
{
|
|
|
|
struct net_pkt *pkt;
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_CONTEXT_NET_PKT_POOL)
|
|
|
|
if (context->tx_slab) {
|
|
|
|
pkt = net_pkt_alloc_from_slab(context->tx_slab(), timeout);
|
|
|
|
if (!pkt) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_pkt_set_iface(pkt, net_context_get_iface(context));
|
|
|
|
net_pkt_set_family(pkt, net_context_get_family(context));
|
|
|
|
net_pkt_set_context(pkt, context);
|
|
|
|
|
|
|
|
if (net_pkt_alloc_buffer(pkt, len,
|
|
|
|
net_context_get_ip_proto(context),
|
|
|
|
timeout)) {
|
|
|
|
net_pkt_unref(pkt);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pkt;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
pkt = net_pkt_alloc_with_buffer(net_context_get_iface(context), len,
|
|
|
|
net_context_get_family(context),
|
|
|
|
net_context_get_ip_proto(context),
|
|
|
|
timeout);
|
2019-03-20 15:10:04 +01:00
|
|
|
if (pkt) {
|
|
|
|
net_pkt_set_context(pkt, context);
|
|
|
|
}
|
2019-03-08 10:43:30 +01:00
|
|
|
|
|
|
|
return pkt;
|
|
|
|
}
|
|
|
|
|
2019-06-27 16:57:01 +02:00
|
|
|
static void set_pkt_txtime(struct net_pkt *pkt, const struct msghdr *msghdr)
|
|
|
|
{
|
|
|
|
struct cmsghdr *cmsg;
|
|
|
|
|
|
|
|
for (cmsg = CMSG_FIRSTHDR(msghdr); cmsg != NULL;
|
|
|
|
cmsg = CMSG_NXTHDR(msghdr, cmsg)) {
|
2020-05-27 18:26:57 +02:00
|
|
|
if (cmsg->cmsg_len == CMSG_LEN(sizeof(uint64_t)) &&
|
2019-06-27 16:57:01 +02:00
|
|
|
cmsg->cmsg_level == SOL_SOCKET &&
|
|
|
|
cmsg->cmsg_type == SCM_TXTIME) {
|
2020-05-27 18:26:57 +02:00
|
|
|
uint64_t txtime = *(uint64_t *)CMSG_DATA(cmsg);
|
2019-06-27 16:57:01 +02:00
|
|
|
|
|
|
|
net_pkt_set_txtime(pkt, txtime);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-03-08 10:43:30 +01:00
|
|
|
|
2019-02-20 08:48:36 +01:00
|
|
|
static int context_sendto(struct net_context *context,
|
|
|
|
const void *buf,
|
|
|
|
size_t len,
|
|
|
|
const struct sockaddr *dst_addr,
|
|
|
|
socklen_t addrlen,
|
|
|
|
net_context_send_cb_t cb,
|
2020-04-03 09:48:00 +02:00
|
|
|
k_timeout_t timeout,
|
2019-02-07 09:45:03 +01:00
|
|
|
void *user_data,
|
|
|
|
bool sendto)
|
2018-12-13 14:05:21 +01:00
|
|
|
{
|
2019-06-27 16:48:10 +02:00
|
|
|
const struct msghdr *msghdr = NULL;
|
2018-12-13 14:05:21 +01:00
|
|
|
struct net_pkt *pkt;
|
2019-02-11 09:10:13 +01:00
|
|
|
size_t tmp_len;
|
2018-12-13 14:05:21 +01:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
NET_ASSERT(PART_OF_ARRAY(contexts, context));
|
|
|
|
|
|
|
|
if (!net_context_is_used(context)) {
|
|
|
|
return -EBADF;
|
|
|
|
}
|
|
|
|
|
2019-06-27 16:48:10 +02:00
|
|
|
if (sendto && addrlen == 0 && dst_addr == NULL && buf != NULL) {
|
|
|
|
/* User wants to call sendmsg */
|
|
|
|
msghdr = buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!msghdr && !dst_addr &&
|
2019-01-24 13:13:42 +01:00
|
|
|
!(IS_ENABLED(CONFIG_NET_SOCKETS_CAN) &&
|
|
|
|
net_context_get_ip_proto(context) == CAN_RAW)) {
|
2018-12-13 14:05:21 +01:00
|
|
|
return -EDESTADDRREQ;
|
|
|
|
}
|
|
|
|
|
2019-05-02 21:18:39 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6) &&
|
|
|
|
net_context_get_family(context) == AF_INET6) {
|
2019-07-23 17:23:48 +02:00
|
|
|
const struct sockaddr_in6 *addr6 =
|
|
|
|
(const struct sockaddr_in6 *)dst_addr;
|
2018-12-13 14:05:21 +01:00
|
|
|
|
2019-06-27 16:48:10 +02:00
|
|
|
if (msghdr) {
|
|
|
|
addr6 = msghdr->msg_name;
|
|
|
|
addrlen = msghdr->msg_namelen;
|
|
|
|
|
2019-08-08 10:20:08 +02:00
|
|
|
if (!addr6) {
|
2019-08-06 12:16:59 +02:00
|
|
|
addr6 = net_sin6(&context->remote);
|
|
|
|
addrlen = sizeof(struct sockaddr_in6);
|
2019-06-27 16:48:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* For sendmsg(), the dst_addr is NULL so set it here.
|
|
|
|
*/
|
|
|
|
dst_addr = (const struct sockaddr *)addr6;
|
|
|
|
}
|
|
|
|
|
2019-05-02 21:18:39 +02:00
|
|
|
if (addrlen < sizeof(struct sockaddr_in6)) {
|
2018-12-13 14:05:21 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2019-05-02 21:18:39 +02:00
|
|
|
if (net_ipv6_is_addr_unspecified(&addr6->sin6_addr)) {
|
2018-12-13 14:05:21 +01:00
|
|
|
return -EDESTADDRREQ;
|
|
|
|
}
|
2019-05-02 21:18:39 +02:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_IPV4) &&
|
|
|
|
net_context_get_family(context) == AF_INET) {
|
2019-07-23 17:23:48 +02:00
|
|
|
const struct sockaddr_in *addr4 =
|
|
|
|
(const struct sockaddr_in *)dst_addr;
|
2018-12-19 15:30:00 +01:00
|
|
|
|
2019-06-27 16:48:10 +02:00
|
|
|
if (msghdr) {
|
|
|
|
addr4 = msghdr->msg_name;
|
|
|
|
addrlen = msghdr->msg_namelen;
|
|
|
|
|
2019-08-08 10:20:08 +02:00
|
|
|
if (!addr4) {
|
2019-08-06 12:16:59 +02:00
|
|
|
addr4 = net_sin(&context->remote);
|
|
|
|
addrlen = sizeof(struct sockaddr_in);
|
2019-06-27 16:48:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* For sendmsg(), the dst_addr is NULL so set it here.
|
|
|
|
*/
|
|
|
|
dst_addr = (const struct sockaddr *)addr4;
|
|
|
|
}
|
|
|
|
|
2019-05-02 21:18:39 +02:00
|
|
|
if (addrlen < sizeof(struct sockaddr_in)) {
|
2018-12-19 15:30:00 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2019-05-02 21:18:39 +02:00
|
|
|
if (!addr4->sin_addr.s_addr) {
|
2018-12-19 15:30:00 +01:00
|
|
|
return -EDESTADDRREQ;
|
|
|
|
}
|
2019-01-28 14:45:28 +01:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
|
|
|
|
net_context_get_family(context) == AF_PACKET) {
|
|
|
|
struct sockaddr_ll *ll_addr = (struct sockaddr_ll *)dst_addr;
|
|
|
|
struct net_if *iface;
|
|
|
|
|
2020-05-18 17:57:46 +02:00
|
|
|
if (msghdr) {
|
|
|
|
ll_addr = msghdr->msg_name;
|
|
|
|
addrlen = msghdr->msg_namelen;
|
|
|
|
|
|
|
|
if (!ll_addr) {
|
|
|
|
ll_addr = (struct sockaddr_ll *)
|
|
|
|
(&context->remote);
|
|
|
|
addrlen = sizeof(struct sockaddr_ll);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* For sendmsg(), the dst_addr is NULL so set it here.
|
|
|
|
*/
|
|
|
|
dst_addr = (const struct sockaddr *)ll_addr;
|
|
|
|
}
|
|
|
|
|
2019-01-28 14:45:28 +01:00
|
|
|
if (addrlen < sizeof(struct sockaddr_ll)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ll_addr->sll_ifindex < 0) {
|
|
|
|
return -EDESTADDRREQ;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface = net_if_get_by_index(ll_addr->sll_ifindex);
|
|
|
|
if (!iface) {
|
|
|
|
NET_ERR("Cannot bind to interface index %d",
|
|
|
|
ll_addr->sll_ifindex);
|
|
|
|
return -EDESTADDRREQ;
|
|
|
|
}
|
2019-01-24 13:13:42 +01:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) &&
|
|
|
|
net_context_get_family(context) == AF_CAN) {
|
|
|
|
struct sockaddr_can *can_addr = (struct sockaddr_can *)dst_addr;
|
|
|
|
struct net_if *iface;
|
|
|
|
|
|
|
|
if (addrlen < sizeof(struct sockaddr_can)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (can_addr->can_ifindex < 0) {
|
|
|
|
/* The index should have been set in bind */
|
|
|
|
can_addr->can_ifindex =
|
|
|
|
net_can_ptr(&context->local)->can_ifindex;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (can_addr->can_ifindex < 0) {
|
|
|
|
return -EDESTADDRREQ;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface = net_if_get_by_index(can_addr->can_ifindex);
|
|
|
|
if (!iface) {
|
|
|
|
NET_ERR("Cannot bind to interface index %d",
|
|
|
|
can_addr->can_ifindex);
|
|
|
|
return -EDESTADDRREQ;
|
|
|
|
}
|
2018-12-13 14:05:21 +01:00
|
|
|
} else {
|
|
|
|
NET_DBG("Invalid protocol family %d",
|
|
|
|
net_context_get_family(context));
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2019-06-27 16:48:10 +02:00
|
|
|
if (msghdr && len == 0) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < msghdr->msg_iovlen; i++) {
|
|
|
|
len += msghdr->msg_iov[i].iov_len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-08 10:43:30 +01:00
|
|
|
pkt = context_alloc_pkt(context, len, PKT_WAIT_TIME);
|
2018-12-13 14:05:21 +01:00
|
|
|
if (!pkt) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2019-02-11 09:10:13 +01:00
|
|
|
tmp_len = net_pkt_available_payload_buffer(
|
|
|
|
pkt, net_context_get_ip_proto(context));
|
|
|
|
if (tmp_len < len) {
|
|
|
|
len = tmp_len;
|
|
|
|
}
|
|
|
|
|
2018-12-13 14:05:21 +01:00
|
|
|
context->send_cb = cb;
|
|
|
|
context->user_data = user_data;
|
|
|
|
|
2019-03-07 09:23:25 +01:00
|
|
|
if (IS_ENABLED(CONFIG_NET_CONTEXT_PRIORITY)) {
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t priority;
|
2019-03-07 09:23:25 +01:00
|
|
|
|
|
|
|
get_context_priority(context, &priority, NULL);
|
|
|
|
net_pkt_set_priority(pkt, priority);
|
|
|
|
}
|
|
|
|
|
2019-03-07 11:20:43 +01:00
|
|
|
if (IS_ENABLED(CONFIG_NET_CONTEXT_TIMESTAMP)) {
|
|
|
|
bool timestamp;
|
|
|
|
|
|
|
|
get_context_timepstamp(context, ×tamp, NULL);
|
|
|
|
if (timestamp) {
|
|
|
|
struct net_ptp_time tp = {
|
2019-05-30 12:32:07 +02:00
|
|
|
/* Use the nanosecond field to temporarily
|
|
|
|
* store the cycle count as it is a 32-bit
|
|
|
|
* variable. The value is checked in
|
|
|
|
* net_if.c:net_if_tx()
|
|
|
|
*
|
|
|
|
* The net_pkt timestamp field is used in two
|
|
|
|
* roles here:
|
|
|
|
* 1) To calculate how long it takes the packet
|
|
|
|
* from net_context to be sent by the
|
|
|
|
* network device driver.
|
|
|
|
* 2) gPTP enabled Ethernet device driver will
|
|
|
|
* use the value to tell gPTP what time the
|
|
|
|
* packet was sent.
|
|
|
|
*
|
|
|
|
* Because these two things are happening at
|
|
|
|
* different times, we can share the variable.
|
|
|
|
*/
|
|
|
|
.nanosecond = k_cycle_get_32(),
|
2019-03-07 11:20:43 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
net_pkt_set_timestamp(pkt, &tp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-27 16:57:01 +02:00
|
|
|
/* If there is ancillary data in msghdr, then we need to add that
|
|
|
|
* to net_pkt as there is no other way to store it.
|
|
|
|
*/
|
|
|
|
if (msghdr && msghdr->msg_control && msghdr->msg_controllen) {
|
|
|
|
if (IS_ENABLED(CONFIG_NET_CONTEXT_TXTIME)) {
|
|
|
|
bool is_txtime;
|
|
|
|
|
|
|
|
get_context_txtime(context, &is_txtime, NULL);
|
|
|
|
if (is_txtime) {
|
|
|
|
set_pkt_txtime(pkt, msghdr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-07 09:45:03 +01:00
|
|
|
if (IS_ENABLED(CONFIG_NET_OFFLOAD) &&
|
|
|
|
net_if_is_ip_offloaded(net_context_get_iface(context))) {
|
2019-06-27 16:48:10 +02:00
|
|
|
ret = context_write_data(pkt, buf, len, msghdr);
|
2019-02-07 09:45:03 +01:00
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_pkt_cursor_init(pkt);
|
|
|
|
|
|
|
|
if (sendto) {
|
|
|
|
ret = net_offload_sendto(net_context_get_iface(context),
|
|
|
|
pkt, dst_addr, addrlen, cb,
|
|
|
|
timeout, user_data);
|
|
|
|
} else {
|
|
|
|
ret = net_offload_send(net_context_get_iface(context),
|
|
|
|
pkt, cb, timeout, user_data);
|
|
|
|
}
|
|
|
|
} else if (IS_ENABLED(CONFIG_NET_UDP) &&
|
2018-12-13 14:05:21 +01:00
|
|
|
net_context_get_ip_proto(context) == IPPROTO_UDP) {
|
2019-06-27 16:48:10 +02:00
|
|
|
ret = context_setup_udp_packet(context, pkt, buf, len, msghdr,
|
2018-12-13 14:05:21 +01:00
|
|
|
dst_addr, addrlen);
|
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
context_finalize_packet(context, pkt);
|
|
|
|
|
|
|
|
ret = net_send_data(pkt);
|
|
|
|
} else if (IS_ENABLED(CONFIG_NET_TCP) &&
|
|
|
|
net_context_get_ip_proto(context) == IPPROTO_TCP) {
|
2019-10-19 09:08:06 +02:00
|
|
|
|
2019-06-27 16:48:10 +02:00
|
|
|
ret = context_write_data(pkt, buf, len, msghdr);
|
2019-01-18 09:03:14 +01:00
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_pkt_cursor_init(pkt);
|
|
|
|
ret = net_tcp_queue_data(context, pkt);
|
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2019-02-21 10:15:21 +01:00
|
|
|
ret = net_tcp_send_data(context, cb, user_data);
|
2019-01-28 14:45:28 +01:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
|
|
|
|
net_context_get_family(context) == AF_PACKET) {
|
2019-06-27 16:48:10 +02:00
|
|
|
ret = context_write_data(pkt, buf, len, msghdr);
|
2019-01-28 14:45:28 +01:00
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_pkt_cursor_init(pkt);
|
|
|
|
|
|
|
|
net_if_queue_tx(net_pkt_iface(pkt), pkt);
|
2019-01-24 13:13:42 +01:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) &&
|
|
|
|
net_context_get_family(context) == AF_CAN &&
|
|
|
|
net_context_get_ip_proto(context) == CAN_RAW) {
|
2019-06-27 16:48:10 +02:00
|
|
|
ret = context_write_data(pkt, buf, len, msghdr);
|
2019-01-24 13:13:42 +01:00
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_pkt_cursor_init(pkt);
|
|
|
|
|
|
|
|
ret = net_send_data(pkt);
|
2018-12-13 14:05:21 +01:00
|
|
|
} else {
|
|
|
|
NET_DBG("Unknown protocol while sending packet: %d",
|
|
|
|
net_context_get_ip_proto(context));
|
|
|
|
ret = -EPROTONOSUPPORT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2019-02-11 09:10:13 +01:00
|
|
|
return len;
|
2018-12-13 14:05:21 +01:00
|
|
|
fail:
|
|
|
|
net_pkt_unref(pkt);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-02-20 08:48:36 +01:00
|
|
|
int net_context_send(struct net_context *context,
|
|
|
|
const void *buf,
|
|
|
|
size_t len,
|
|
|
|
net_context_send_cb_t cb,
|
2020-04-03 09:48:00 +02:00
|
|
|
k_timeout_t timeout,
|
2019-02-20 08:48:36 +01:00
|
|
|
void *user_data)
|
2018-12-13 14:05:21 +01:00
|
|
|
{
|
|
|
|
socklen_t addrlen;
|
2019-02-04 11:14:12 +01:00
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
k_mutex_lock(&context->lock, K_FOREVER);
|
2018-12-13 14:05:21 +01:00
|
|
|
|
|
|
|
if (!(context->flags & NET_CONTEXT_REMOTE_ADDR_SET) ||
|
|
|
|
!net_sin(&context->remote)->sin_port) {
|
2019-02-04 11:14:12 +01:00
|
|
|
ret = -EDESTADDRREQ;
|
|
|
|
goto unlock;
|
2018-12-13 14:05:21 +01:00
|
|
|
}
|
|
|
|
|
2019-05-02 21:18:39 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6) &&
|
|
|
|
net_context_get_family(context) == AF_INET6) {
|
2018-12-13 14:05:21 +01:00
|
|
|
addrlen = sizeof(struct sockaddr_in6);
|
2019-05-02 21:18:39 +02:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_IPV4) &&
|
|
|
|
net_context_get_family(context) == AF_INET) {
|
|
|
|
addrlen = sizeof(struct sockaddr_in);
|
2019-01-28 14:45:28 +01:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
|
|
|
|
net_context_get_family(context) == AF_PACKET) {
|
|
|
|
ret = -EOPNOTSUPP;
|
|
|
|
goto unlock;
|
2019-01-24 13:13:42 +01:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) &&
|
|
|
|
net_context_get_family(context) == AF_CAN) {
|
|
|
|
addrlen = sizeof(struct sockaddr_can);
|
2018-12-13 14:05:21 +01:00
|
|
|
} else {
|
|
|
|
addrlen = 0;
|
|
|
|
}
|
|
|
|
|
2019-02-20 08:48:36 +01:00
|
|
|
ret = context_sendto(context, buf, len, &context->remote,
|
2019-02-07 09:45:03 +01:00
|
|
|
addrlen, cb, timeout, user_data, false);
|
2019-02-04 11:14:12 +01:00
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&context->lock);
|
|
|
|
|
|
|
|
return ret;
|
2018-12-13 14:05:21 +01:00
|
|
|
}
|
|
|
|
|
2019-06-27 16:48:10 +02:00
|
|
|
int net_context_sendmsg(struct net_context *context,
|
|
|
|
const struct msghdr *msghdr,
|
|
|
|
int flags,
|
|
|
|
net_context_send_cb_t cb,
|
2020-04-03 09:48:00 +02:00
|
|
|
k_timeout_t timeout,
|
2019-06-27 16:48:10 +02:00
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
k_mutex_lock(&context->lock, K_FOREVER);
|
|
|
|
|
|
|
|
ret = context_sendto(context, msghdr, 0, NULL, 0,
|
|
|
|
cb, timeout, user_data, true);
|
|
|
|
|
|
|
|
k_mutex_unlock(&context->lock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2018-12-13 14:05:21 +01:00
|
|
|
|
2019-02-20 08:48:36 +01:00
|
|
|
int net_context_sendto(struct net_context *context,
|
|
|
|
const void *buf,
|
|
|
|
size_t len,
|
|
|
|
const struct sockaddr *dst_addr,
|
|
|
|
socklen_t addrlen,
|
|
|
|
net_context_send_cb_t cb,
|
2020-04-03 09:48:00 +02:00
|
|
|
k_timeout_t timeout,
|
2019-02-20 08:48:36 +01:00
|
|
|
void *user_data)
|
2018-12-13 14:05:21 +01:00
|
|
|
{
|
2019-02-04 11:14:12 +01:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
k_mutex_lock(&context->lock, K_FOREVER);
|
|
|
|
|
2019-02-20 08:48:36 +01:00
|
|
|
ret = context_sendto(context, buf, len, dst_addr, addrlen,
|
2019-02-07 09:45:03 +01:00
|
|
|
cb, timeout, user_data, true);
|
2019-02-04 11:14:12 +01:00
|
|
|
|
|
|
|
k_mutex_unlock(&context->lock);
|
|
|
|
|
|
|
|
return ret;
|
2018-12-13 14:05:21 +01:00
|
|
|
}
|
|
|
|
|
2018-03-21 11:14:07 +01:00
|
|
|
enum net_verdict net_context_packet_received(struct net_conn *conn,
|
|
|
|
struct net_pkt *pkt,
|
2019-01-30 10:07:10 +01:00
|
|
|
union net_ip_header *ip_hdr,
|
|
|
|
union net_proto_header *proto_hdr,
|
2018-03-21 11:14:07 +01:00
|
|
|
void *user_data)
|
2016-06-22 15:44:55 +02:00
|
|
|
{
|
|
|
|
struct net_context *context = find_context(conn);
|
2018-06-28 15:40:10 +02:00
|
|
|
enum net_verdict verdict = NET_DROP;
|
2016-06-22 15:44:55 +02:00
|
|
|
|
|
|
|
NET_ASSERT(context);
|
2017-04-05 08:37:44 +02:00
|
|
|
NET_ASSERT(net_pkt_iface(pkt));
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_lock(&context->lock, K_FOREVER);
|
|
|
|
|
2017-04-05 08:37:44 +02:00
|
|
|
net_context_set_iface(context, net_pkt_iface(pkt));
|
|
|
|
net_pkt_set_context(pkt, context);
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2017-03-07 13:12:28 +01:00
|
|
|
/* If there is no callback registered, then we can only drop
|
|
|
|
* the packet.
|
|
|
|
*/
|
|
|
|
if (!context->recv_cb) {
|
2018-06-28 15:40:10 +02:00
|
|
|
goto unlock;
|
2017-03-07 13:12:28 +01:00
|
|
|
}
|
|
|
|
|
2019-01-24 13:13:42 +01:00
|
|
|
if (net_context_get_ip_proto(context) == IPPROTO_TCP) {
|
2018-03-27 10:31:31 +02:00
|
|
|
net_stats_update_tcp_recv(net_pkt_iface(pkt),
|
2019-02-19 10:25:17 +01:00
|
|
|
net_pkt_remaining_data(pkt));
|
2017-03-07 13:12:28 +01:00
|
|
|
}
|
2017-11-13 13:28:22 +01:00
|
|
|
|
2019-01-30 10:25:03 +01:00
|
|
|
context->recv_cb(context, pkt, ip_hdr, proto_hdr, 0, user_data);
|
2016-06-22 15:44:55 +02:00
|
|
|
|
|
|
|
#if defined(CONFIG_NET_CONTEXT_SYNC_RECV)
|
2017-03-07 13:12:28 +01:00
|
|
|
k_sem_give(&context->recv_data_wait);
|
2016-06-22 15:44:55 +02:00
|
|
|
#endif /* CONFIG_NET_CONTEXT_SYNC_RECV */
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
verdict = NET_OK;
|
|
|
|
|
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&context->lock);
|
|
|
|
|
|
|
|
return verdict;
|
2016-06-22 15:44:55 +02:00
|
|
|
}
|
|
|
|
|
2016-11-17 20:00:15 +01:00
|
|
|
#if defined(CONFIG_NET_UDP)
|
2016-11-17 00:08:23 +01:00
|
|
|
static int recv_udp(struct net_context *context,
|
|
|
|
net_context_recv_cb_t cb,
|
2020-04-03 09:48:00 +02:00
|
|
|
k_timeout_t timeout,
|
2016-11-17 00:08:23 +01:00
|
|
|
void *user_data)
|
2016-06-22 15:44:55 +02:00
|
|
|
{
|
|
|
|
struct sockaddr local_addr = {
|
2017-08-18 09:03:46 +02:00
|
|
|
.sa_family = net_context_get_family(context),
|
2016-06-22 15:44:55 +02:00
|
|
|
};
|
|
|
|
struct sockaddr *laddr = NULL;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t lport = 0U;
|
2016-06-22 15:44:55 +02:00
|
|
|
int ret;
|
|
|
|
|
2016-12-20 20:15:00 +01:00
|
|
|
ARG_UNUSED(timeout);
|
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
if (context->conn_handler) {
|
|
|
|
net_conn_unregister(context->conn_handler);
|
|
|
|
context->conn_handler = NULL;
|
|
|
|
}
|
|
|
|
|
2017-08-11 05:31:12 +02:00
|
|
|
ret = bind_default(context);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6) &&
|
|
|
|
net_context_get_family(context) == AF_INET6) {
|
2016-08-18 09:08:04 +02:00
|
|
|
if (net_sin6_ptr(&context->local)->sin6_addr) {
|
2016-06-22 15:44:55 +02:00
|
|
|
net_ipaddr_copy(&net_sin6(&local_addr)->sin6_addr,
|
2016-08-18 09:08:04 +02:00
|
|
|
net_sin6_ptr(&context->local)->sin6_addr);
|
2016-06-22 15:44:55 +02:00
|
|
|
|
|
|
|
laddr = &local_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_sin6(&local_addr)->sin6_port =
|
|
|
|
net_sin6((struct sockaddr *)&context->local)->sin6_port;
|
2016-08-22 21:51:07 +02:00
|
|
|
lport = net_sin6((struct sockaddr *)&context->local)->sin6_port;
|
2019-04-29 10:32:31 +02:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_IPV4) &&
|
|
|
|
net_context_get_family(context) == AF_INET) {
|
2016-08-18 09:08:04 +02:00
|
|
|
if (net_sin_ptr(&context->local)->sin_addr) {
|
2016-06-22 15:44:55 +02:00
|
|
|
net_ipaddr_copy(&net_sin(&local_addr)->sin_addr,
|
2016-08-18 09:08:04 +02:00
|
|
|
net_sin_ptr(&context->local)->sin_addr);
|
2016-06-22 15:44:55 +02:00
|
|
|
|
|
|
|
laddr = &local_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
lport = net_sin((struct sockaddr *)&context->local)->sin_port;
|
|
|
|
}
|
|
|
|
|
|
|
|
context->recv_cb = cb;
|
|
|
|
|
|
|
|
ret = net_conn_register(net_context_get_ip_proto(context),
|
2019-01-28 14:45:28 +01:00
|
|
|
net_context_get_family(context),
|
2016-06-22 15:44:55 +02:00
|
|
|
context->flags & NET_CONTEXT_REMOTE_ADDR_SET ?
|
|
|
|
&context->remote : NULL,
|
|
|
|
laddr,
|
|
|
|
ntohs(net_sin(&context->remote)->sin_port),
|
|
|
|
ntohs(lport),
|
2018-03-21 11:14:07 +01:00
|
|
|
net_context_packet_received,
|
2016-06-22 15:44:55 +02:00
|
|
|
user_data,
|
|
|
|
&context->conn_handler);
|
2016-11-17 00:08:23 +01:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2019-04-29 10:32:31 +02:00
|
|
|
#else
|
|
|
|
#define recv_udp(...) 0
|
2016-11-17 20:00:15 +01:00
|
|
|
#endif /* CONFIG_NET_UDP */
|
2016-11-17 00:08:23 +01:00
|
|
|
|
2019-01-28 14:45:28 +01:00
|
|
|
static enum net_verdict net_context_raw_packet_received(
|
|
|
|
struct net_conn *conn,
|
|
|
|
struct net_pkt *pkt,
|
|
|
|
union net_ip_header *ip_hdr,
|
|
|
|
union net_proto_header *proto_hdr,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
struct net_context *context = find_context(conn);
|
|
|
|
|
|
|
|
NET_ASSERT(context);
|
|
|
|
NET_ASSERT(net_pkt_iface(pkt));
|
|
|
|
|
|
|
|
/* If there is no callback registered, then we can only drop
|
|
|
|
* the packet.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!context->recv_cb) {
|
|
|
|
return NET_DROP;
|
|
|
|
}
|
|
|
|
|
|
|
|
net_context_set_iface(context, net_pkt_iface(pkt));
|
|
|
|
net_pkt_set_context(pkt, context);
|
|
|
|
|
|
|
|
context->recv_cb(context, pkt, ip_hdr, proto_hdr, 0, user_data);
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_CONTEXT_SYNC_RECV)
|
|
|
|
k_sem_give(&context->recv_data_wait);
|
|
|
|
#endif /* CONFIG_NET_CONTEXT_SYNC_RECV */
|
|
|
|
|
|
|
|
return NET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int recv_raw(struct net_context *context,
|
|
|
|
net_context_recv_cb_t cb,
|
2020-04-03 09:48:00 +02:00
|
|
|
k_timeout_t timeout,
|
2019-02-27 15:45:18 +01:00
|
|
|
struct sockaddr *local_addr,
|
2019-01-28 14:45:28 +01:00
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ARG_UNUSED(timeout);
|
|
|
|
|
|
|
|
context->recv_cb = cb;
|
|
|
|
|
|
|
|
if (context->conn_handler) {
|
|
|
|
net_conn_unregister(context->conn_handler);
|
|
|
|
context->conn_handler = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = bind_default(context);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = net_conn_register(net_context_get_ip_proto(context),
|
|
|
|
net_context_get_family(context),
|
2019-02-27 15:45:18 +01:00
|
|
|
NULL, local_addr, 0, 0,
|
2019-01-28 14:45:28 +01:00
|
|
|
net_context_raw_packet_received,
|
|
|
|
user_data,
|
|
|
|
&context->conn_handler);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-11-17 00:08:23 +01:00
|
|
|
int net_context_recv(struct net_context *context,
|
|
|
|
net_context_recv_cb_t cb,
|
2020-04-03 09:48:00 +02:00
|
|
|
k_timeout_t timeout,
|
2016-11-17 00:08:23 +01:00
|
|
|
void *user_data)
|
|
|
|
{
|
2018-03-20 14:06:45 +01:00
|
|
|
int ret;
|
2016-11-17 00:08:23 +01:00
|
|
|
NET_ASSERT(context);
|
|
|
|
|
|
|
|
if (!net_context_is_used(context)) {
|
2017-06-04 13:28:04 +02:00
|
|
|
return -EBADF;
|
2016-11-17 00:08:23 +01:00
|
|
|
}
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_lock(&context->lock, K_FOREVER);
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_OFFLOAD) &&
|
|
|
|
net_if_is_ip_offloaded(net_context_get_iface(context))) {
|
2018-06-28 15:40:10 +02:00
|
|
|
ret = net_offload_recv(
|
2016-11-15 19:06:22 +01:00
|
|
|
net_context_get_iface(context),
|
|
|
|
context, cb, timeout, user_data);
|
2018-06-28 15:40:10 +02:00
|
|
|
goto unlock;
|
2016-11-15 19:06:22 +01:00
|
|
|
}
|
|
|
|
|
2019-04-29 10:32:31 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_UDP) &&
|
|
|
|
net_context_get_ip_proto(context) == IPPROTO_UDP) {
|
2018-03-20 14:06:45 +01:00
|
|
|
ret = recv_udp(context, cb, timeout, user_data);
|
2019-04-29 10:32:31 +02:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_TCP) &&
|
|
|
|
net_context_get_ip_proto(context) == IPPROTO_TCP) {
|
2018-03-20 14:06:45 +01:00
|
|
|
ret = net_tcp_recv(context, cb, user_data);
|
2019-04-29 10:32:31 +02:00
|
|
|
} else {
|
2019-01-28 14:45:28 +01:00
|
|
|
if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
|
|
|
|
net_context_get_family(context) == AF_PACKET) {
|
2020-02-28 09:25:18 +01:00
|
|
|
struct sockaddr_ll addr;
|
|
|
|
|
|
|
|
addr.sll_family = AF_PACKET;
|
|
|
|
addr.sll_ifindex =
|
|
|
|
net_sll_ptr(&context->local)->sll_ifindex;
|
|
|
|
addr.sll_protocol =
|
|
|
|
net_sll_ptr(&context->local)->sll_protocol;
|
|
|
|
memcpy(addr.sll_addr,
|
|
|
|
net_sll_ptr(&context->local)->sll_addr,
|
|
|
|
sizeof(addr.sll_addr));
|
|
|
|
|
|
|
|
ret = recv_raw(context, cb, timeout,
|
|
|
|
(struct sockaddr *)&addr, user_data);
|
2019-04-29 10:32:31 +02:00
|
|
|
} else if (IS_ENABLED(CONFIG_NET_SOCKETS_CAN) &&
|
|
|
|
net_context_get_family(context) == AF_CAN) {
|
2019-02-27 15:45:18 +01:00
|
|
|
struct sockaddr_can local_addr = {
|
|
|
|
.can_family = AF_CAN,
|
|
|
|
};
|
|
|
|
|
|
|
|
ret = recv_raw(context, cb, timeout,
|
|
|
|
(struct sockaddr *)&local_addr,
|
|
|
|
user_data);
|
2019-02-12 15:22:06 +01:00
|
|
|
if (ret == -EALREADY) {
|
|
|
|
/* This is perfectly normal for CAN sockets.
|
|
|
|
* The SocketCAN will dispatch the packet to
|
|
|
|
* correct net_context listener.
|
|
|
|
*/
|
|
|
|
ret = 0;
|
|
|
|
}
|
2019-04-29 10:32:31 +02:00
|
|
|
} else {
|
|
|
|
ret = -EPROTOTYPE;
|
2019-01-24 13:13:42 +01:00
|
|
|
}
|
2018-03-20 14:06:45 +01:00
|
|
|
}
|
2016-11-22 22:27:31 +01:00
|
|
|
|
2018-03-20 14:06:45 +01:00
|
|
|
if (ret < 0) {
|
2018-06-28 15:40:10 +02:00
|
|
|
goto unlock;
|
2016-06-22 15:44:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_CONTEXT_SYNC_RECV)
|
2020-04-03 09:48:00 +02:00
|
|
|
if (!K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
|
2017-10-26 18:57:57 +02:00
|
|
|
int ret;
|
|
|
|
|
2018-03-21 11:14:07 +01:00
|
|
|
/* Make sure we have the lock, then the
|
|
|
|
* net_context_packet_received() callback will release the
|
|
|
|
* semaphore when data has been received.
|
2016-06-22 15:44:55 +02:00
|
|
|
*/
|
2017-10-26 18:57:57 +02:00
|
|
|
k_sem_reset(&context->recv_data_wait);
|
2016-06-22 15:44:55 +02:00
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_unlock(&context->lock);
|
|
|
|
|
2017-10-26 18:57:57 +02:00
|
|
|
ret = k_sem_take(&context->recv_data_wait, timeout);
|
2018-06-28 15:40:10 +02:00
|
|
|
|
|
|
|
k_mutex_lock(&context->lock, K_FOREVER);
|
|
|
|
|
2017-10-26 18:57:57 +02:00
|
|
|
if (ret == -EAGAIN) {
|
2018-06-28 15:40:10 +02:00
|
|
|
ret = -ETIMEDOUT;
|
|
|
|
goto unlock;
|
2016-06-22 15:44:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NET_CONTEXT_SYNC_RECV */
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&context->lock);
|
|
|
|
|
|
|
|
return ret;
|
2016-06-22 15:44:55 +02:00
|
|
|
}
|
|
|
|
|
2017-04-28 21:05:29 +02:00
|
|
|
int net_context_update_recv_wnd(struct net_context *context,
|
2020-05-27 18:26:57 +02:00
|
|
|
int32_t delta)
|
2018-06-28 15:40:10 +02:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2019-09-05 04:30:41 +02:00
|
|
|
if (IS_ENABLED(CONFIG_NET_OFFLOAD) &&
|
|
|
|
net_if_is_ip_offloaded(net_context_get_iface(context))) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_lock(&context->lock, K_FOREVER);
|
|
|
|
|
|
|
|
ret = net_tcp_update_recv_wnd(context, delta);
|
|
|
|
|
|
|
|
k_mutex_unlock(&context->lock);
|
|
|
|
|
|
|
|
return ret;
|
2017-04-28 21:05:29 +02:00
|
|
|
}
|
2018-02-07 13:44:04 +01:00
|
|
|
|
|
|
|
static int set_context_priority(struct net_context *context,
|
|
|
|
const void *value, size_t len)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_NET_CONTEXT_PRIORITY)
|
2020-05-27 18:26:57 +02:00
|
|
|
if (len > sizeof(uint8_t)) {
|
2018-02-07 13:44:04 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
context->options.priority = *((uint8_t *)value);
|
2018-02-07 13:44:04 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
return -ENOTSUP;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-03-07 11:20:43 +01:00
|
|
|
static int set_context_timestamp(struct net_context *context,
|
|
|
|
const void *value, size_t len)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_NET_CONTEXT_TIMESTAMP)
|
|
|
|
if (len > sizeof(bool)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
context->options.timestamp = *((bool *)value);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
return -ENOTSUP;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-06-27 16:57:01 +02:00
|
|
|
static int set_context_txtime(struct net_context *context,
|
|
|
|
const void *value, size_t len)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_NET_CONTEXT_TXTIME)
|
|
|
|
if (len > sizeof(bool)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
context->options.txtime = *((bool *)value);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
return -ENOTSUP;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-01 15:00:54 +02:00
|
|
|
static int set_context_proxy(struct net_context *context,
|
|
|
|
const void *value, size_t len)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_SOCKS)
|
|
|
|
struct sockaddr *addr = (struct sockaddr *)value;
|
|
|
|
|
|
|
|
if (len > NET_SOCKADDR_MAX_SIZE) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr->sa_family != net_context_get_family(context)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
context->options.proxy.addrlen = len;
|
|
|
|
memcpy(&context->options.proxy.addr, addr, len);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
return -ENOTSUP;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-02-07 13:44:04 +01:00
|
|
|
int net_context_set_option(struct net_context *context,
|
|
|
|
enum net_context_option option,
|
|
|
|
const void *value, size_t len)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
NET_ASSERT(context);
|
|
|
|
|
|
|
|
if (!PART_OF_ARRAY(contexts, context)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_lock(&context->lock, K_FOREVER);
|
|
|
|
|
2018-02-07 13:44:04 +01:00
|
|
|
switch (option) {
|
|
|
|
case NET_OPT_PRIORITY:
|
|
|
|
ret = set_context_priority(context, value, len);
|
|
|
|
break;
|
2019-03-07 11:20:43 +01:00
|
|
|
case NET_OPT_TIMESTAMP:
|
|
|
|
ret = set_context_timestamp(context, value, len);
|
|
|
|
break;
|
2019-06-27 16:57:01 +02:00
|
|
|
case NET_OPT_TXTIME:
|
|
|
|
ret = set_context_txtime(context, value, len);
|
|
|
|
break;
|
2019-08-01 15:00:54 +02:00
|
|
|
case NET_OPT_SOCKS5:
|
|
|
|
ret = set_context_proxy(context, value, len);
|
|
|
|
break;
|
2018-02-07 13:44:04 +01:00
|
|
|
}
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_unlock(&context->lock);
|
|
|
|
|
2018-02-07 13:44:04 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int net_context_get_option(struct net_context *context,
|
|
|
|
enum net_context_option option,
|
|
|
|
void *value, size_t *len)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
NET_ASSERT(context);
|
|
|
|
|
|
|
|
if (!PART_OF_ARRAY(contexts, context)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_lock(&context->lock, K_FOREVER);
|
|
|
|
|
2018-02-07 13:44:04 +01:00
|
|
|
switch (option) {
|
|
|
|
case NET_OPT_PRIORITY:
|
|
|
|
ret = get_context_priority(context, value, len);
|
|
|
|
break;
|
2019-03-07 11:20:43 +01:00
|
|
|
case NET_OPT_TIMESTAMP:
|
|
|
|
ret = get_context_timepstamp(context, value, len);
|
|
|
|
break;
|
2019-06-27 16:57:01 +02:00
|
|
|
case NET_OPT_TXTIME:
|
|
|
|
ret = get_context_txtime(context, value, len);
|
|
|
|
break;
|
2019-08-01 15:00:54 +02:00
|
|
|
case NET_OPT_SOCKS5:
|
|
|
|
ret = get_context_proxy(context, value, len);
|
|
|
|
break;
|
2018-02-07 13:44:04 +01:00
|
|
|
}
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_unlock(&context->lock);
|
|
|
|
|
2018-02-07 13:44:04 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-11-23 11:48:33 +01:00
|
|
|
void net_context_foreach(net_context_cb_t cb, void *user_data)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
k_sem_take(&contexts_lock, K_FOREVER);
|
|
|
|
|
|
|
|
for (i = 0; i < NET_MAX_CONTEXT; i++) {
|
|
|
|
if (!net_context_is_used(&contexts[i])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-06-28 15:40:10 +02:00
|
|
|
k_mutex_lock(&contexts[i].lock, K_FOREVER);
|
|
|
|
|
2016-11-23 11:48:33 +01:00
|
|
|
cb(&contexts[i], user_data);
|
2018-06-28 15:40:10 +02:00
|
|
|
|
|
|
|
k_mutex_unlock(&contexts[i].lock);
|
2016-11-23 11:48:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
k_sem_give(&contexts_lock);
|
|
|
|
}
|
|
|
|
|
2016-06-22 15:44:55 +02:00
|
|
|
void net_context_init(void)
|
|
|
|
{
|
2017-07-27 19:59:06 +02:00
|
|
|
k_sem_init(&contexts_lock, 1, UINT_MAX);
|
2016-05-09 14:49:48 +02:00
|
|
|
}
|