<commit_before>/** @file
 * @brief Network context API
 *
 * An API for applications to define a network connection.
 */

/*
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#if defined(CONFIG_NET_DEBUG_CONTEXT)
#define SYS_LOG_DOMAIN "net/ctx"
#define NET_LOG_ENABLED 1
#endif

#include <kernel.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h>

#include <net/nbuf.h>
#include <net/net_ip.h>
#include <net/net_context.h>
#include <net/offload_ip.h>

#include "connection.h"
#include "net_private.h"

#include "ipv6.h"
#include "ipv4.h"
#include "udp.h"
#include "tcp.h"

#define NET_MAX_CONTEXT CONFIG_NET_MAX_CONTEXTS

static struct net_context contexts[NET_MAX_CONTEXT];

/* We need to lock the contexts array as these APIs are typically called
 * from applications which are usually run in task context.
 */
static struct k_sem contexts_lock;

enum net_verdict packet_received(struct net_conn *conn,
				 struct net_buf *buf,
				 void *user_data);

static void set_appdata_values(struct net_buf *buf,
			       enum net_ip_protocol proto,
			       size_t total_len);

#if defined(CONFIG_NET_TCP)
static struct sockaddr *create_sockaddr(struct net_buf *buf,
					struct sockaddr *addr)
{
#if defined(CONFIG_NET_IPV6)
	if (net_nbuf_family(buf) == AF_INET6) {
		net_ipaddr_copy(&net_sin6(addr)->sin6_addr,
				&NET_IPV6_BUF(buf)->src);
		net_sin6(addr)->sin6_port = NET_TCP_BUF(buf)->src_port;
		net_sin6(addr)->sin6_family = AF_INET6;
	} else
#endif

#if defined(CONFIG_NET_IPV4)
	if (net_nbuf_family(buf) == AF_INET) {
		net_ipaddr_copy(&net_sin(addr)->sin_addr,
				&NET_IPV4_BUF(buf)->src);
		net_sin(addr)->sin_port = NET_TCP_BUF(buf)->src_port;
		net_sin(addr)->sin_family = AF_INET;
	} else
#endif
	{
		return NULL;
	}

	return addr;
}
#endif

int net_context_get(sa_family_t family,
		    enum net_sock_type type,
		    enum net_ip_protocol ip_proto,
		    struct net_context **context)
{
	int i, ret = -ENOENT;

#if defined(CONFIG_NET_CONTEXT_CHECK)

#if !defined(CONFIG_NET_IPV4)
	if (family == AF_INET) {
		NET_ASSERT_INFO(family != AF_INET, "IPv4 disabled");
		return -EPFNOSUPPORT;
	}
#endif

#if !defined(CONFIG_NET_IPV6)
	if (family == AF_INET6) {
		NET_ASSERT_INFO(family != AF_INET6, "IPv6 disabled");
		return -EPFNOSUPPORT;
	}
#endif

#if !defined(CONFIG_NET_UDP)
	if (type == SOCK_DGRAM) {
		NET_ASSERT_INFO(type != SOCK_DGRAM,
				"Datagram context disabled");
		return -EPROTOTYPE;
	}

	if (ip_proto == IPPROTO_UDP) {
		NET_ASSERT_INFO(ip_proto != IPPROTO_UDP, "UDP disabled");
		return -EPROTONOSUPPORT;
	}
#endif

#if !defined(CONFIG_NET_TCP)
	if (type == SOCK_STREAM) {
		NET_ASSERT_INFO(type != SOCK_STREAM,
				"Stream context disabled");
		return -EPROTOTYPE;
	}

	if (ip_proto == IPPROTO_TCP) {
		NET_ASSERT_INFO(ip_proto != IPPROTO_TCP, "TCP disabled");
		return -EPROTONOSUPPORT;
	}
#endif

