1 /*
2  * Copyright (c) 2018-2019 Intel Corporation
3  * Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include "tp.h"
9 #include <zephyr/toolchain/gcc.h>
10 
11 #define is(_a, _b) (strcmp((_a), (_b)) == 0)
12 
13 #ifndef MIN3
14 #define MIN3(_a, _b, _c) MIN((_a), MIN((_b), (_c)))
15 #endif
16 
17 #define th_sport(_x) UNALIGNED_GET(UNALIGNED_MEMBER_ADDR((_x), th_sport))
18 #define th_dport(_x) UNALIGNED_GET(UNALIGNED_MEMBER_ADDR((_x), th_dport))
19 #define th_seq(_x) ntohl(UNALIGNED_GET(UNALIGNED_MEMBER_ADDR((_x), th_seq)))
20 #define th_ack(_x) ntohl(UNALIGNED_GET(UNALIGNED_MEMBER_ADDR((_x), th_ack)))
21 
22 #define th_off(_x) ((_x)->th_off)
23 #define th_flags(_x) UNALIGNED_GET(UNALIGNED_MEMBER_ADDR((_x), th_flags))
24 #define th_win(_x) UNALIGNED_GET(UNALIGNED_MEMBER_ADDR((_x), th_win))
25 
26 #define tcp_slist(_conn, _slist, _op, _type, _link)			\
27 ({									\
28 	k_mutex_lock(&_conn->lock, K_FOREVER);				\
29 									\
30 	sys_snode_t *_node = sys_slist_##_op(_slist);			\
31 									\
32 	_type * _x = _node ? CONTAINER_OF(_node, _type, _link) : NULL;	\
33 									\
34 	k_mutex_unlock(&_conn->lock);					\
35 									\
36 	_x;								\
37 })
38 
39 #if defined(CONFIG_NET_TEST_PROTOCOL)
40 #define tcp_malloc(_size) \
41 	tp_malloc(_size, tp_basename(__FILE__), __LINE__, __func__)
42 #define tcp_calloc(_nmemb, _size) \
43 	tp_calloc(_nmemb, _size, tp_basename(__FILE__), __LINE__, __func__)
44 #define tcp_free(_ptr) tp_free(_ptr, tp_basename(__FILE__), __LINE__, __func__)
45 #else
46 #define tcp_malloc(_size) k_malloc(_size)
47 #define tcp_calloc(_nmemb, _size) k_calloc(_nmemb, _size)
48 #define tcp_free(_ptr) k_free(_ptr)
49 #endif
50 
51 #define TCP_PKT_ALLOC_TIMEOUT K_MSEC(CONFIG_NET_TCP_PKT_ALLOC_TIMEOUT)
52 
53 #if defined(CONFIG_NET_TEST_PROTOCOL)
54 #define tcp_pkt_clone(_pkt) tp_pkt_clone(_pkt, tp_basename(__FILE__), __LINE__)
55 #define tcp_pkt_unref(_pkt) tp_pkt_unref(_pkt, tp_basename(__FILE__), __LINE__)
56 #else
57 #define tcp_pkt_clone(_pkt) net_pkt_clone(_pkt, TCP_PKT_ALLOC_TIMEOUT)
58 #define tcp_pkt_unref(_pkt) net_pkt_unref(_pkt)
59 #define tp_pkt_alloc(args...)
60 #endif
61 
62 #define tcp_pkt_ref(_pkt) net_pkt_ref(_pkt)
63 #define tcp_pkt_alloc(_conn, _len)					\
64 ({									\
65 	struct net_pkt *_pkt;						\
66 									\
67 	if ((_len) > 0) {						\
68 		_pkt = net_pkt_alloc_with_buffer(			\
69 			(_conn)->iface,					\
70 			(_len),						\
71 			net_context_get_family((_conn)->context),	\
72 			IPPROTO_TCP,					\
73 			TCP_PKT_ALLOC_TIMEOUT);				\
74 	} else {							\
75 		_pkt = net_pkt_alloc(TCP_PKT_ALLOC_TIMEOUT);		\
76 	}								\
77 									\
78 	tp_pkt_alloc(_pkt, tp_basename(__FILE__), __LINE__);		\
79 									\
80 	_pkt;								\
81 })
82 
83 #define tcp_rx_pkt_alloc(_conn, _len)					\
84 ({									\
85 	struct net_pkt *_pkt;						\
86 									\
87 	if ((_len) > 0) {						\
88 		_pkt = net_pkt_rx_alloc_with_buffer(			\
89 			(_conn)->iface,					\
90 			(_len),						\
91 			net_context_get_family((_conn)->context),	\
92 			IPPROTO_TCP,					\
93 			TCP_PKT_ALLOC_TIMEOUT);				\
94 	} else {							\
95 		_pkt = net_pkt_rx_alloc(TCP_PKT_ALLOC_TIMEOUT);		\
96 	}								\
97 									\
98 	tp_pkt_alloc(_pkt, tp_basename(__FILE__), __LINE__);		\
99 									\
100 	_pkt;								\
101 })
102 
103 #define tcp_pkt_alloc_no_conn(_iface, _family, _len)			\
104 ({									\
105 	struct net_pkt *_pkt;						\
106 									\
107 	if ((_len) > 0) {						\
108 		_pkt = net_pkt_alloc_with_buffer(			\
109 			(_iface), (_len), (_family),			\
110 			IPPROTO_TCP,					\
111 			TCP_PKT_ALLOC_TIMEOUT);				\
112 	} else {							\
113 		_pkt = net_pkt_alloc(TCP_PKT_ALLOC_TIMEOUT);		\
114 	}								\
115 									\
116 	tp_pkt_alloc(_pkt, tp_basename(__FILE__), __LINE__);		\
117 									\
118 	_pkt;								\
119 })
120 
121 #if defined(CONFIG_NET_TEST_PROTOCOL)
122 #define conn_seq(_conn, _req) \
123 	tp_seq_track(TP_SEQ, &(_conn)->seq, (_req), tp_basename(__FILE__), \
124 			__LINE__, __func__)
125 #define conn_ack(_conn, _req) \
126 	tp_seq_track(TP_ACK, &(_conn)->ack, (_req), tp_basename(__FILE__), \
127 			__LINE__, __func__)
128 #else
129 #define conn_seq(_conn, _req) (_conn)->seq += (_req)
130 #define conn_ack(_conn, _req) (_conn)->ack += (_req)
131 #endif
132 
133 #define NET_TCP_DEFAULT_MSS 536
134 
135 #define conn_mss(_conn)							\
136 	MIN((_conn)->recv_options.mss_found ? (_conn)->recv_options.mss	\
137 					    : NET_TCP_DEFAULT_MSS,	\
138 	    net_tcp_get_supported_mss(_conn))
139 
140 #define conn_state(_conn, _s)						\
141 ({									\
142 	NET_DBG("%s->%s",						\
143 		tcp_state_to_str((_conn)->state, false),		\
144 		tcp_state_to_str((_s), false));				\
145 	(_conn)->state = _s;						\
146 })
147 
148 #define conn_send_data_dump(_conn)                                             \
149 	({                                                                     \
150 		NET_DBG("conn: %p total=%zd, unacked_len=%d, "                 \
151 			"send_win=%hu, mss=%hu",                               \
152 			(_conn), net_pkt_get_len((_conn)->send_data),          \
153 			_conn->unacked_len, _conn->send_win,                   \
154 			(uint16_t)conn_mss((_conn)));                          \
155 		NET_DBG("conn: %p send_data_timer=%hu, send_data_retries=%hu", \
156 			(_conn),                                               \
157 			(bool)k_ticks_to_ms_ceil32(                            \
158 				k_work_delayable_remaining_get(                \
159 					&(_conn)->send_data_timer)),           \
160 			(_conn)->send_data_retries);                           \
161 	})
162 
163 enum pkt_addr {
164 	TCP_EP_SRC = 1,
165 	TCP_EP_DST = 0
166 };
167 
168 struct tcphdr {
169 	uint16_t th_sport;
170 	uint16_t th_dport;
171 	uint32_t th_seq;
172 	uint32_t th_ack;
173 #ifdef CONFIG_LITTLE_ENDIAN
174 	uint8_t th_x2:4;	/* unused */
175 	uint8_t th_off:4;	/* data offset, in units of 32-bit words */
176 #else
177 	uint8_t th_off:4;
178 	uint8_t th_x2:4;
179 #endif
180 	uint8_t th_flags;
181 	uint16_t th_win;
182 	uint16_t th_sum;
183 	uint16_t th_urp;
184 } __packed;
185 
186 enum th_flags {
187 	FIN = BIT(0),
188 	SYN = BIT(1),
189 	RST = BIT(2),
190 	PSH = BIT(3),
191 	ACK = BIT(4),
192 	URG = BIT(5),
193 	ECN = BIT(6),
194 	CWR = BIT(7),
195 };
196 
197 struct tcp_mss_option {
198 	uint32_t option;
199 };
200 
201 enum tcp_state {
202 	TCP_UNUSED = 0,
203 	TCP_CLOSED,
204 	TCP_LISTEN,
205 	TCP_SYN_SENT,
206 	TCP_SYN_RECEIVED,
207 	TCP_ESTABLISHED,
208 	TCP_FIN_WAIT_1,
209 	TCP_FIN_WAIT_2,
210 	TCP_CLOSE_WAIT,
211 	TCP_CLOSING,
212 	TCP_LAST_ACK,
213 	TCP_TIME_WAIT
214 };
215 
216 enum tcp_data_mode {
217 	TCP_DATA_MODE_SEND = 0,
218 	TCP_DATA_MODE_RESEND = 1
219 };
220 
221 union tcp_endpoint {
222 	struct sockaddr sa;
223 	struct sockaddr_in sin;
224 	struct sockaddr_in6 sin6;
225 };
226 
227 /* TCP Option codes */
228 #define NET_TCP_END_OPT          0
229 #define NET_TCP_NOP_OPT          1
230 #define NET_TCP_MSS_OPT          2
231 #define NET_TCP_WINDOW_SCALE_OPT 3
232 
233 /* TCP Option sizes */
234 #define NET_TCP_END_SIZE          1
235 #define NET_TCP_NOP_SIZE          1
236 #define NET_TCP_MSS_SIZE          4
237 #define NET_TCP_WINDOW_SCALE_SIZE 3
238 
239 struct tcp_options {
240 	uint16_t mss;
241 	uint16_t window;
242 	bool mss_found : 1;
243 	bool wnd_found : 1;
244 };
245 
246 #ifdef CONFIG_NET_TCP_CONGESTION_AVOIDANCE
247 
248 struct tcp_collision_avoidance_reno {
249 	uint16_t cwnd;
250 	uint16_t ssthresh;
251 	uint16_t pending_fast_retransmit_bytes;
252 };
253 #endif
254 
255 struct tcp;
256 typedef void (*net_tcp_closed_cb_t)(struct tcp *conn, void *user_data);
257 
258 struct tcp { /* TCP connection */
259 	sys_snode_t next;
260 	struct net_context *context;
261 	struct net_pkt *send_data;
262 	struct net_pkt *queue_recv_data;
263 	struct net_if *iface;
264 	void *recv_user_data;
265 	sys_slist_t send_queue;
266 	union {
267 		net_tcp_accept_cb_t accept_cb;
268 		struct tcp *accepted_conn;
269 	};
270 	net_context_connect_cb_t connect_cb;
271 #if defined(CONFIG_NET_TEST)
272 	net_tcp_closed_cb_t test_closed_cb;
273 	void *test_user_data;
274 #endif
275 	struct k_mutex lock;
276 	struct k_sem connect_sem; /* semaphore for blocking connect */
277 	struct k_sem tx_sem; /* Semaphore indicating if transfers are blocked . */
278 	struct k_fifo recv_data;  /* temp queue before passing data to app */
279 	struct tcp_options recv_options;
280 	struct tcp_options send_options;
281 	struct k_work_delayable send_timer;
282 	struct k_work_delayable recv_queue_timer;
283 	struct k_work_delayable send_data_timer;
284 	struct k_work_delayable timewait_timer;
285 	struct k_work_delayable persist_timer;
286 	struct k_work_delayable ack_timer;
287 #if defined(CONFIG_NET_TCP_KEEPALIVE)
288 	struct k_work_delayable keepalive_timer;
289 #endif /* CONFIG_NET_TCP_KEEPALIVE */
290 	struct k_work conn_release;
291 
292 	union {
293 		/* Because FIN and establish timers are never happening
294 		 * at the same time, share the timer between them to
295 		 * save memory.
296 		 */
297 		struct k_work_delayable fin_timer;
298 		struct k_work_delayable establish_timer;
299 	};
300 	union tcp_endpoint src;
301 	union tcp_endpoint dst;
302 #if defined(CONFIG_NET_TCP_IPV6_ND_REACHABILITY_HINT)
303 	int64_t last_nd_hint_time;
304 #endif
305 	size_t send_data_total;
306 	int unacked_len;
307 	atomic_t ref_count;
308 	enum tcp_state state;
309 	enum tcp_data_mode data_mode;
310 	uint32_t seq;
311 	uint32_t ack;
312 #if defined(CONFIG_NET_TCP_KEEPALIVE)
313 	uint32_t keep_idle;
314 	uint32_t keep_intvl;
315 	uint32_t keep_cnt;
316 	uint32_t keep_cur;
317 #endif /* CONFIG_NET_TCP_KEEPALIVE */
318 	uint16_t recv_win_sent;
319 	uint16_t recv_win_max;
320 	uint16_t recv_win;
321 	uint16_t send_win_max;
322 	uint16_t send_win;
323 #ifdef CONFIG_NET_TCP_RANDOMIZED_RTO
324 	uint16_t rto;
325 #endif
326 #ifdef CONFIG_NET_TCP_CONGESTION_AVOIDANCE
327 	struct tcp_collision_avoidance_reno ca;
328 #endif
329 	uint8_t send_data_retries;
330 #ifdef CONFIG_NET_TCP_FAST_RETRANSMIT
331 	uint8_t dup_ack_cnt;
332 #endif
333 	uint8_t zwp_retries;
334 	bool in_connect : 1;
335 	bool in_close : 1;
336 #if defined(CONFIG_NET_TCP_KEEPALIVE)
337 	bool keep_alive : 1;
338 #endif /* CONFIG_NET_TCP_KEEPALIVE */
339 	bool tcp_nodelay : 1;
340 	bool addr_ref_done : 1;
341 	bool rst_received : 1;
342 };
343 
344 #define _flags(_fl, _op, _mask, _cond)					\
345 ({									\
346 	bool result = false;						\
347 									\
348 	if (UNALIGNED_GET(_fl) && (_cond) &&				\
349 	    (UNALIGNED_GET(_fl) _op(_mask))) {				\
350 		UNALIGNED_PUT(UNALIGNED_GET(_fl) & ~(_mask), _fl);	\
351 		result = true;						\
352 	}								\
353 									\
354 	result;								\
355 })
356 
357 #define FL(_fl, _op, _mask, _args...)					\
358 	_flags(_fl, _op, _mask, sizeof(#_args) > 1 ? _args : true)
359 
360 typedef void (*net_tcp_cb_t)(struct tcp *conn, void *user_data);
361 
362 #if defined(CONFIG_NET_TEST)
363 void tcp_install_close_cb(struct net_context *ctx,
364 			  net_tcp_closed_cb_t cb,
365 			  void *user_data);
366 #endif
367