Commit 133fa0fb authored by Oleg Zhurakivskyy's avatar Oleg Zhurakivskyy Committed by Jukka Rissanen
Browse files

net: tcp2: Add experimental TCP



Add experimental TCP.

Signed-off-by: default avatarOleg Zhurakivskyy <oleg.zhurakivskyy@intel.com>
parent 3cbf4a20
Loading
Loading
Loading
Loading

subsys/net/ip/tcp2.c

0 → 100644
+1218 −0

File added.

Preview size limit exceeded, changes collapsed.

subsys/net/ip/tcp2.h

0 → 100644
+141 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2018-2019 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @brief Transmission Control Protocol (TCP)
 *
 * - net_tcp_get() is called by net_context_get(AF_INET, SOCK_STREAM,
     IPPROTO_TCP, ...) and creates struct tcp for the net_context
 * - net_tcp_listen()/net_tcp_accept() listen/accept
 * - At the reception of SYN on the listening net_context, a new pair
 *   of net_context/struct tcp registers a new net_conn handle
 *   with the tcp_pkt_received() as a callback
 * - net_tcp_queue() queues the data for the transmission
 * - The incoming data is delivered up through the context->recv_cb
 * - net_tcp_put() closes the connection
 *
 * NOTE: The present API is provided in order to make the integration
 *       into the ip stack and the socket layer less intrusive.
 *
 *       Semantically cleaner use is possible (and might be exposed),
 *       look into the unit test tests/net/tcp2 for insights.
 */

#ifndef TCP2_H
#define TCP2_H

#ifdef __cplusplus
extern "C" {
#endif

#include <sys/types.h>

/**
 * @brief Allocate a TCP connecton for the net_context
 *        and mutually link the net_context and TCP connection.
 *
 * @param context Network context
 *
 * @return 0 on success, < 0 on error
 */
int net_tcp_get(struct net_context *context);

/**
 * @brief Close and delete the TCP connecton for the net_context
 *
 * @param context Network context
 *
 * @return 0 on success, < 0 on error
 */
int net_tcp_put(struct net_context *context);

/* TODO: Clarify what happens if the ref count goes to 0 */
/**
 * @brief Unref a TCP connecton
 *
 * @param context Network context
 *
 * @return 0 if successful, < 0 on error
 */
int net_tcp_unref(struct net_context *context);
/* TODO: Merge net_tcp_unref() and net_tcp_put() */

/**
 * @brief Listen for an incoming TCP connection
 *
 * @param context Network context
 *
 * @return 0 if successful, < 0 on error
 */
int net_tcp_listen(struct net_context *context);

/**
 * @brief Register an accept callback
 *
 * @param context	Network context
 * @param cb		net_tcp_accept_cb_t callback
 * @param user_data	User data passed as an argument in the callback
 *
 * @return 0 if successful, < 0 on error
 */
int net_tcp_accept(struct net_context *context, net_tcp_accept_cb_t cb,
			void *user_data);
/**
 * @brief Enqueue data for transmission
 *
 * @param context	Network context
 * @param buf		Pointer to the data
 * @param len		Number of bytes
 * @param msghdr	Data for a vector array operation
 *
 * @return 0 if ok, < 0 if error
 */
int net_tcp_queue(struct net_context *context, const void *buf, size_t len,
		  const struct msghdr *msghdr);
/* TODO: split into 2 functions, conn -> context, queue -> send? */

/* The following functions are provided solely for the compatibility
 * with the old TCP
 */

/**
 * @brief Return struct net_tcp_hdr pointer
 *
 * @param pkt Network packet
 * @param tcp_access Helper variable for accessing TCP header
 *
 * @return Pointer to the TCP header on success, NULL on error
 */
struct net_tcp_hdr *net_tcp_input(struct net_pkt *pkt,
					struct net_pkt_data_access *tcp_access);
/* TODO: net_tcp_input() isn't used by TCP and might be dropped with little
 *       re-factorig
 */

/* No ops, provided for compatibility with the old TCP */

void net_tcp_init(void);
int net_tcp_update_recv_wnd(struct net_context *context, s32_t delta);
int net_tcp_queue_data(struct net_context *context, struct net_pkt *pkt);
int net_tcp_finalize(struct net_pkt *pkt);

#if defined(CONFIG_NET_TEST_PROTOCOL)
/**
 * @brief Handle an incoming TCP packet
 *
 * This function is provided for the TCP sanity check and will be eventually
 * dropped.
 *
 * @param pkt Network packet
 */
void tcp_input(struct net_pkt *pkt);
#endif

#ifdef __cplusplus
}
#endif

#endif /* TCP2_H */
+189 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2018-2019 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "tp.h"

#define is(_a, _b) (strcmp((_a), (_b)) == 0)
#define is_timer_subscribed(_t) (k_timer_remaining_get(_t))

#define th_seq(_x) ntohl((_x)->th_seq)
#define th_ack(_x) ntohl((_x)->th_ack)
#define ip_get(_x) ((struct net_ipv4_hdr *) net_pkt_ip_data((_x)))
#define ip6_get(_x) ((struct net_ipv6_hdr *) net_pkt_ip_data((_x)))

#define tcp_slist(_slist, _op, _type, _link)				\
({									\
	sys_snode_t *_node = sys_slist_##_op(_slist);			\
									\
	_type * _x = _node ? CONTAINER_OF(_node, _type, _link) : NULL;	\
									\
	_x;								\
})

#if IS_ENABLED(CONFIG_NET_TEST_PROTOCOL)
#define tcp_malloc(_size) \
	tp_malloc(_size, tp_basename(__FILE__), __LINE__, __func__)