	if (family != AF_INET && family != AF_INET6) {
		NET_ASSERT_INFO(family == AF_INET || family == AF_INET6,
				"Unknown address family %d", family);
		return -EAFNOSUPPORT;
	}

	if (type != SOCK_DGRAM && type != SOCK_STREAM) {
		NET_ASSERT_INFO(type == SOCK_DGRAM || type == SOCK_STREAM,
				"Unknown context type");
		return -EPROTOTYPE;
	}

	if (ip_proto != IPPROTO_UDP && ip_proto != IPPROTO_TCP) {
		NET_ASSERT_INFO(ip_proto == IPPROTO_UDP ||
				ip_proto == IPPROTO_TCP,
				"Unknown IP protocol %d", ip_proto);
		return -EPROTONOSUPPORT;
	}

	if ((type == SOCK_STREAM && ip_proto == IPPROTO_UDP) ||
	    (type == SOCK_DGRAM && ip_proto == IPPROTO_TCP)) {
		NET_ASSERT_INFO(\
			(type != SOCK_STREAM || ip_proto != IPPROTO_UDP) &&
			(type != SOCK_DGRAM || ip_proto != IPPROTO_TCP),
			"Context type and protocol mismatch, type %d proto %d",
			type, ip_proto);
		return -EOPNOTSUPP;
	}

	if (!context) {
		NET_ASSERT_INFO(context, "Invalid context");
		return -EINVAL;
	}
#endif /* CONFIG_NET_CONTEXT_CHECK */

	k_sem_take(&contexts_lock, K_FOREVER);

	for (i = 0; i < NET_MAX_CONTEXT; i++) {
		if (net_context_is_used(&contexts[i])) {
			continue;
		}

#if defined(CONFIG_NET_TCP)
		if (ip_proto == IPPROTO_TCP) {
			contexts[i].tcp = net_tcp_alloc(&contexts[i]);
			if (!contexts[i].tcp) {
				NET_ASSERT_INFO(contexts[i].tcp,
						"Cannot allocate TCP context");
				return -ENOBUFS;
			}
		}
#endif /* CONFIG_NET_TCP */

		contexts[i].flags = 0;

		net_context_set_family(&contexts[i], family);
		net_context_set_type(&contexts[i], type);
		net_context_set_ip_proto(&contexts[i], ip_proto);

		contexts[i].flags |= NET_CONTEXT_IN_USE;
		contexts[i].iface = 0;

		memset(&contexts[i].remote, 0, sizeof(struct sockaddr));
		memset(&contexts[i].local, 0, sizeof(struct sockaddr_ptr));

#if defined(CONFIG_NET_CONTEXT_SYNC_RECV)
		k_sem_init(&contexts[i].recv_data_wait, 0, UINT_MAX);
		k_sem_give(&contexts[i].recv_data_wait);
#endif /* CONFIG_NET_CONTEXT_SYNC_RECV */

		*context = &contexts[i];

		ret = 0;
		break;
	}

	k_sem_give(&contexts_lock);

#if defined(CONFIG_NET_L2_OFFLOAD_IP)
	/* FIXME - Figure out a way to get the correct network interface
	 * as it is not known at this point yet.
	 */
	if (!ret && net_if_is_ip_offloaded(net_if_get_default())) {
		ret = net_l2_offload_ip_get(net_if_get_default(),
					    family,
					    type,
					    ip_proto,
					    context);
		if (ret < 0) {
			(*context)->flags &= ~NET_CONTEXT_IN_USE;
			*context = NULL;
		}

		return ret;
	}
#endif /* CONFIG_NET_L2_OFFLOAD_IP */

	return ret;
}

#if defined(CONFIG_NET_TCP)
static inline int send_fin(struct net_context *context,
			   struct sockaddr *remote);
static enum net_verdict tcp_active_close(struct net_conn *conn,
					 struct net_buf *buf,
					 void *user_data);

