<commit_before>/**
 * @file
 * @brief Implementation of the Transmission Control Protocol (TCP).
 * @details RFC 768
 *
 * @date 04.04.10
 * @author <NAME>
 * @author <NAME>
 * @author <NAME>
 */

#include <net/l4/tcp.h>
#include <net/skbuff.h>
#include <errno.h>
#include <assert.h>
#include <net/sock.h>
#include <time.h>
#include <sys/time.h>
#include <util/sys_log.h>
#include <net/socket/inet_sock.h>
#include <net/socket/inet6_sock.h>
#include <net/l3/ipv4/ip.h>
#include <net/l3/ipv6.h>
#include <string.h>

#include <kernel/time/timer.h>
#include <embox/net/proto.h>
#include <embox/unit.h>
#include <kernel/softirq_lock.h>
#include <kernel/time/ktime.h>
#include <net/lib/tcp.h>
#include <util/indexator.h>

#include <kernel/task/io_sync.h>
#include <kernel/printk.h>
#include <prom/prom_printf.h>

#include <net/lib/ipv4.h>
#include <net/lib/ipv6.h>

EMBOX_UNIT_INIT(tcp_init);
EMBOX_NET_PROTO(ETH_P_IP, IPPROTO_TCP, tcp_rcv, NULL);
EMBOX_NET_PROTO(ETH_P_IPV6, IPPROTO_TCP, tcp_rcv, NULL);

/** TODO
 * +1. Create default socket for resetting
 * +2. PSH flag
 * +3. RST flag
 * ?4. Changes state's logic (i.e. TCP_CLOSED for all socket which doesn't exists etc.)
 * +5. Rewrite send_from_sock (don't send new skb if queue is not empty)
 * +6. tcp_sock_free in tcp_st_finwait_2
 * +7. Remove seq_next (use rem.seq instead, build packet, and then rebuild only)
 * +8. Add lock/unlock
 * +9. Add rexmit
 * +-10. Add window
 * 11. Add options
 * +-12. Add timeout (i.e. sockopts) to tcp_sock.c
 */


/* Error code of TCP handlers */
enum tcp_ret_code {
	TCP_RET_OK,       /* all ok, don't free packet */
	TCP_RET_DROP,     /* drop packet */
	TCP_RET_SEND_SEQ, /* send packet */
	TCP_RET_SEND,     /* send acknowledgment or other packet
						 without outgoing queue using OLD skb*/
	TCP_RET_SEND_ALLOC, /* send acknowledgment or other packet
						  without outgoing queue using NEW skb */
	TCP_RET_RST,      /* reset (only for pre_process) */
	TCP_RET_FREE      /* drop packet and free socket */
};

/* Type of TCP state handlers */
typedef enum tcp_ret_code (*tcp_handler_t)(struct tcp_sock *tcp_sk,
		const struct tcphdr *tcph, struct sk_buff *skb,
		struct tcphdr *out_tcph);

static struct sys_timer tcp_tmr_default; /* Timer structure for rexmitting or TIME-WAIT satate */

/* Prototypes */
static int tcp_handle(struct tcp_sock *tcp_sk, struct sk_buff *skb, tcp_handler_t hnd);
static const tcp_handler_t tcp_st_handler[];
static void tcp_get_now(struct timeval *out_now);

/************************ Debug functions ******************************/
#if 1
void debug_print(__u8 code, const char *msg, ...) { }
static inline void packet_print(const struct tcp_sock *tcp_sk,
		const struct sk_buff *skb, const char *msg, int family,
		const void *addr, in_port_t port) { }

#else

void debug_print(__u8 code, const char *msg, ...) {
	va_list args;

	va_start(args, msg);
	switch (code) {
//default:
//	case 0:  /* default */
	case 1:  /* in/out package print */
//	case 2:  /* socket state */
//	case 3:  /* global functions */
//	case 4:  /* hash/unhash */
//	case 5:  /* lock/unlock */
//	case 6:	 /* sock_alloc/sock_free */
//	case 7:  /* tcp_default_timer action */
//	case 8:  /* state's handler */
//	case 9:  /* sending package */
//	case 10: /* pre_process */
//	case 11: /* tcp_handle */
		softirq_lock();
		prom_vprintf(msg, args);
		softirq_unlock();
		break;
	}
	va_end(args);
}

