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