static bool send_fin_if_active_close(struct net_context *context)
{
	NET_ASSERT(context->tcp);

	switch (context->tcp->state) {
	case NET_TCP_SYN_RCVD:
	case NET_TCP_ESTABLISHED:
		/* Sending a packet with the FIN flag automatically
		 * transitions to FIN_WAIT_1
		 */
		send_fin(context, &context->remote);
		net_conn_change_callback(context->conn_handler,
					 tcp_active_close, context);
		return true;
	default:
		net_tcp_release(context->tcp);
		return false;
	}
}
#endif /* CONFIG_NET_TCP */

int net_context_put(struct net_context *context)
{
	NET_ASSERT(context);

	if (!PART_OF_ARRAY(contexts, context)) {
		return -EINVAL;
	}

	k_sem_take(&contexts_lock, K_FOREVER);

#if defined(CONFIG_NET_L2_OFFLOAD_IP)
	if (net_if_is_ip_offloaded(net_context_get_iface(context))) {
		context->flags &= ~NET_CONTEXT_IN_USE;
		return net_l2_offload_ip_put(
			net_context_get_iface(context), context);
	}
#endif /* CONFIG_NET_L2_OFFLOAD_IP */

#if defined(CONFIG_NET_TCP)
	if (net_context_get_ip_proto(context) == IPPROTO_TCP) {
		if (send_fin_if_active_close(context)) {
			NET_DBG("TCP connection in active close, not "
				"disposing yet");
			goto still_in_use;
		}
	}
#endif /* CONFIG_NET_TCP */

	if (context->conn_handler) {
		net_conn_unregister(context->conn_handler);
	}

	context->flags &= ~NET_CONTEXT_IN_USE;

#if defined(CONFIG_NET_TCP)
still_in_use:
#endif /* CONFIG_NET_TCP */

	k_sem_give(&contexts_lock);

	return 0;
}<commit_msg>net: tcp: Destroy net_tcp struct at the same time as the context<commit_after>/** @file
 * @brief Network context API
 *
 * An API for applications to define a network connection.
 */

/*
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#if defined(CONFIG_NET_DEBUG_CONTEXT)
#define SYS_LOG_DOMAIN "net/ctx"
#define NET_LOG_ENABLED 1
#endif

#include <kernel.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h>

#include <net/nbuf.h>
#include <net/net_ip.h>
#include <net/net_context.h>
#include <net/offload_ip.h>

#include "connection.h"
#include "net_private.h"

#include "ipv6.h"
#include "ipv4.h"
#include "udp.h"
#include "tcp.h"

#define NET_MAX_CONTEXT CONFIG_NET_MAX_CONTEXTS

static struct net_context contexts[NET_MAX_CONTEXT];

/* We need to lock the contexts array as these APIs are typically called
 * from applications which are usually run in task context.
 */
static struct k_sem contexts_lock;

enum net_verdict packet_received(struct net_conn *conn,
				 struct net_buf *buf,
				 void *user_data);

static void set_appdata_values(struct net_buf *buf,
			       enum net_ip_protocol proto,
			       size_t total_len);

#if defined(CONFIG_NET_TCP)
static struct sockaddr *create_sockaddr(struct net_buf *buf,
					struct sockaddr *addr)
{
#if defined(CONFIG_NET_IPV6)
	if (net_nbuf_family(buf) == AF_INET6) {
		net_ipaddr_copy(&net_sin6(addr)->sin6_addr,
				&NET_IPV6_BUF(buf)->src);
		net_sin6(addr)->sin6_port = NET_TCP_BUF(buf)->src_port;
		net_sin6(addr)->sin6_family = AF_INET6;
	} else
#endif

#if defined(CONFIG_NET_IPV4)
	if (net_nbuf_family(buf) == AF_INET) {
		net_ipaddr_copy(&net_sin(addr)->sin_addr,
				&NET_IPV4_BUF(buf)->src);
		net_sin(addr)->sin_port = NET_TCP_BUF(buf)->src_port;
		net_sin(addr)->sin_family = AF_INET;
	} else
#endif
	{
		return NULL;
	}