static inline void packet_print(const struct tcp_sock *tcp_sk,
		const struct sk_buff *skb, const char *msg, int family,
		const void *addr, in_port_t port) {
	struct timeval now;
	char buff[INET6_ADDRSTRLEN];

	tcp_get_now(&now);
	debug_print(1, "%ld.%ld %s:%d %s sk %p skb %p seq %u ack %u seq_len %u flags %s %s %s %s %s %s %s %s\n",
			// info
			now.tv_sec, now.tv_usec,
			inet_ntop(family, addr, &buff[0], sizeof buff),
			ntohs(port), msg,
			tcp_sk != NULL ? to_sock(tcp_sk) : NULL, skb,
			// seq, ack, seq_len
			ntohl(skb->h.th->seq), ntohl(skb->h.th->ack_seq), tcp_seq_length(skb->h.th, skb->nh.raw),
			// flags
			(skb->h.th->ack ? "ACK" : ""), (skb->h.th->syn ? "SYN" : ""),
			(skb->h.th->fin ? "FIN" : ""), (skb->h.th->rst ? "RST" : ""),
			(skb->h.th->psh ? "PSH" : ""), (skb->h.th->urg ? "URG" : ""),
			(skb->h.th->ece ? "ECE" : ""), (skb->h.th->cwr ? "CWR" : ""));
}

#endif

/************************ Auxiliary functions **************************/
int alloc_prep_skb(struct tcp_sock *tcp_sk, size_t opt_len,
		size_t *data_len, struct sk_buff **out_skb) {
	int ret;
	struct sock *sk;
	size_t total_len, hdr_len;

	assert(tcp_sk != NULL);
	assert(out_skb != NULL);

	sk = to_sock(tcp_sk);
	if (sk->o_ops == NULL) {
		return -ENOSYS;
	}

	opt_len = (opt_len + 3) & ~(size_t)3;
	hdr_len = TCP_MIN_HEADER_SIZE + opt_len;
	total_len = hdr_len + (data_len != NULL ? *data_len : 0);

	assert(sk->o_ops->make_pack != NULL);
	ret = sk->o_ops->make_pack(sk, NULL, &total_len, out_skb);
	if (ret != 0) {
		return ret;
	}
	else if (total_len < hdr_len + (data_len != NULL)) {
		skb_free(*out_skb);
		return -EMSGSIZE;
	}

	if (data_len != NULL) {
		*data_len = total_len - hdr_len;
	}

	return 0;
}

void tcp_sock_lock(struct tcp_sock *tcp_sk, unsigned int obj) {
	if (tcp_sk->lock++ == 0) {
		softirq_lock();
	}
}

void tcp_sock_unlock(struct tcp_sock *tcp_sk, unsigned int obj) {
	assert(tcp_sk->lock != 0);
	if (--tcp_sk->lock == 0) {
		softirq_unlock();
	}
}

static void tcp_sock_rcv(struct tcp_sock *tcp_sk,
		struct sk_buff *skb) {
	assert(tcp_sk != NULL);
	assert(skb != NULL);
	assert(tcp_sk->rem.seq >= ntohl(skb->h.th->seq)); /* FIXME */

	sock_rcv(to_sock(tcp_sk), skb, skb->h.raw
			+ TCP_HEADER_SIZE(skb->h.th)
			+ (tcp_sk->rem.seq - ntohl(skb->h.th->seq)),
			tcp_data_length(skb->h.th, skb->nh.raw));
}

