<commit_before>/** @file
 * @brief TCP handler
 *
 * Handle TCP connections.
 */

/*
 * Copyright (c) 2016 Intel Corporation
 * Copyright 2011-2015 by <NAME>. FNET Community.
 * Copyright 2008-2010 by <NAME>. Freescale Semiconductor, Inc.
 * Copyright 2003 by <NAME>, <NAME>. Motorola SPS.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#if defined(CONFIG_NET_DEBUG_TCP)
#define SYS_LOG_DOMAIN "net/tcp"
#define NET_DEBUG 1
#endif

#include <nanokernel.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 "connection.h"
#include "net_private.h"

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

/*
 * Each TCP connection needs to be tracked by net_context, so
 * we need to allocate equal number of control structures here.
 */
#define NET_MAX_TCP_CONTEXT CONFIG_NET_MAX_CONTEXTS
static struct net_tcp tcp_context[NET_MAX_TCP_CONTEXT];

static struct nano_sem tcp_lock;

struct tcp_segment {
	uint32_t seq;
	uint32_t ack;
	uint16_t wnd;
	uint8_t flags;
	uint8_t optlen;
	void *options;
	struct net_buf *data;
	struct sockaddr_ptr *src_addr;
	const struct sockaddr *dst_addr;
};

#if NET_DEBUG > 0
static inline uint32_t a2u32(uint8_t *a)
{
	return  a[0] << 24 | a[1] << 16 | a[2] << 8  | a[3];
}

static inline uint32_t a2u16(uint8_t *a)
{
	return a[0] << 8 | a[1];
}

static void net_tcp_trace(char *str, struct net_buf *buf)
{
	NET_INFO("%s[TCP header]", str);
	NET_INFO("|(SrcPort)         %5u |(DestPort)      %5u |",
		 ntohs(NET_TCP_BUF(buf)->src_port),
		 ntohs(NET_TCP_BUF(buf)->dst_port));
	NET_INFO("|(Sequence number)                 0x%010x |",
		 a2u32(NET_TCP_BUF(buf)->seq));
	NET_INFO("|(ACK number)                      0x%010x |",
		 a2u32(NET_TCP_BUF(buf)->ack));
	NET_INFO("|(HL) %2u |(F)  %u%u%u%u%u%u |(Window)           %5u |",
		 (NET_TCP_BUF(buf)->offset >> 4) * 4,
		 NET_TCP_BUF(buf)->flags >> 5 & 1,
		 NET_TCP_BUF(buf)->flags >> 4 & 1,
		 NET_TCP_BUF(buf)->flags >> 3 & 1,
		 NET_TCP_BUF(buf)->flags >> 2 & 1,
		 NET_TCP_BUF(buf)->flags >> 1 & 1,
		 NET_TCP_BUF(buf)->flags & 1,
		 a2u16(NET_TCP_BUF(buf)->wnd));
	NET_INFO("|(Checksum)    0x%04x |(Urgent)           %5u |",
		 ntohs(NET_TCP_BUF(buf)->chksum),
		 a2u16(NET_TCP_BUF(buf)->urg));
}
#else
#define net_tcp_trace(...)
#endif

static inline uint32_t init_isn(void)
{
	/* Randomise initial seq number */
	return sys_rand32_get();
}

struct net_tcp *net_tcp_alloc(struct net_context *context)
{
	int i;

	for (i = 0; i < NET_MAX_TCP_CONTEXT; i++) {
		if (net_tcp_is_used(&tcp_context[i])) {
			continue;
		}

		memset(&tcp_context[i], 0, sizeof(struct net_tcp));

		tcp_context[i].flags |= NET_TCP_IN_USE;
		tcp_context[i].state = NET_TCP_CLOSED;
		tcp_context[i].context = context;

		tcp_context[i].send_seq = init_isn();
		tcp_context[i].recv_max_ack = tcp_context[i].send_seq + 1u;

		return &tcp_context[i];
	}

	return NULL;
}

int net_tcp_release(struct net_tcp *tcp)
{
	if (tcp >= &tcp_context[0] ||
	    tcp <= &tcp_context[NET_MAX_TCP_CONTEXT]) {
		return -EINVAL;
	}

	tcp->flags &= ~NET_TCP_IN_USE;
	tcp->state = NET_TCP_CLOSED;
	tcp->context = NULL;

	if (tcp->send) {
		net_nbuf_unref(tcp->send);
		tcp->send = NULL;
	}

	if (tcp->recv) {
		net_nbuf_unref(tcp->recv);
		tcp->recv = NULL;
	}

	return 0;
}