	return addr;
}
#endif

int net_context_get(sa_family_t family,
		    enum net_sock_type type,
		    enum net_ip_protocol ip_proto,
		    struct net_context **context)
{
	int i, ret = -ENOENT;

#if defined(CONFIG_NET_CONTEXT_CHECK)

#if !defined(CONFIG_NET_IPV4)
	if (family == AF_INET) {
		NET_ASSERT_INFO(family != AF_INET, "IPv4 disabled");
		return -EPFNOSUPPORT;
	}
#endif

#if !defined(CONFIG_NET_IPV6)
	if (family == AF_INET6) {
		NET_ASSERT_INFO(family != AF_INET6, "IPv6 disabled");
		return -EPFNOSUPPORT;
	}
#endif

#if !defined(CONFIG_NET_UDP)
	if (type == SOCK_DGRAM) {
		NET_ASSERT_INFO(type != SOCK_DGRAM,
				"Datagram context disabled");
		return -EPROTOTYPE;
	}

	if (ip_proto == IPPROTO_UDP) {
		NET_ASSERT_INFO(ip_proto != IPPROTO_UDP, "UDP disabled");
		return -EPROTONOSUPPORT;
	}
#endif

#if !defined(CONFIG_NET_TCP)
	if (type == SOCK_STREAM) {
		NET_ASSERT_INFO(type != SOCK_STREAM,
				"Stream context disabled");
		return -EPROTOTYPE;
	}

	if (ip_proto == IPPROTO_TCP) {
		NET_ASSERT_INFO(ip_proto != IPPROTO_TCP, "TCP disabled");
		return -EPROTONOSUPPORT;
	}
#endif

	if (family != AF_INET && family != AF_INET6) {
		NET_ASSERT_INFO(family == AF_INET || family == AF_INET6,
				"Unknown address family %d", family);
		return -EAFNOSUPPORT;
	}

	if (type != SOCK_DGRAM && type != SOCK_STREAM) {
		NET_ASSERT_INFO(type == SOCK_DGRAM || type == SOCK_STREAM,
				"Unknown context type");
		return -EPROTOTYPE;
	}

	if (ip_proto != IPPROTO_UDP && ip_proto != IPPROTO_TCP) {
		NET_ASSERT_INFO(ip_proto == IPPROTO_UDP ||
				ip_proto == IPPROTO_TCP,
				"Unknown IP protocol %d", ip_proto);
		return -EPROTONOSUPPORT;
	}

	if ((type == SOCK_STREAM && ip_proto == IPPROTO_UDP) ||
	    (type == SOCK_DGRAM && ip_proto == IPPROTO_TCP)) {
		NET_ASSERT_INFO(\
			(type != SOCK_STREAM || ip_proto != IPPROTO_UDP) &&
			(type != SOCK_DGRAM || ip_proto != IPPROTO_TCP),
			"Context type and protocol mismatch, type %d proto %d",
			type, ip_proto);
		return -EOPNOTSUPP;
	}

	if (!context) {
		NET_ASSERT_INFO(context, "Invalid context");
		return -EINVAL;
	}
#endif /* CONFIG_NET_CONTEXT_CHECK */

	k_sem_take(&contexts_lock, K_FOREVER);

