1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** NetX Component */
16 /** */
17 /** Transmission Control Protocol (TCP) */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define NX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "nx_api.h"
28 #include "nx_tcp.h"
29 #include "nx_packet.h"
30 #ifdef NX_ENABLE_HTTP_PROXY
31 #include "nx_http_proxy_client.h"
32 #endif /* NX_ENABLE_HTTP_PROXY */
33
34
35 /**************************************************************************/
36 /* */
37 /* FUNCTION RELEASE */
38 /* */
39 /* _nx_tcp_socket_packet_process PORTABLE C */
40 /* 6.2.0 */
41 /* AUTHOR */
42 /* */
43 /* Yuxin Zhou, Microsoft Corporation */
44 /* */
45 /* DESCRIPTION */
46 /* */
47 /* This function processes an incoming TCP packet relative to the */
48 /* socket it belongs to, including processing state changes, and */
49 /* sending and receiving data. */
50 /* */
51 /* INPUT */
52 /* */
53 /* socket_ptr Pointer to owning socket */
54 /* packet_ptr Pointer to packet to process */
55 /* */
56 /* OUTPUT */
57 /* */
58 /* None */
59 /* */
60 /* CALLS */
61 /* */
62 /* _nx_packet_release Packet release function */
63 /* _nx_tcp_socket_connection_reset Reset connection */
64 /* _nx_tcp_socket_state_ack_check Process received ACKs */
65 /* _nx_tcp_socket_state_closing Process CLOSING state */
66 /* _nx_tcp_socket_state_data_check Process received data */
67 /* _nx_tcp_socket_state_established Process ESTABLISHED state */
68 /* _nx_tcp_socket_state_fin_wait1 Process FIN WAIT 1 state */
69 /* _nx_tcp_socket_state_fin_wait2 Process FIN WAIT 2 state */
70 /* _nx_tcp_socket_state_last_ack Process LAST ACK state */
71 /* _nx_tcp_socket_state_syn_received Process SYN RECEIVED state */
72 /* _nx_tcp_socket_state_syn_sent Process SYN SENT state */
73 /* _nx_tcp_socket_state_transmit_check Check for transmit ability */
74 /* (nx_tcp_urgent_data_callback) Application urgent callback */
75 /* function */
76 /* _nx_http_proxy_client_connect_response_process */
77 /* Process HTTP Proxy CONNECT */
78 /* response */
79 /* */
80 /* CALLED BY */
81 /* */
82 /* _nx_tcp_packet_process Process raw TCP packet */
83 /* */
84 /* RELEASE HISTORY */
85 /* */
86 /* DATE NAME DESCRIPTION */
87 /* */
88 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
89 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
90 /* resulting in version 6.1 */
91 /* 08-02-2021 Yuxin Zhou Modified comment(s), and */
92 /* supported TCP/IP offload, */
93 /* resulting in version 6.1.8 */
94 /* 01-31-2022 Yuxin Zhou Modified comment(s), and */
95 /* fixed unsigned integers */
96 /* comparison, */
97 /* resulting in version 6.1.10 */
98 /* 10-31-2022 Wenhui Xie Modified comment(s), and */
99 /* supported HTTP Proxy, */
100 /* resulting in version 6.2.0 */
101 /* */
102 /**************************************************************************/
_nx_tcp_socket_packet_process(NX_TCP_SOCKET * socket_ptr,NX_PACKET * packet_ptr)103 VOID _nx_tcp_socket_packet_process(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr)
104 {
105
106 UINT packet_queued = NX_FALSE;
107 NX_TCP_HEADER tcp_header_copy;
108 VOID (*urgent_callback)(NX_TCP_SOCKET *socket_ptr);
109 ULONG header_length;
110 ULONG packet_data_length;
111 ULONG packet_sequence;
112 ULONG rx_sequence;
113 ULONG rx_window;
114 UINT outside_of_window;
115 ULONG mss = 0;
116 #ifdef NX_ENABLE_TCPIP_OFFLOAD
117 ULONG tcpip_offload;
118
119 tcpip_offload = socket_ptr -> nx_tcp_socket_connect_interface -> nx_interface_capability_flag &
120 NX_INTERFACE_CAPABILITY_TCPIP_OFFLOAD;
121 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
122
123 /* Add debug information. */
124 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
125
126 /* Copy the TCP header, since the actual packet can be delivered to
127 a waiting socket/thread during this routine and before we are done
128 using the header. */
129 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
130 tcp_header_copy = *((NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr);
131
132 /* Get the size of the TCP header. */
133 header_length = (tcp_header_copy.nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * (ULONG)sizeof(ULONG);
134
135 /* Process the segment if socket state is equal or greater than NX_TCP_SYN_RECEIVED. According to RFC 793, Section 3.9, Page 69. */
136 if ((socket_ptr -> nx_tcp_socket_state >= NX_TCP_SYN_RECEIVED)
137 #ifdef NX_ENABLE_TCPIP_OFFLOAD
138 && (!tcpip_offload)
139 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
140 )
141 {
142
143 /* Step1: Check sequence number. According to RFC 793, Section 3.9, Page 69. */
144
145 /* Pickup the sequence of this packet. */
146 packet_sequence = tcp_header_copy.nx_tcp_sequence_number;
147
148 /* Calculate the data length in the packet. */
149 packet_data_length = packet_ptr -> nx_packet_length - header_length;
150
151 /* Pickup the rx sequence. */
152 rx_sequence = socket_ptr -> nx_tcp_socket_rx_sequence;
153
154 #ifdef NX_ENABLE_LOW_WATERMARK
155 if ((socket_ptr -> nx_tcp_socket_rx_window_current == 0) &&
156 (socket_ptr -> nx_tcp_socket_receive_queue_head == NX_NULL) &&
157 (packet_ptr -> nx_packet_pool_owner -> nx_packet_pool_available >=
158 packet_ptr -> nx_packet_pool_owner -> nx_packet_pool_low_watermark))
159 {
160
161 /* Window was closed due to low watermark of packet pool. */
162 /* Now reset the window size. */
163 socket_ptr -> nx_tcp_socket_rx_window_current = socket_ptr -> nx_tcp_socket_rx_window_default;
164 }
165 #endif /* NX_ENABLE_LOW_WATERMARK */
166
167 /* Pickup the rx window. */
168 rx_window = socket_ptr -> nx_tcp_socket_rx_window_current;
169
170 /* There are four cases for the acceptability test for an incoming segment.
171 Section 3.9 Page 69, RFC 793. */
172 outside_of_window = NX_TRUE;
173
174 if (packet_data_length == 0)
175 {
176 if (rx_window == 0)
177 {
178 if (packet_sequence == rx_sequence)
179 {
180 outside_of_window = NX_FALSE;
181 }
182 else if ((tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_RST_BIT) ||
183 (tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_URG_BIT) ||
184 ((tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_CONTROL_MASK) == NX_TCP_ACK_BIT))
185 {
186
187 /* If the RCV.WND is zero, no segments will be acceptable, but
188 special allowance should be made to accept valid ACKs, URGs and RSTs.
189 Section 3.9 Page 69, RFC 793. */
190 outside_of_window = NX_FALSE;
191 }
192 }
193 else if (((INT)(packet_sequence - rx_sequence) >= 0) &&
194 ((INT)(rx_sequence + rx_window - packet_sequence) > 0))
195 {
196 outside_of_window = NX_FALSE;
197 }
198 }
199 else
200 {
201 if ((rx_window > 0) &&
202 ((((INT)(packet_sequence - rx_sequence) >= 0) &&
203 ((INT)(rx_sequence + rx_window - packet_sequence) > 0)) ||
204 (((INT)(packet_sequence + (packet_data_length - 1) - rx_sequence) >= 0) &&
205 ((INT)(rx_sequence + 1 + (rx_window - packet_sequence) - packet_data_length) > 0))))
206 {
207 outside_of_window = NX_FALSE;
208 }
209 }
210
211 /* Detect whether or not the data is outside the window. */
212 if (outside_of_window)
213 {
214
215 /* If an incoming segment is not acceptable, an acknowledgment should be sent in reply
216 (unless the RST bit is set, if so drop the segment and return).
217 Section 3.9, Page 69, RFC 793. */
218 if (!(tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_RST_BIT))
219 {
220
221 /* Send an immediate ACK. */
222 _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence);
223 }
224
225 #ifndef NX_DISABLE_TCP_INFO
226
227 /* Increment the TCP dropped packet count. */
228 socket_ptr -> nx_tcp_socket_ip_ptr -> nx_ip_tcp_receive_packets_dropped++;
229 #endif
230
231 /* Release the packet. */
232 _nx_packet_release(packet_ptr);
233
234 /* Finished processing, simply return! */
235 return;
236 }
237
238 /* Step2: Check the RST bit. According to RFC 793, Section 3.9, Page 70. */
239 if (tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_RST_BIT)
240 {
241
242 #ifndef NX_DISABLE_TCP_INFO
243
244 /* Increment the resets received count. */
245 (socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_resets_received++;
246 #endif
247
248 /* If trace is enabled, insert this event into the trace buffer. */
249 NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_RESET_RECEIVE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, packet_ptr, tcp_header_copy.nx_tcp_sequence_number, NX_TRACE_INTERNAL_EVENTS, 0, 0);
250
251 /* Reset connection. */
252 _nx_tcp_socket_connection_reset(socket_ptr);
253
254 /* Release the packet. */
255 _nx_packet_release(packet_ptr);
256
257 /* Finished processing, simply return! */
258 return;
259 }
260
261 /* Step3: Check the SYN bit. According to RFC 793, Section 3.9, Page 71. */
262 if (tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_SYN_BIT)
263 {
264
265 /* The SYN is in the window it is an error, send a reset. */
266
267 /* Adjust the SEQ for the SYN bit. */
268 /* The reset logic uses the sequence number in tcp_header_ptr as its ACK number. */
269 tcp_header_copy.nx_tcp_sequence_number++;
270
271 /* Send RST message. */
272 _nx_tcp_packet_send_rst(socket_ptr, &tcp_header_copy);
273
274 /* Reset the connection. */
275 _nx_tcp_socket_connection_reset(socket_ptr);
276
277 /* Release the packet. */
278 _nx_packet_release(packet_ptr);
279
280 /* Finished processing, simply return! */
281 return;
282 }
283
284 /* Step4: Check the ACK field. According to RFC 793, Section 3.9, Page 72. */
285 if (socket_ptr -> nx_tcp_socket_state != NX_TCP_SYN_RECEIVED)
286 {
287
288 /* Check the ACK field. */
289 if (_nx_tcp_socket_state_ack_check(socket_ptr, &tcp_header_copy) == NX_FALSE)
290 {
291
292 /* Release the packet. */
293 _nx_packet_release(packet_ptr);
294
295 /* Finished processing, simply return! */
296 return;
297 }
298 }
299 }
300
301 /* Illegal option length check. */
302 if (header_length > sizeof(NX_TCP_HEADER))
303 {
304
305 /* There are one or more option words. */
306 /* The illegal option length is validated during MSS option get function. */
307 if (!_nx_tcp_mss_option_get((packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_TCP_HEADER)),
308 header_length - (ULONG)sizeof(NX_TCP_HEADER), &mss))
309 {
310
311 /* TCP MUST be prepared to handle an illegal option length (e.g., zero) without crashing;
312 a suggested procedure is to reset the connection and log the reason, outlined in RFC 1122, Section 4.2.2.5, Page85. */
313
314 /* Preprocess the sequence number if the incoming segment does not have an ACK field.
315 Reset Generation, RFC793, Section3.4, Page37. */
316 if (!(tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_ACK_BIT))
317 {
318
319 /* Update sequence number to set the reset acknowledge number. */
320 tcp_header_copy.nx_tcp_sequence_number += (packet_ptr -> nx_packet_length - header_length);
321
322 /* Check the SYN and FIN bits. */
323 if ((tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_SYN_BIT) ||
324 (tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_FIN_BIT))
325 {
326
327 /* Update sequence number to set the reset acknowledge number. */
328 tcp_header_copy.nx_tcp_sequence_number++;
329 }
330 }
331
332 /* Send RST message. */
333 _nx_tcp_packet_send_rst(socket_ptr, &tcp_header_copy);
334
335 /* Reset the connection. */
336 _nx_tcp_socket_connection_reset(socket_ptr);
337
338 #ifndef NX_DISABLE_TCP_INFO
339 /* Increment the TCP invalid packet error count. */
340 socket_ptr -> nx_tcp_socket_ip_ptr -> nx_ip_tcp_invalid_packets++;
341 #endif /* NX_DISABLE_TCP_INFO */
342
343 /* Release the packet. */
344 _nx_packet_release(packet_ptr);
345
346 return;
347 }
348
349 }
350
351 /* Process relative to the state of the socket. */
352 switch (socket_ptr -> nx_tcp_socket_state)
353 {
354
355 case NX_TCP_SYN_SENT:
356
357 /* Call the SYN SENT state handling function to process any state
358 changes caused by this new packet. */
359 _nx_tcp_socket_state_syn_sent(socket_ptr, &tcp_header_copy, packet_ptr);
360
361 /* Check whether socket is established. */
362 if (socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED)
363 {
364
365 /* Check for data in the current packet. */
366 packet_queued = _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr);
367 }
368
369 /* State processing is complete. */
370 break;
371
372 case NX_TCP_SYN_RECEIVED:
373
374 /* Call the SYN RECEIVED state handling function to process any state
375 changes caused by this new packet. */
376 _nx_tcp_socket_state_syn_received(socket_ptr, &tcp_header_copy);
377
378 /* Check whether socket is established. */
379 if (socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED)
380 {
381
382 /* Check for data in the current packet. */
383 packet_queued = _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr);
384 }
385
386 /* State processing is complete. */
387 break;
388
389 case NX_TCP_ESTABLISHED:
390
391 /* Check for data in the current packet. */
392 packet_queued = _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr);
393
394 #ifdef NX_ENABLE_TCPIP_OFFLOAD
395 if (!tcpip_offload)
396 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
397 {
398
399 /* Call the ESTABLISHED state handling function to process any state
400 changes caused by this new packet. */
401 _nx_tcp_socket_state_established(socket_ptr);
402
403 /* Determine if any transmit suspension can be lifted. */
404 _nx_tcp_socket_state_transmit_check(socket_ptr);
405 }
406
407 /* State processing is complete. */
408 break;
409
410 case NX_TCP_CLOSE_WAIT:
411
412 /* Determine if any transmit suspension can be lifted. */
413 _nx_tcp_socket_state_transmit_check(socket_ptr);
414
415 /* State processing is complete. */
416 break;
417
418 case NX_TCP_LAST_ACK:
419
420 /* Call the LAST ACK state handling function to process any state
421 changes caused by this new packet. */
422 _nx_tcp_socket_state_last_ack(socket_ptr, &tcp_header_copy);
423
424 /* State processing is complete. */
425 break;
426
427 case NX_TCP_FIN_WAIT_1:
428
429 /* Check for data in the current packet. */
430 packet_queued = _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr);
431
432 /* Call the FIN WAIT 1 state handling function to process any state
433 changes caused by this new packet. */
434 _nx_tcp_socket_state_fin_wait1(socket_ptr);
435
436 /* State processing is complete. */
437 break;
438
439 case NX_TCP_FIN_WAIT_2:
440
441 /* Check for data in the current packet. */
442 packet_queued = _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr);
443
444 /* Call the FIN WAIT 2 state handling function to process any state
445 changes caused by this new packet. */
446 _nx_tcp_socket_state_fin_wait2(socket_ptr);
447
448 /* State processing is complete. */
449 break;
450
451 case NX_TCP_CLOSING:
452
453 /* Call the CLOSING state handling function to process any state
454 changes caused by this new packet. */
455 _nx_tcp_socket_state_closing(socket_ptr, &tcp_header_copy);
456
457 /* State processing is complete. */
458 break;
459
460 case NX_TCP_TIMED_WAIT:
461
462 /* State processing is complete. */
463 break;
464
465 default:
466 break;
467 }
468
469 #ifdef NX_ENABLE_HTTP_PROXY
470
471 /* Check if HTTP Proxy is started and waiting for the response form the HTTP Proxy server. */
472 if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) &&
473 (socket_ptr -> nx_tcp_socket_ip_ptr -> nx_ip_http_proxy_enable) &&
474 (socket_ptr -> nx_tcp_socket_http_proxy_state == NX_HTTP_PROXY_STATE_CONNECTING))
475 {
476
477 /* Receive and process the response. */
478 _nx_http_proxy_client_connect_response_process(socket_ptr);
479 }
480 #endif /* NX_ENABLE_HTTP_PROXY */
481
482 /* Check for an URG (urgent) bit set. */
483 /*lint -e{644} suppress variable might not be initialized, since "tcp_header_copy" was initialized. */
484 if (tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_URG_BIT)
485 {
486
487 /* Yes, an Urgent bit is set. */
488
489 /* Pickup the urgent callback function specified when the socket was created. */
490 urgent_callback = socket_ptr -> nx_tcp_urgent_data_callback;
491
492 /* Determine if there is an urgent callback function specified. */
493 if (urgent_callback)
494 {
495
496 /* Yes, call the application's urgent callback function to alert the application
497 of the presence of the urgent bit. */
498 (urgent_callback)(socket_ptr);
499 }
500 }
501
502 /* Determine if we need to release the packet. */
503 if (!packet_queued)
504 {
505
506 /* Yes, the packet was not queued up above, so it needs to be released. */
507 _nx_packet_release(packet_ptr);
508 }
509 }
510
511