#define tcp_calloc(_nmemb, _size) \
	tp_calloc(_nmemb, _size, tp_basename(__FILE__), __LINE__, __func__)
#define tcp_free(_ptr) tp_free(_ptr, tp_basename(__FILE__), __LINE__, __func__)
#else
#define tcp_malloc(_size) k_malloc(_size)
#define tcp_calloc(_nmemb, _size) k_calloc(_nmemb, _size)
#define tcp_free(_ptr) k_free(_ptr)
#endif

#if IS_ENABLED(CONFIG_NET_TEST_PROTOCOL)
#define tcp_nbuf_alloc(_pool, _len) \
	tp_nbuf_alloc(_pool, _len, tp_basename(__FILE__), __LINE__, __func__)
#define tcp_nbuf_unref(_nbuf) \
	tp_nbuf_unref(_nbuf, tp_basename(__FILE__), __LINE__, __func__)
#else
#define tcp_nbuf_alloc(_pool, _len) net_buf_alloc_len(_pool, _len, K_NO_WAIT)
#define tcp_nbuf_unref(_nbuf) net_buf_unref(_nbuf)
#endif

#if IS_ENABLED(CONFIG_NET_TEST_PROTOCOL)
#define tcp_pkt_alloc(_len) tp_pkt_alloc(_len, tp_basename(__FILE__), __LINE__)
#define tcp_pkt_clone(_pkt) tp_pkt_clone(_pkt, tp_basename(__FILE__), __LINE__)
#define tcp_pkt_unref(_pkt) tp_pkt_unref(_pkt, tp_basename(__FILE__), __LINE__)
#else
static struct net_pkt *tcp_pkt_alloc(size_t len)
{
	struct net_pkt *pkt = net_pkt_alloc(K_NO_WAIT);

	pkt->family = AF_INET;

	NET_ASSERT(pkt);

	if (len) {
		struct net_buf *buf = net_pkt_get_frag(pkt, K_NO_WAIT);

		net_buf_add(buf, len);
		net_pkt_frag_insert(pkt, buf);
		NET_ASSERT(buf);
	}

	return pkt;
}
#define tcp_pkt_clone(_pkt) net_pkt_clone(_pkt, K_NO_WAIT)
#define tcp_pkt_unref(_pkt) net_pkt_unref(_pkt)
#endif
#define tcp_pkt_ref(_pkt) net_pkt_ref(_pkt)

#if IS_ENABLED(CONFIG_NET_TEST_PROTOCOL)
#define conn_seq(_conn, _req) \
	tp_seq_track(TP_SEQ, &(_conn)->seq, (_req), tp_basename(__FILE__), \
			__LINE__, __func__)
#define conn_ack(_conn, _req) \
	tp_seq_track(TP_ACK, &(_conn)->ack, (_req), tp_basename(__FILE__), \
			__LINE__, __func__)
#else
#define conn_seq(_conn, _req) (_conn)->seq += (_req)
#define conn_ack(_conn, _req) (_conn)->ack += (_req)
#endif

#define conn_state(_conn, _s)						\
({									\
	NET_DBG("%s->%s",						\
		tcp_state_to_str((_conn)->state, false),		\
		tcp_state_to_str((_s), false));				\
	(_conn)->state = _s;						\
})

#define TCPOPT_PAD	0
#define TCPOPT_NOP	1
#define TCPOPT_MAXSEG	2
#define TCPOPT_WINDOW	3

enum pkt_addr {
	SRC = 1,
	DST = 0
};

struct tcphdr {
	u16_t th_sport;
	u16_t th_dport;
	u32_t th_seq;
	u32_t th_ack;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
	u8_t th_x2:4;	/* unused */
	u8_t th_off:4;	/* data offset */
#endif
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
	u8_t th_off:4;
	u8_t th_x2:4;
#endif
	u8_t th_flags;
	u16_t th_win;
	u16_t th_sum;
	u16_t th_urp;
};

enum th_flags {
	FIN = 1,
	SYN = 1 << 1,
	RST = 1 << 2,
	PSH = 1 << 3,
	ACK = 1 << 4,
	URG = 1 << 5,
};

enum tcp_state {
	TCP_LISTEN = 1,
	TCP_SYN_SENT,
	TCP_SYN_RECEIVED,
	TCP_ESTABLISHED,
	TCP_FIN_WAIT1,
	TCP_FIN_WAIT2,
	TCP_CLOSE_WAIT,
	TCP_CLOSING,
	TCP_LAST_ACK,
	TCP_TIME_WAIT,
	TCP_CLOSED
};

struct tcp_win { /* TCP window */
	size_t len;
	sys_slist_t bufs;
};

union tcp_endpoint {
	struct sockaddr sa;
	struct sockaddr_in sin;
	struct sockaddr_in6 sin6;
};

struct tcp { /* TCP connection */
	sys_snode_t next;
	enum tcp_state state;
	u32_t seq;
	u32_t ack;
	union tcp_endpoint *src;
	union tcp_endpoint *dst;
	u16_t win;
	struct tcp_win *rcv;
	struct tcp_win *snd;
	struct k_timer send_timer;
	sys_slist_t send_queue;
	bool in_retransmission;
	size_t send_retries;
	struct net_if *iface;
};

#define _flags(_fl, _op, _mask, _cond)					\
({									\
	bool result = false;						\
									\
	if (*(_fl) && (_cond) && (*(_fl) _op (_mask))) {		\
		*(_fl) &= ~(_mask);					\
		result = true;						\
	}								\
									\
	result;								\
})

#define FL(_fl, _op, _mask, _args...)					\
	_flags(_fl, _op, _mask, strlen("" #_args) ? _args : true)