	for (i = 0; i < NET_MAX_CONTEXT; i++) {
		if (net_context_is_used(&contexts[i])) {
			continue;
		}

#if defined(CONFIG_NET_TCP)
		if (ip_proto == IPPROTO_TCP) {
			contexts[i].tcp = net_tcp_alloc(&contexts[i]);
			if (!contexts[i].tcp) {
				NET_ASSERT_INFO(contexts[i].tcp,
						"Cannot allocate TCP context");
				return -ENOBUFS;
			}
		}
#endif /* CONFIG_NET_TCP */

		contexts[i].flags = 0;

		net_context_set_family(&contexts[i], family);
		net_context_set_type(&contexts[i], type);
		net_context_set_ip_proto(&contexts[i], ip_proto);

		contexts[i].flags |= NET_CONTEXT_IN_USE;
		contexts[i].iface = 0;

		memset(&contexts[i].remote, 0, sizeof(struct sockaddr));
		memset(&contexts[i].local, 0, sizeof(struct sockaddr_ptr));

#if defined(CONFIG_NET_CONTEXT_SYNC_RECV)
		k_sem_init(&contexts[i].recv_data_wait, 0, UINT_MAX);
		k_sem_give(&contexts[i].recv_data_wait);
#endif /* CONFIG_NET_CONTEXT_SYNC_RECV */

		*context = &contexts[i];

		ret = 0;
		break;
	}

	k_sem_give(&contexts_lock);

#if defined(CONFIG_NET_L2_OFFLOAD_IP)
	/* FIXME - Figure out a way to get the correct network interface
	 * as it is not known at this point yet.
	 */
	if (!ret && net_if_is_ip_offloaded(net_if_get_default())) {
		ret = net_l2_offload_ip_get(net_if_get_default(),
					    family,
					    type,
					    ip_proto,
					    context);
		if (ret < 0) {
			(*context)->flags &= ~NET_CONTEXT_IN_USE;
			*context = NULL;
		}

		return ret;
	}
#endif /* CONFIG_NET_L2_OFFLOAD_IP */

	return ret;
}

#if defined(CONFIG_NET_TCP)
static inline int send_fin(struct net_context *context,
			   struct sockaddr *remote);
static enum net_verdict tcp_active_close(struct net_conn *conn,
					 struct net_buf *buf,
					 void *user_data);

static bool send_fin_if_active_close(struct net_context *context)
{
	NET_ASSERT(context->tcp);

	switch (context->tcp->state) {
	case NET_TCP_SYN_RCVD:
	case NET_TCP_ESTABLISHED:
		/* Sending a packet with the FIN flag automatically
		 * transitions to FIN_WAIT_1
		 */
		send_fin(context, &context->remote);
		net_conn_change_callback(context->conn_handler,
					 tcp_active_close, context);
		return true;
	default:
		return false;
	}
}
#endif /* CONFIG_NET_TCP */

int net_context_put(struct net_context *context)
{
	NET_ASSERT(context);

	if (!PART_OF_ARRAY(contexts, context)) {
		return -EINVAL;
	}

	k_sem_take(&contexts_lock, K_FOREVER);

#if defined(CONFIG_NET_L2_OFFLOAD_IP)
	if (net_if_is_ip_offloaded(net_context_get_iface(context))) {
		context->flags &= ~NET_CONTEXT_IN_USE;
		return net_l2_offload_ip_put(
			net_context_get_iface(context), context);
	}
#endif /* CONFIG_NET_L2_OFFLOAD_IP */

#if defined(CONFIG_NET_TCP)
	if (net_context_get_ip_proto(context) == IPPROTO_TCP) {
		if (send_fin_if_active_close(context)) {
			NET_DBG("TCP connection in active close, not "
				"disposing yet");
			goto still_in_use;
		}

		if (context->tcp) {
			net_tcp_release(context->tcp);
		}
	}
#endif /* CONFIG_NET_TCP */

	if (context->conn_handler) {
		net_conn_unregister(context->conn_handler);
	}

	context->flags &= ~NET_CONTEXT_IN_USE;

#if defined(CONFIG_NET_TCP)
still_in_use:
#endif /* CONFIG_NET_TCP */

	k_sem_give(&contexts_lock);

	return 0;
}
{'fraction_non_alphanumeric': 0.12693303477713247, 'fraction_numerical': 0.006297669862151004, 'mean_word_length': 4.571929824561403, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 62, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7560375', 'n_tokens_mistral': 5951, 'n_tokens_neox': 5469, 'n_words': 1109}