void tcp_sock_set_state(struct tcp_sock *tcp_sk, enum tcp_sock_state new_state) {
	const char *str_state[TCP_MAX_STATE] = {"TCP_CLOSED", "TCP_LISTEN",
			"TCP_SYN_SENT", "TCP_SYN_RECV_PRE", "TCP_SYN_RECV", "TCP_ESTABIL",
			"TCP_FINWAIT_1", "TCP_FINWAIT_2", "TCP_CLOSEWAIT", "TCP_CLOSING",
			"TCP_LASTACK", "TCP_TIMEWAIT"};
	switch (new_state) {
	default:
		break;
	case TCP_SYN_SENT:
	case TCP_SYN_RECV:
		tcp_get_now(&tcp_sk->syn_time); /* set when SYN sent */
		/* fallthrough */
	case TCP_FINWAIT_1:
	case TCP_LASTACK:
		tcp_sk->ack_flag = tcp_sk->self.seq + 1;
		debug_print(2, "sk %p set ack_flag %u for state %d-%s\n",<commit_msg>tcp: Fix receive buffer length<commit_after>/**
 * @file
 * @brief Implementation of the Transmission Control Protocol (TCP).
 * @details RFC 768
 *
 * @date 04.04.10
 * @author <NAME>
 * @author <NAME>
 * @author <NAME>
 */

#include <net/l4/tcp.h>
#include <net/skbuff.h>
#include <errno.h>
#include <assert.h>
#include <net/sock.h>
#include <time.h>
#include <sys/time.h>
#include <util/sys_log.h>
#include <net/socket/inet_sock.h>
#include <net/socket/inet6_sock.h>
#include <net/l3/ipv4/ip.h>
#include <net/l3/ipv6.h>
#include <string.h>

#include <kernel/time/timer.h>
#include <embox/net/proto.h>
#include <embox/unit.h>
#include <kernel/softirq_lock.h>
#include <kernel/time/ktime.h>
#include <net/lib/tcp.h>
#include <util/indexator.h>

#include <kernel/task/io_sync.h>
#include <kernel/printk.h>
#include <prom/prom_printf.h>

#include <net/lib/ipv4.h>
#include <net/lib/ipv6.h>

EMBOX_UNIT_INIT(tcp_init);
EMBOX_NET_PROTO(ETH_P_IP, IPPROTO_TCP, tcp_rcv, NULL);
EMBOX_NET_PROTO(ETH_P_IPV6, IPPROTO_TCP, tcp_rcv, NULL);

/** TODO
 * +1. Create default socket for resetting
 * +2. PSH flag
 * +3. RST flag
 * ?4. Changes state's logic (i.e. TCP_CLOSED for all socket which doesn't exists etc.)
 * +5. Rewrite send_from_sock (don't send new skb if queue is not empty)
 * +6. tcp_sock_free in tcp_st_finwait_2
 * +7. Remove seq_next (use rem.seq instead, build packet, and then rebuild only)
 * +8. Add lock/unlock
 * +9. Add rexmit
 * +-10. Add window
 * 11. Add options
 * +-12. Add timeout (i.e. sockopts) to tcp_sock.c
 */


/* Error code of TCP handlers */
enum tcp_ret_code {
	TCP_RET_OK,       /* all ok, don't free packet */
	TCP_RET_DROP,     /* drop packet */
	TCP_RET_SEND_SEQ, /* send packet */
	TCP_RET_SEND,     /* send acknowledgment or other packet
						 without outgoing queue using OLD skb*/
	TCP_RET_SEND_ALLOC, /* send acknowledgment or other packet
						  without outgoing queue using NEW skb */
	TCP_RET_RST,      /* reset (only for pre_process) */
	TCP_RET_FREE      /* drop packet and free socket */
};

/* Type of TCP state handlers */
typedef enum tcp_ret_code (*tcp_handler_t)(struct tcp_sock *tcp_sk,
		const struct tcphdr *tcph, struct sk_buff *skb,
		struct tcphdr *out_tcph);

static struct sys_timer tcp_tmr_default; /* Timer structure for rexmitting or TIME-WAIT satate */

/* Prototypes */
static int tcp_handle(struct tcp_sock *tcp_sk, struct sk_buff *skb, tcp_handler_t hnd);
static const tcp_handler_t tcp_st_handler[];
static void tcp_get_now(struct timeval *out_now);

/************************ Debug functions ******************************/
#if 1
void debug_print(__u8 code, const char *msg, ...) { }
static inline void packet_print(const struct tcp_sock *tcp_sk,
		const struct sk_buff *skb, const char *msg, int family,
		const void *addr, in_port_t port) { }

#else

void debug_print(__u8 code, const char *msg, ...) {
	va_list args;

	va_start(args, msg);
	switch (code) {
//default:
//	case 0:  /* default */
	case 1:  /* in/out package print */
//	case 2:  /* socket state */
//	case 3:  /* global functions */
//	case 4:  /* hash/unhash */
//	case 5:  /* lock/unlock */
//	case 6:	 /* sock_alloc/sock_free */
//	case 7:  /* tcp_default_timer action */
//	case 8:  /* state's handler */
//	case 9:  /* sending package */
//	case 10: /* pre_process */
//	case 11: /* tcp_handle */
		softirq_lock();
		prom_vprintf(msg, args);
		softirq_unlock();
		break;
	}
	va_end(args);
}

static inline void packet_print(const struct tcp_sock *tcp_sk,
		const struct sk_buff *skb, const char *msg, int family,
		const void *addr, in_port_t port) {
	struct timeval now;
	char buff[INET6_ADDRSTRLEN];

	tcp_get_now(&now);
	debug_print(1, "%ld.%ld %s:%d %s sk %p skb %p seq %u ack %u seq_len %u flags %s %s %s %s %s %s %s %s\n",
			// info
			now.tv_sec, now.tv_usec,
			inet_ntop(family, addr, &buff[0], sizeof buff),
			ntohs(port), msg,
			tcp_sk != NULL ? to_sock(tcp_sk) : NULL, skb,
			// seq, ack, seq_len
			ntohl(skb->h.th->seq), ntohl(skb->h.th->ack_seq), tcp_seq_length(skb->h.th, skb->nh.raw),
			// flags
			(skb->h.th->ack ? "ACK" : ""), (skb->h.th->syn ? "SYN" : ""),
			(skb->h.th->fin ? "FIN" : ""), (skb->h.th->rst ? "RST" : ""),
			(skb->h.th->psh ? "PSH" : ""), (skb->h.th->urg ? "URG" : ""),
			(skb->h.th->ece ? "ECE" : ""), (skb->h.th->cwr ? "CWR" : ""));
}

#endif

/************************ Auxiliary functions **************************/
int alloc_prep_skb(struct tcp_sock *tcp_sk, size_t opt_len,
		size_t *data_len, struct sk_buff **out_skb) {
	int ret;
	struct sock *sk;
	size_t total_len, hdr_len;

	assert(tcp_sk != NULL);
	assert(out_skb != NULL);

	sk = to_sock(tcp_sk);
	if (sk->o_ops == NULL) {
		return -ENOSYS;
	}

	opt_len = (opt_len + 3) & ~(size_t)3;
	hdr_len = TCP_MIN_HEADER_SIZE + opt_len;
	total_len = hdr_len + (data_len != NULL ? *data_len : 0);

	assert(sk->o_ops->make_pack != NULL);
	ret = sk->o_ops->make_pack(sk, NULL, &total_len, out_skb);
	if (ret != 0) {
		return ret;
	}
	else if (total_len < hdr_len + (data_len != NULL)) {
		skb_free(*out_skb);
		return -EMSGSIZE;
	}

	if (data_len != NULL) {
		*data_len = total_len - hdr_len;
	}

	return 0;
}

void tcp_sock_lock(struct tcp_sock *tcp_sk, unsigned int obj) {
	if (tcp_sk->lock++ == 0) {
		softirq_lock();
	}
}

void tcp_sock_unlock(struct tcp_sock *tcp_sk, unsigned int obj) {
	assert(tcp_sk->lock != 0);
	if (--tcp_sk->lock == 0) {
		softirq_unlock();
	}
}

static void tcp_sock_rcv(struct tcp_sock *tcp_sk,
		struct sk_buff *skb) {
	size_t seq_off;

	assert(tcp_sk != NULL);
	assert(skb != NULL);
	assert(tcp_sk->rem.seq >= ntohl(skb->h.th->seq)); /* FIXME */
	seq_off = tcp_sk->rem.seq - ntohl(skb->h.th->seq);

	assert(tcp_data_length(skb->h.th, skb->nh.raw) > seq_off);
	sock_rcv(to_sock(tcp_sk), skb, skb->h.raw
			+ TCP_HEADER_SIZE(skb->h.th) + seq_off,
			tcp_data_length(skb->h.th, skb->nh.raw) - seq_off);
}

void tcp_sock_set_state(struct tcp_sock *tcp_sk, enum tcp_sock_state new_state) {
	const char *str_state[TCP_MAX_STATE] = {"TCP_CLOSED", "TCP_LISTEN",
			"TCP_SYN_SENT", "TCP_SYN_RECV_PRE", "TCP_SYN_RECV", "TCP_ESTABIL",
			"TCP_FINWAIT_1", "TCP_FINWAIT_2", "TCP_CLOSEWAIT", "TCP_CLOSING",
			"TCP_LASTACK", "TCP_TIMEWAIT"};
	switch (new_state) {
	default:
		break;
	case TCP_SYN_SENT:
	case TCP_SYN_RECV:
		tcp_get_now(&tcp_sk->syn_time); /* set when SYN sent */
		/* fallthrough */
	case TCP_FINWAIT_1:
	case TCP_LASTACK:
		tcp_sk->ack_flag = tcp_sk->self.seq + 1;
		debug_print(2, "sk %p set ack_flag %u for state %d-%s\n",
{'fraction_non_alphanumeric': 0.177705223880597, 'fraction_numerical': 0.010416666666666666, 'mean_word_length': 3.8255813953488373, 'pattern_counts': {'":': 0, '<': 61, '<?xml version=': 0, '>': 150, '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': '5476518', 'n_tokens_mistral': 5431, 'n_tokens_neox': 5178, 'n_words': 1243}