1 /*
2  * Copyright (c) 2018-2019 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "tp.h"
8 
9 #define is(_a, _b) (strcmp((_a), (_b)) == 0)
10 
11 #ifndef MIN3
12 #define MIN3(_a, _b, _c) MIN((_a), MIN((_b), (_c)))
13 #endif
14 
15 #define th_sport(_x) UNALIGNED_GET(&(_x)->th_sport)
16 #define th_dport(_x) UNALIGNED_GET(&(_x)->th_dport)
17 #define th_seq(_x) ntohl(UNALIGNED_GET(&(_x)->th_seq))
18 #define th_ack(_x) ntohl(UNALIGNED_GET(&(_x)->th_ack))
19 #define th_off(_x) ((_x)->th_off)
20 #define th_flags(_x) UNALIGNED_GET(&(_x)->th_flags)
21 #define th_win(_x) UNALIGNED_GET(&(_x)->th_win)
22 
23 #define tcp_slist(_conn, _slist, _op, _type, _link)			\
24 ({									\
25 	k_mutex_lock(&conn->lock, K_FOREVER);				\
26 									\
27 	sys_snode_t *_node = sys_slist_##_op(_slist);			\
28 									\
29 	_type * _x = _node ? CONTAINER_OF(_node, _type, _link) : NULL;	\
30 									\
31 	k_mutex_unlock(&conn->lock);					\
32 									\
33 	_x;								\
34 })
35 
36 #if IS_ENABLED(CONFIG_NET_TEST_PROTOCOL)
37 #define tcp_malloc(_size) \
38 	tp_malloc(_size, tp_basename(__FILE__), __LINE__, __func__)
39 #define tcp_calloc(_nmemb, _size) \
40 	tp_calloc(_nmemb, _size, tp_basename(__FILE__), __LINE__, __func__)
41 #define tcp_free(_ptr) tp_free(_ptr, tp_basename(__FILE__), __LINE__, __func__)
42 #else
43 #define tcp_malloc(_size) k_malloc(_size)
44 #define tcp_calloc(_nmemb, _size) k_calloc(_nmemb, _size)
45 #define tcp_free(_ptr) k_free(_ptr)
46 #endif
47 
48 #define TCP_PKT_ALLOC_TIMEOUT K_MSEC(100)
49 
50 #if defined(CONFIG_NET_TEST_PROTOCOL)
51 #define tcp_pkt_clone(_pkt) tp_pkt_clone(_pkt, tp_basename(__FILE__), __LINE__)
52 #define tcp_pkt_unref(_pkt) tp_pkt_unref(_pkt, tp_basename(__FILE__), __LINE__)
53 #else
54 #define tcp_pkt_clone(_pkt) net_pkt_clone(_pkt, TCP_PKT_ALLOC_TIMEOUT)
55 #define tcp_pkt_unref(_pkt) net_pkt_unref(_pkt)
56 #define tp_pkt_alloc(args...)
57 #endif
58 
59 #define tcp_pkt_ref(_pkt) net_pkt_ref(_pkt)
60 #define tcp_pkt_alloc(_conn, _len)					\
61 ({									\
62 	struct net_pkt *_pkt;						\
63 									\
64 	if ((_len) > 0) {						\
65 		_pkt = net_pkt_alloc_with_buffer(			\
66 			(_conn)->iface,					\
67 			(_len),						\
68 			net_context_get_family((_conn)->context),	\
69 			IPPROTO_TCP,					\
70 			TCP_PKT_ALLOC_TIMEOUT);				\
71 	} else {							\
72 		_pkt = net_pkt_alloc(TCP_PKT_ALLOC_TIMEOUT);		\
73 	}								\
74 									\
75 	tp_pkt_alloc(_pkt, tp_basename(__FILE__), __LINE__);		\
76 									\
77 	_pkt;								\
78 })
79 
80 #define tcp_rx_pkt_alloc(_conn, _len)					\
81 ({									\
82 	struct net_pkt *_pkt;						\
83 									\
84 	if ((_len) > 0) {						\
85 		_pkt = net_pkt_rx_alloc_with_buffer(			\
86 			(_conn)->iface,					\
87 			(_len),						\
88 			net_context_get_family((_conn)->context),	\
89 			IPPROTO_TCP,					\
90 			TCP_PKT_ALLOC_TIMEOUT);				\
91 	} else {							\
92 		_pkt = net_pkt_rx_alloc(TCP_PKT_ALLOC_TIMEOUT);		\
93 	}								\
94 									\
95 	tp_pkt_alloc(_pkt, tp_basename(__FILE__), __LINE__);		\
96 									\
97 	_pkt;								\
98 })
99 
100 
101 #if IS_ENABLED(CONFIG_NET_TEST_PROTOCOL)
102 #define conn_seq(_conn, _req) \
103 	tp_seq_track(TP_SEQ, &(_conn)->seq, (_req), tp_basename(__FILE__), \
104 			__LINE__, __func__)
105 #define conn_ack(_conn, _req) \
106 	tp_seq_track(TP_ACK, &(_conn)->ack, (_req), tp_basename(__FILE__), \
107 			__LINE__, __func__)
108 #else
109 #define conn_seq(_conn, _req) (_conn)->seq += (_req)
110 #define conn_ack(_conn, _req) (_conn)->ack += (_req)
111 #endif
112 
113 #define conn_mss(_conn)					\
114 	((_conn)->recv_options.mss_found ?		\
115 	 (_conn)->recv_options.mss : (uint16_t)NET_IPV6_MTU)
116 
117 #define conn_state(_conn, _s)						\
118 ({									\
119 	NET_DBG("%s->%s",						\
120 		tcp_state_to_str((_conn)->state, false),		\
121 		tcp_state_to_str((_s), false));				\
122 	(_conn)->state = _s;						\
123 })
124 
125 #define conn_send_data_dump(_conn)                                             \
126 	({                                                                     \
127 		NET_DBG("conn: %p total=%zd, unacked_len=%d, "                 \
128 			"send_win=%hu, mss=%hu",                               \
129 			(_conn), net_pkt_get_len((_conn)->send_data),          \
130 			conn->unacked_len, conn->send_win,                     \
131 			(uint16_t)conn_mss((_conn)));                          \
132 		NET_DBG("conn: %p send_data_timer=%hu, send_data_retries=%hu", \
133 			(_conn),                                               \
134 			(bool)k_ticks_to_ms_ceil32(                            \
135 				k_work_delayable_remaining_get(                \
136 					&(_conn)->send_data_timer)),           \
137 			(_conn)->send_data_retries);                           \
138 	})
139 
140 enum pkt_addr {
141 	TCP_EP_SRC = 1,
142 	TCP_EP_DST = 0
143 };
144 
145 struct tcphdr {
146 	uint16_t th_sport;
147 	uint16_t th_dport;
148 	uint32_t th_seq;
149 	uint32_t th_ack;
150 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
151 	uint8_t th_x2:4;	/* unused */
152 	uint8_t th_off:4;	/* data offset, in units of 32-bit words */
153 #endif
154 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
155 	uint8_t th_off:4;
156 	uint8_t th_x2:4;
157 #endif
158 	uint8_t th_flags;
159 	uint16_t th_win;
160 	uint16_t th_sum;
161 	uint16_t th_urp;
162 } __packed;
163 
164 enum th_flags {
165 	FIN = 1,
166 	SYN = 1 << 1,
167 	RST = 1 << 2,
168 	PSH = 1 << 3,
169 	ACK = 1 << 4,
170 	URG = 1 << 5,
171 	ECN = 1 << 6,
172 	CWR = 1 << 7,
173 };
174 
175 enum tcp_state {
176 	TCP_LISTEN = 1,
177 	TCP_SYN_SENT,
178 	TCP_SYN_RECEIVED,
179 	TCP_ESTABLISHED,
180 	TCP_FIN_WAIT_1,
181 	TCP_FIN_WAIT_2,
182 	TCP_CLOSE_WAIT,
183 	TCP_CLOSING,
184 	TCP_LAST_ACK,
185 	TCP_TIME_WAIT,
186 	TCP_CLOSED
187 };
188 
189 enum tcp_data_mode {
190 	TCP_DATA_MODE_SEND = 0,
191 	TCP_DATA_MODE_RESEND = 1
192 };
193 
194 union tcp_endpoint {
195 	struct sockaddr sa;
196 	struct sockaddr_in sin;
197 	struct sockaddr_in6 sin6;
198 };
199 
200 /* TCP Option codes */
201 #define NET_TCP_END_OPT          0
202 #define NET_TCP_NOP_OPT          1
203 #define NET_TCP_MSS_OPT          2
204 #define NET_TCP_WINDOW_SCALE_OPT 3
205 
206 /* TCP Option sizes */
207 #define NET_TCP_END_SIZE          1
208 #define NET_TCP_NOP_SIZE          1
209 #define NET_TCP_MSS_SIZE          4
210 #define NET_TCP_WINDOW_SCALE_SIZE 3
211 
212 struct tcp_options {
213 	uint16_t mss;
214 	uint16_t window;
215 	bool mss_found : 1;
216 	bool wnd_found : 1;
217 };
218 
219 struct tcp { /* TCP connection */
220 	sys_snode_t next;
221 	struct net_context *context;
222 	struct net_pkt *send_data;
223 	struct net_pkt *queue_recv_data;
224 	struct net_if *iface;
225 	void *recv_user_data;
226 	sys_slist_t send_queue;
227 	union {
228 		net_tcp_accept_cb_t accept_cb;
229 		struct tcp *accepted_conn;
230 	};
231 	struct k_mutex lock;
232 	struct k_sem connect_sem; /* semaphore for blocking connect */
233 	struct k_fifo recv_data;  /* temp queue before passing data to app */
234 	struct tcp_options recv_options;
235 	struct tcp_options send_options;
236 	struct k_work_delayable send_timer;
237 	struct k_work_delayable recv_queue_timer;
238 	struct k_work_delayable send_data_timer;
239 	struct k_work_delayable timewait_timer;
240 	union {
241 		/* Because FIN and establish timers are never happening
242 		 * at the same time, share the timer between them to
243 		 * save memory.
244 		 */
245 		struct k_work_delayable fin_timer;
246 		struct k_work_delayable establish_timer;
247 	};
248 	union tcp_endpoint src;
249 	union tcp_endpoint dst;
250 	size_t send_data_total;
251 	size_t send_retries;
252 	int unacked_len;
253 	atomic_t ref_count;
254 	enum tcp_state state;
255 	enum tcp_data_mode data_mode;
256 	uint32_t seq;
257 	uint32_t ack;
258 	uint16_t recv_win;
259 	uint16_t send_win;
260 	uint8_t send_data_retries;
261 	bool in_retransmission : 1;
262 	bool in_connect : 1;
263 	bool in_close : 1;
264 };
265 
266 #define _flags(_fl, _op, _mask, _cond)					\
267 ({									\
268 	bool result = false;						\
269 									\
270 	if (UNALIGNED_GET(_fl) && (_cond) &&				\
271 	    (UNALIGNED_GET(_fl) _op(_mask))) {				\
272 		UNALIGNED_PUT(UNALIGNED_GET(_fl) & ~(_mask), _fl);	\
273 		result = true;						\
274 	}								\
275 									\
276 	result;								\
277 })
278 
279 #define FL(_fl, _op, _mask, _args...)					\
280 	_flags(_fl, _op, _mask, strlen("" #_args) ? _args : true)
281 
282 typedef void (*net_tcp_cb_t)(struct tcp *conn, void *user_data);
283