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