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