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