static inline int net_tcp_add_options(struct net_buf *header, size_t len,<commit_msg>net: tcp: Fix race in net_tcp allocation<commit_after>/** @file
 * @brief TCP handler
 *
 * Handle TCP connections.
 */

/*
 * Copyright (c) 2016 Intel Corporation
 * Copyright 2011-2015 by <NAME>. FNET Community.
 * Copyright 2008-2010 by <NAME>. Freescale Semiconductor, Inc.
 * Copyright 2003 by <NAME>, <NAME>. Motorola SPS.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#if defined(CONFIG_NET_DEBUG_TCP)
#define SYS_LOG_DOMAIN "net/tcp"
#define NET_DEBUG 1
#endif

#include <nanokernel.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 "connection.h"
#include "net_private.h"

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

/*
 * Each TCP connection needs to be tracked by net_context, so
 * we need to allocate equal number of control structures here.
 */
#define NET_MAX_TCP_CONTEXT CONFIG_NET_MAX_CONTEXTS
static struct net_tcp tcp_context[NET_MAX_TCP_CONTEXT];

static struct nano_sem tcp_lock;

struct tcp_segment {
	uint32_t seq;
	uint32_t ack;
	uint16_t wnd;
	uint8_t flags;
	uint8_t optlen;
	void *options;
	struct net_buf *data;
	struct sockaddr_ptr *src_addr;
	const struct sockaddr *dst_addr;
};

#if NET_DEBUG > 0
static inline uint32_t a2u32(uint8_t *a)
{
	return  a[0] << 24 | a[1] << 16 | a[2] << 8  | a[3];
}

static inline uint32_t a2u16(uint8_t *a)
{
	return a[0] << 8 | a[1];
}

static void net_tcp_trace(char *str, struct net_buf *buf)
{
	NET_INFO("%s[TCP header]", str);
	NET_INFO("|(SrcPort)         %5u |(DestPort)      %5u |",
		 ntohs(NET_TCP_BUF(buf)->src_port),
		 ntohs(NET_TCP_BUF(buf)->dst_port));
	NET_INFO("|(Sequence number)                 0x%010x |",
		 a2u32(NET_TCP_BUF(buf)->seq));
	NET_INFO("|(ACK number)                      0x%010x |",
		 a2u32(NET_TCP_BUF(buf)->ack));
	NET_INFO("|(HL) %2u |(F)  %u%u%u%u%u%u |(Window)           %5u |",
		 (NET_TCP_BUF(buf)->offset >> 4) * 4,
		 NET_TCP_BUF(buf)->flags >> 5 & 1,
		 NET_TCP_BUF(buf)->flags >> 4 & 1,
		 NET_TCP_BUF(buf)->flags >> 3 & 1,
		 NET_TCP_BUF(buf)->flags >> 2 & 1,
		 NET_TCP_BUF(buf)->flags >> 1 & 1,
		 NET_TCP_BUF(buf)->flags & 1,
		 a2u16(NET_TCP_BUF(buf)->wnd));
	NET_INFO("|(Checksum)    0x%04x |(Urgent)           %5u |",
		 ntohs(NET_TCP_BUF(buf)->chksum),
		 a2u16(NET_TCP_BUF(buf)->urg));
}
#else
#define net_tcp_trace(...)
#endif

static inline uint32_t init_isn(void)
{
	/* Randomise initial seq number */
	return sys_rand32_get();
}

struct net_tcp *net_tcp_alloc(struct net_context *context)
{
	int i, key;

	key = irq_lock();
	for (i = 0; i < NET_MAX_TCP_CONTEXT; i++) {
		if (!net_tcp_is_used(&tcp_context[i])) {
			tcp_context[i].flags |= NET_TCP_IN_USE;
			break;
		}
	}
	irq_unlock(key);

	if (i >= NET_MAX_TCP_CONTEXT) {
		return NULL;
	}

	memset(&tcp_context[i], 0, sizeof(struct net_tcp));

	tcp_context[i].state = NET_TCP_CLOSED;
	tcp_context[i].context = context;

	tcp_context[i].send_seq = init_isn();
	tcp_context[i].recv_max_ack = tcp_context[i].send_seq + 1u;

	return &tcp_context[i];
}

int net_tcp_release(struct net_tcp *tcp)
{
	int key;

	if (tcp >= &tcp_context[0] ||
	    tcp <= &tcp_context[NET_MAX_TCP_CONTEXT]) {
		return -EINVAL;
	}

	tcp->state = NET_TCP_CLOSED;
	tcp->context = NULL;

	if (tcp->send) {
		net_nbuf_unref(tcp->send);
		tcp->send = NULL;
	}

	if (tcp->recv) {
		net_nbuf_unref(tcp->recv);
		tcp->recv = NULL;
	}

	key = irq_lock();
	tcp->flags &= ~NET_TCP_IN_USE;
	irq_unlock(key);

	return 0;
}

static inline int net_tcp_add_options(struct net_buf *header, size_t len,
{'fraction_non_alphanumeric': 0.14420180722891565, 'fraction_numerical': 0.0286144578313253, 'mean_word_length': 4.00879949717159, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 100, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '176692', 'n_tokens_mistral': 3304, 'n_tokens_neox': 3078, 'n_words': 751}