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_ip.h"
29 #ifdef FEATURE_NX_IPV6
30 #include "nx_ipv6.h"
31 #endif /* FEATURE_NX_IPV6 */
32 #include "nx_packet.h"
33 #include "nx_tcp.h"
34 #include "tx_thread.h"
35 #ifdef NX_IPSEC_ENABLE
36 #include "nx_ipsec.h"
37 #endif /* NX_IPSEC_ENABLE */
38 
39 
40 #ifdef NX_ENABLE_TCPIP_OFFLOAD
41 /**************************************************************************/
42 /*                                                                        */
43 /*  FUNCTION                                               RELEASE        */
44 /*                                                                        */
45 /*    _nx_tcp_socket_driver_send                          PORTABLE C      */
46 /*                                                           6.4.0        */
47 /*  AUTHOR                                                                */
48 /*                                                                        */
49 /*    Yuxin Zhou, Microsoft Corporation                                   */
50 /*                                                                        */
51 /*  DESCRIPTION                                                           */
52 /*                                                                        */
53 /*    This function sends a TCP packet through TCP/IP offload interface.  */
54 /*                                                                        */
55 /*  INPUT                                                                 */
56 /*                                                                        */
57 /*    socket_ptr                            Pointer to socket             */
58 /*    packet_ptr                            Pointer to packet to send     */
59 /*    wait_option                           Suspension option             */
60 /*                                                                        */
61 /*  OUTPUT                                                                */
62 /*                                                                        */
63 /*    status                                Completion status             */
64 /*                                                                        */
65 /*  CALLS                                                                 */
66 /*                                                                        */
67 /*    _nx_ip_packet_send                    Packet send function          */
68 /*    _nx_ipv6_packet_send                  Packet send function          */
69 /*                                                                        */
70 /*  CALLED BY                                                             */
71 /*                                                                        */
72 /*    _nx_tcp_socket_send_internal                                        */
73 /*                                                                        */
74 /*  RELEASE HISTORY                                                       */
75 /*                                                                        */
76 /*    DATE              NAME                      DESCRIPTION             */
77 /*                                                                        */
78 /*  08-02-2021     Yuxin Zhou               Initial Version 6.1.8         */
79 /*  12-31-2023     Yajun Xia                Modified comment(s),          */
80 /*                                            supported VLAN,             */
81 /*                                            resulting in version 6.4.0  */
82 /*                                                                        */
83 /**************************************************************************/
_nx_tcp_socket_driver_send(NX_TCP_SOCKET * socket_ptr,NX_PACKET * packet_ptr,ULONG wait_option)84 static UINT _nx_tcp_socket_driver_send(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr, ULONG wait_option)
85 {
86 UINT            status;
87 NX_IP          *ip_ptr;
88 NX_INTERFACE   *interface_ptr = socket_ptr -> nx_tcp_socket_connect_interface;
89 #ifdef NX_ENABLE_IP_PACKET_FILTER
90 UCHAR          *original_ptr = packet_ptr -> nx_packet_prepend_ptr;
91 ULONG           original_length = packet_ptr -> nx_packet_length;
92 NX_TCP_HEADER  *header_ptr;
93 #endif /* NX_ENABLE_IP_PACKET_FILTER */
94 
95     /* Setup the pointer to the associated IP instance.  */
96     ip_ptr =  socket_ptr -> nx_tcp_socket_ip_ptr;
97 
98 #ifdef NX_ENABLE_IP_PACKET_FILTER
99     /* Check if the IP packet filter is set. */
100     if (ip_ptr -> nx_ip_packet_filter || ip_ptr -> nx_ip_packet_filter_extended)
101     {
102 
103         /* Yes, add the TCP and IP Header to trigger filtering.  */
104         /* Prepend the TCP header to the packet.  First, make room for the TCP header.  */
105         packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_TCP_HEADER);
106 
107         /* Add the length of the TCP header.  */
108         packet_ptr -> nx_packet_length =  packet_ptr -> nx_packet_length + (ULONG)sizeof(NX_TCP_HEADER);
109 
110         /* Pickup the pointer to the head of the TCP packet.  */
111         /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
112         header_ptr =  (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
113 
114         /* Build the output request in the TCP header.  */
115         header_ptr -> nx_tcp_header_word_0 = (((ULONG)(socket_ptr -> nx_tcp_socket_port)) << NX_SHIFT_BY_16) |
116                                                 (ULONG)socket_ptr -> nx_tcp_socket_connect_port;
117         header_ptr -> nx_tcp_acknowledgment_number = 0;
118         header_ptr -> nx_tcp_sequence_number = 0;
119         header_ptr -> nx_tcp_header_word_3 = NX_TCP_HEADER_SIZE | NX_TCP_ACK_BIT | NX_TCP_PSH_BIT;
120         header_ptr -> nx_tcp_header_word_4 = 0;
121 
122         /* Endian swapping logic.  If NX_LITTLE_ENDIAN is specified, these macros will
123             swap the endian of the TCP header.  */
124         NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_0);
125         NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_3);
126 
127 #ifndef NX_DISABLE_IPV4
128         if (socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V4)
129         {
130             _nx_ip_header_add(ip_ptr, packet_ptr,
131                               socket_ptr -> nx_tcp_socket_connect_interface -> nx_interface_ip_address,
132                               socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_address.v4,
133                               socket_ptr -> nx_tcp_socket_type_of_service,
134                               socket_ptr -> nx_tcp_socket_time_to_live,
135                               NX_IP_TCP,
136                               socket_ptr -> nx_tcp_socket_fragment_enable);
137         }
138 #endif /* !NX_DISABLE_IPV4  */
139 
140 #ifdef FEATURE_NX_IPV6
141         if (socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6)
142         {
143             if (_nx_ipv6_header_add(ip_ptr, &packet_ptr,
144                                     NX_PROTOCOL_TCP,
145                                     packet_ptr -> nx_packet_length,
146                                     ip_ptr -> nx_ipv6_hop_limit,
147                                     socket_ptr -> nx_tcp_socket_ipv6_addr -> nxd_ipv6_address,
148                                     socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_address.v6,
149                                     NX_NULL))
150             {
151 
152                 /* Invalid interface address. Just return success.  */
153                 return(NX_SUCCESS);
154             }
155         }
156 #endif /* FEATURE_NX_IPV6 */
157 
158         if (ip_ptr -> nx_ip_packet_filter)
159         {
160             if (ip_ptr -> nx_ip_packet_filter((VOID *)(packet_ptr -> nx_packet_prepend_ptr),
161                                               NX_IP_PACKET_OUT) != NX_SUCCESS)
162             {
163 
164                 /* Packet consumed by IP filter. Just return success.  */
165                 _nx_packet_transmit_release(packet_ptr);
166                 return(NX_SUCCESS);
167             }
168         }
169 
170         /* Check if the IP packet filter extended is set. */
171         if (ip_ptr -> nx_ip_packet_filter_extended)
172         {
173 
174             /* Yes, call the IP packet filter extended routine. */
175             if (ip_ptr -> nx_ip_packet_filter_extended(ip_ptr, packet_ptr, NX_IP_PACKET_OUT) != NX_SUCCESS)
176             {
177 
178                 /* Packet consumed by IP filter. Just return success.  */
179                 _nx_packet_transmit_release(packet_ptr);
180                 return(NX_SUCCESS);
181             }
182         }
183 
184         /* Reset UDP and IP header.  */
185         packet_ptr -> nx_packet_prepend_ptr = original_ptr;
186         packet_ptr -> nx_packet_length = original_length;
187     }
188 #endif /* NX_ENABLE_IP_PACKET_FILTER */
189 
190     /* Let TCP/IP offload interface send the packet.  */
191     status = interface_ptr -> nx_interface_tcpip_offload_handler(ip_ptr, interface_ptr, socket_ptr,
192                                                                  NX_TCPIP_OFFLOAD_TCP_SOCKET_SEND,
193                                                                  packet_ptr, NX_NULL, NX_NULL, 0, NX_NULL,
194                                                                  wait_option);
195 
196     if (status)
197     {
198         return(NX_TCPIP_OFFLOAD_ERROR);
199     }
200     else
201     {
202         return(NX_SUCCESS);
203     }
204 }
205 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
206 
207 /**************************************************************************/
208 /*                                                                        */
209 /*  FUNCTION                                               RELEASE        */
210 /*                                                                        */
211 /*    _nx_tcp_socket_send_internal                        PORTABLE C      */
212 /*                                                           6.1.10       */
213 /*  AUTHOR                                                                */
214 /*                                                                        */
215 /*    Yuxin Zhou, Microsoft Corporation                                   */
216 /*                                                                        */
217 /*  DESCRIPTION                                                           */
218 /*                                                                        */
219 /*    This function sends a TCP packet through the specified socket.      */
220 /*                                                                        */
221 /*  INPUT                                                                 */
222 /*                                                                        */
223 /*    socket_ptr                            Pointer to socket             */
224 /*    packet_ptr                            Pointer to packet to send     */
225 /*    wait_option                           Suspension option             */
226 /*                                                                        */
227 /*  OUTPUT                                                                */
228 /*                                                                        */
229 /*    status                                Completion status             */
230 /*                                                                        */
231 /*  CALLS                                                                 */
232 /*                                                                        */
233 /*    _nx_ip_packet_send                    Packet send function          */
234 /*    _nx_ipv6_packet_send                  Packet send function          */
235 /*    _nx_ip_checksum_compute               Calculate TCP checksum        */
236 /*    _nx_tcp_socket_thread_suspend         Suspend calling thread        */
237 /*    tx_mutex_get                          Get protection mutex          */
238 /*    tx_mutex_put                          Put protection mutex          */
239 /*    _nx_tcp_socket_driver_send            TCP/IP offload send function  */
240 /*                                                                        */
241 /*  CALLED BY                                                             */
242 /*                                                                        */
243 /*    _nx_tcp_socket_send                                                 */
244 /*                                                                        */
245 /*  NOTE:                                                                 */
246 /*                                                                        */
247 /*    This is an internal function, only being called by                  */
248 /*    _nx_tcp_socket_send().  The caller guarantees that the payload      */
249 /*    size does not exceed MSS.                                           */
250 /*                                                                        */
251 /*  RELEASE HISTORY                                                       */
252 /*                                                                        */
253 /*    DATE              NAME                      DESCRIPTION             */
254 /*                                                                        */
255 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
256 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
257 /*                                            resulting in version 6.1    */
258 /*  08-02-2021     Yuxin Zhou               Modified comment(s), and      */
259 /*                                            supported TCP/IP offload,   */
260 /*                                            resulting in version 6.1.8  */
261 /*  10-15-2021     Yuxin Zhou               Modified comment(s), and      */
262 /*                                            fixed the bug of race       */
263 /*                                            condition,                  */
264 /*                                            resulting in version 6.1.9  */
265 /*  01-31-2022     Yuxin Zhou               Modified comment(s), and      */
266 /*                                            improved the throughput of  */
267 /*                                            TCP transmission,           */
268 /*                                            resulting in version 6.1.10 */
269 /*                                                                        */
270 /**************************************************************************/
_nx_tcp_socket_send_internal(NX_TCP_SOCKET * socket_ptr,NX_PACKET * packet_ptr,ULONG wait_option)271 UINT  _nx_tcp_socket_send_internal(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr, ULONG wait_option)
272 {
273 
274 TX_INTERRUPT_SAVE_AREA
275 
276 NX_IP          *ip_ptr;
277 NX_PACKET_POOL *pool_ptr;
278 NX_TCP_HEADER  *header_ptr;
279 ULONG           checksum = 0;
280 ULONG           sequence_number;
281 ULONG           tx_window_current;
282 ULONG           remaining_bytes;
283 ULONG          *source_ip = NX_NULL, *dest_ip = NX_NULL;
284 ULONG           send_mss;
285 NX_PACKET      *send_packet = packet_ptr;
286 NX_PACKET      *current_packet;
287 UCHAR          *current_ptr;
288 ULONG           data_offset = 0;
289 ULONG           source_data_size;
290 ULONG           copy_size;
291 UINT            data_left;
292 UINT            ret;
293 UCHAR           preempted = NX_FALSE;
294 UCHAR           adjust_packet;
295 UINT            old_threshold = 0;
296 ULONG           window_size;
297 #ifdef NX_ENABLE_TCPIP_OFFLOAD
298 UINT            status;
299 NX_INTERFACE   *interface_ptr;
300 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
301 #if defined(NX_DISABLE_TCP_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE)
302 UINT            compute_checksum = 1;
303 #endif /* defined(NX_DISABLE_TCP_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */
304 
305 #ifdef NX_DISABLE_TCP_TX_CHECKSUM
306     compute_checksum = 0;
307 #endif /* NX_DISABLE_TCP_TX_CHECKSUM */
308 
309     /* Check packet length. */
310     if (packet_ptr -> nx_packet_length == 0)
311     {
312 
313         /* Empty packet is not allowed. */
314         return(NX_INVALID_PACKET);
315     }
316 
317     /* Lockout interrupts.  */
318     TX_DISABLE
319 
320     /* Determine if the socket is currently bound.  */
321     if (!socket_ptr ->  nx_tcp_socket_bound_next)
322     {
323 
324         /* Restore interrupts.  */
325         TX_RESTORE
326 
327         /* Socket is not bound, return an error message.  */
328         return(NX_NOT_BOUND);
329     }
330 
331     /* Pickup the important information from the socket.  */
332 
333     /* Setup the pointer to the associated IP instance.  */
334     ip_ptr =  socket_ptr -> nx_tcp_socket_ip_ptr;
335 
336     /* Restore interrupts.  */
337     TX_RESTORE
338 
339     /* Check if the connection is in progress. */
340     if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_SENT) || (socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_RECEIVED))
341     {
342 
343         /* Yes it it. Wait for establish state. */
344         _nx_tcp_socket_state_wait(socket_ptr, NX_TCP_ESTABLISHED, wait_option);
345     }
346 
347     /* Obtain the IP mutex.  */
348     tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
349 
350     /* Check for the socket being in an established state.  */
351     if ((socket_ptr -> nx_tcp_socket_state != NX_TCP_ESTABLISHED) && (socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSE_WAIT))
352     {
353 
354         /* Release the protection.  */
355         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
356 
357         /* Socket is not connected, return an error message.  */
358         return(NX_NOT_CONNECTED);
359     }
360 
361     /* Add debug information. */
362     NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
363 
364 #ifndef NX_DISABLE_IPV4
365     if (socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V4)
366     {
367 
368         /* Set the source address. */
369         source_ip = &socket_ptr -> nx_tcp_socket_connect_interface -> nx_interface_ip_address;
370 
371         /* Set the destination address. */
372         dest_ip = &socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_address.v4;
373 
374         /* The outgoing interface should have been stored in the socket structure. */
375         packet_ptr -> nx_packet_address.nx_packet_interface_ptr = socket_ptr -> nx_tcp_socket_connect_interface;
376 
377         /* Calculate the data offset required by fragmented TCP packet. */
378         data_offset = NX_PHYSICAL_HEADER + sizeof(NX_IPV4_HEADER) + sizeof(NX_TCP_HEADER);
379     }
380 #endif /* !NX_DISABLE_IPV4  */
381 
382 #ifdef FEATURE_NX_IPV6
383     if (socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6)
384     {
385 
386         /* Determine whether or not the IPv6 address is valid. */
387         if (socket_ptr -> nx_tcp_socket_ipv6_addr -> nxd_ipv6_address_state != NX_IPV6_ADDR_STATE_VALID)
388         {
389 
390             /* Release the protection.  */
391             tx_mutex_put(&(ip_ptr -> nx_ip_protection));
392 
393             /* Add debug information. */
394             NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
395 
396             return(NX_NO_INTERFACE_ADDRESS);
397         }
398         /* Set the source address. */
399         source_ip = socket_ptr -> nx_tcp_socket_ipv6_addr -> nxd_ipv6_address;
400 
401         /* Set the destination address. */
402         dest_ip = socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_address.v6;
403 
404         /* The outgoing address should have been stored in the socket structure. */
405         packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr = socket_ptr -> nx_tcp_socket_ipv6_addr;
406 
407         /* Calculate the data offset required by fragmented TCP packet. */
408         data_offset = NX_PHYSICAL_HEADER + sizeof(NX_IPV6_HEADER) + sizeof(NX_TCP_HEADER);
409     }
410 #endif /* FEATURE_NX_IPV6 */
411 
412 #ifdef NX_ENABLE_TCPIP_OFFLOAD
413     interface_ptr = socket_ptr -> nx_tcp_socket_connect_interface;
414     if ((interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCPIP_OFFLOAD) &&
415         (interface_ptr -> nx_interface_tcpip_offload_handler))
416     {
417 
418         /* This interface supports TCP/IP offload.  */
419         status = _nx_tcp_socket_driver_send(socket_ptr, packet_ptr, wait_option);
420 
421         /* Release the IP protection.  */
422         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
423 
424         return(status);
425     }
426 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
427 
428 #ifdef NX_IPSEC_ENABLE
429     /* Increase the data offset when IPsec is enabled. */
430     data_offset += socket_ptr -> nx_tcp_socket_egress_sa_data_offset;
431 #endif /* NX_IPSEC_ENABLE */
432 
433     /* If trace is enabled, insert this event into the trace buffer.  */
434     NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_SEND, socket_ptr, packet_ptr, packet_ptr -> nx_packet_length, socket_ptr -> nx_tcp_socket_tx_sequence, NX_TRACE_TCP_EVENTS, 0, 0);
435 
436     /* Get the max mss this socket could send  */
437     send_mss = socket_ptr -> nx_tcp_socket_connect_mss;
438 
439     /* Get original pool. */
440     pool_ptr = packet_ptr -> nx_packet_pool_owner;
441 
442     /* Loop to send the packet. */
443     for (;;)
444     {
445 
446         /* Pick up the min(cwnd, swnd) */
447         if (socket_ptr -> nx_tcp_socket_tx_window_advertised > socket_ptr -> nx_tcp_socket_tx_window_congestion)
448         {
449             tx_window_current = socket_ptr -> nx_tcp_socket_tx_window_congestion;
450 
451             /* On the first and second duplicate ACKs received, the total FlightSize would
452                remain less than or equal to cwnd plus 2*SMSS.
453                Section 3.2, Page 9, RFC5681. */
454             if ((socket_ptr -> nx_tcp_socket_duplicated_ack_received == 1) ||
455                 (socket_ptr -> nx_tcp_socket_duplicated_ack_received == 2))
456             {
457                 tx_window_current += (socket_ptr -> nx_tcp_socket_connect_mss << 1);
458 
459                 /* Make sure the tx_window_current is less or equal to swnd. */
460                 if (tx_window_current > socket_ptr -> nx_tcp_socket_tx_window_advertised)
461                 {
462                     tx_window_current = socket_ptr -> nx_tcp_socket_tx_window_advertised;
463                 }
464             }
465         }
466         else
467         {
468             tx_window_current = socket_ptr -> nx_tcp_socket_tx_window_advertised;
469         }
470 
471         /* Substract any data transmitted but unacked (outstanding bytes) */
472         if (tx_window_current > socket_ptr -> nx_tcp_socket_tx_outstanding_bytes)
473         {
474             tx_window_current -= socket_ptr -> nx_tcp_socket_tx_outstanding_bytes;
475         }
476         else    /* Set tx_window_current to zero. */
477         {
478             tx_window_current = 0;
479         }
480 
481         /* Pick up the min(tx_window, send_mss). */
482         if (tx_window_current > send_mss)
483         {
484             tx_window_current = send_mss;
485         }
486 
487 
488         /* Store the data that is left. */
489         data_left = packet_ptr -> nx_packet_length;
490 
491         /* Check whether data can be sent. */
492         if ((tx_window_current != 0) && (socket_ptr -> nx_tcp_socket_transmit_sent_count < socket_ptr -> nx_tcp_socket_transmit_queue_maximum))
493         {
494 
495             /* Whether to adjust the packet? */
496             if (packet_ptr -> nx_packet_length > tx_window_current)
497             {
498 
499                 /* Packet need to be fragmented. */
500                 adjust_packet = NX_TRUE;
501             }
502             /*lint -e(923) suppress cast of pointer to ULONG.  */
503             else if (((ALIGN_TYPE)packet_ptr -> nx_packet_prepend_ptr) & 3)
504             {
505 
506                 /* Starting address of TCP header need to be four bytes aligned. */
507                 adjust_packet = NX_TRUE;
508             }
509 #ifndef NX_DISABLE_PACKET_CHAIN
510             else if ((packet_ptr -> nx_packet_next != NX_NULL) &&
511                      ((packet_ptr -> nx_packet_length + data_offset) < pool_ptr -> nx_packet_pool_payload_size) &&
512                      (pool_ptr -> nx_packet_pool_available > 0))
513             {
514 
515                 /* All data can be sent in one packet but they are in chained packets. */
516                 adjust_packet = NX_TRUE;
517             }
518             else if (packet_ptr -> nx_packet_prepend_ptr == packet_ptr -> nx_packet_append_ptr)
519             {
520 
521                 /* Loop to find the first byte of data. */
522                 current_packet = packet_ptr -> nx_packet_next;
523 
524                 while ((current_packet != NX_NULL) && (current_packet -> nx_packet_prepend_ptr == current_packet -> nx_packet_append_ptr))
525                 {
526 
527                     /* Move to next packet. */
528                     current_packet = current_packet -> nx_packet_next;
529                 }
530 
531                 /* packet length is not 0. Therefore the packet chain is expected to contain data. */
532                 NX_ASSERT(current_packet != NX_NULL);
533 
534                 /*lint -e{923} suppress cast of pointer to ULONG.  */
535                 if (((ALIGN_TYPE)current_packet -> nx_packet_prepend_ptr) & 3)
536                 {
537 
538                     /* Starting address of TCP data need to be four bytes aligned. */
539                     adjust_packet = NX_TRUE;
540                 }
541                 else
542                 {
543 
544                     /* Packet can be sent directly. */
545                     adjust_packet = NX_FALSE;
546                 }
547             }
548 #endif /* NX_DISABLE_PACKET_CHAIN */
549             else
550             {
551 
552                 /* Packet can be sent directly. */
553                 adjust_packet = NX_FALSE;
554             }
555 
556             /* Adjust the packet? */
557             if (adjust_packet)
558             {
559 
560                 /* Yes. Obtain the size of the packet can be sent. */
561                 if (packet_ptr -> nx_packet_length > tx_window_current)
562                 {
563                     remaining_bytes = tx_window_current;
564                 }
565                 else
566                 {
567                     remaining_bytes = packet_ptr -> nx_packet_length;
568                 }
569 
570                 /* Points to the source packet. */
571                 current_packet = packet_ptr;
572 
573                 /* Mark the beginning of data. */
574                 current_ptr = packet_ptr -> nx_packet_prepend_ptr;
575 
576                 /* Release the protection.  */
577                 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
578 
579                 /* Obtain a new segmentation. */
580                 ret = _nx_packet_allocate(pool_ptr, &send_packet,
581                                           data_offset, wait_option);
582 
583                 if (ret != NX_SUCCESS)
584                 {
585 
586                     /* Restore preemption? */
587                     if (preempted == NX_TRUE)
588                     {
589 
590                         /*lint -e{644} -e{530} suppress variable might not be initialized, since "old_threshold" was initialized when preempted was set to NX_TRUE. */
591                         tx_thread_preemption_change(_tx_thread_current_ptr, old_threshold, &old_threshold);
592                     }
593 
594                     /* Packet allocate failure. Return.*/
595                     return(ret);
596                 }
597 
598                 /* Regain exclusive access to IP instance. */
599                 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
600 
601                 /* Add debug information. */
602                 NX_PACKET_DEBUG(__FILE__, __LINE__, send_packet);
603 
604                 /* Loop through the entire source packet. */
605                 while (remaining_bytes)
606                 {
607 
608                     /* Figure out whether or not the source packet still contains data. */
609                     /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
610                     source_data_size = (ULONG)(current_packet -> nx_packet_append_ptr - current_ptr);
611                     while (source_data_size == 0)
612                     {
613 
614 #ifndef NX_DISABLE_PACKET_CHAIN
615                         /* The current buffer is exhausted.  Move to the next buffer on the source packet chain. */
616                         current_packet = current_packet -> nx_packet_next;
617 
618                         if (current_packet == NX_NULL)
619                         {
620 #endif /* NX_DISABLE_PACKET_CHAIN */
621 
622                             /* Restore preemption? */
623                             if (preempted == NX_TRUE)
624                             {
625                                 tx_thread_preemption_change(_tx_thread_current_ptr, old_threshold, &old_threshold);
626                             }
627 
628                             /* No more data in the source packet. However there are still bytes remaining even though
629                                the packet is not done yet. This is an unrecoverable error. */
630                             /*lint -e{644} suppress variable might not be initialized, since "send_packet" was initialized in _nx_packet_allocate. */
631                             _nx_packet_release(send_packet);
632 
633                             /* Release the protection.  */
634                             tx_mutex_put(&(ip_ptr -> nx_ip_protection));
635 
636                             /* Add debug information. */
637                             NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
638 
639                             return(NX_INVALID_PACKET);
640 #ifndef NX_DISABLE_PACKET_CHAIN
641                         }
642 
643                         /* Mark the beginning of data in the next packet. */
644                         current_ptr = current_packet -> nx_packet_prepend_ptr;
645 
646                         /* Compute the amount of data present in this source buffer. */
647                         /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
648                         source_data_size = (ULONG)(current_packet -> nx_packet_append_ptr - current_ptr);
649 #endif /* NX_DISABLE_PACKET_CHAIN */
650                     }
651 
652 
653                     /* copy_size = min(send_packet, source) */
654                     if (remaining_bytes > source_data_size)
655                     {
656                         copy_size = source_data_size;
657                     }
658                     else
659                     {
660                         copy_size = remaining_bytes;
661                     }
662 
663                     /* Release the mutex before a blocking call. */
664                     tx_mutex_put(&(ip_ptr -> nx_ip_protection));
665 
666                     /* Append data. */
667                     ret = _nx_packet_data_append(send_packet, current_ptr, copy_size,
668                                                  pool_ptr, wait_option);
669 
670                     /* Regain exclusive access to IP instance. */
671                     tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
672 
673                     /* Check for errors with data append. */
674                     if (ret != NX_SUCCESS)
675                     {
676 
677                         /* Append failed. */
678                         if (send_packet -> nx_packet_length == 0)
679                         {
680 
681                             /* The packet is empty, return. */
682                             /* Restore preemption? */
683                             if (preempted == NX_TRUE)
684                             {
685 
686                                 /*lint -e{644} -e{530} suppress variable might not be initialized, since "old_threshold" was initialized when preempted was set to NX_TRUE. */
687                                 tx_thread_preemption_change(_tx_thread_current_ptr, old_threshold, &old_threshold);
688                             }
689 
690                             /* Release the protection.  */
691                             tx_mutex_put(&(ip_ptr -> nx_ip_protection));
692 
693                             /* Release the packet. */
694                             _nx_packet_release(send_packet);
695 
696                             /* Packet allocate failure. Return.*/
697                             return(ret);
698                         }
699 
700                         /* Partial data can be sent. Just break. */
701                         break;
702                     }
703 
704                     /* Reduce the remaining_bytes counter by the amount being copied over. */
705                     remaining_bytes -= copy_size;
706 
707                     /* Advance the prepend ptr on the source buffer, by the amount being copied. */
708                     current_ptr += copy_size;
709                 }
710 
711                 send_packet -> nx_packet_address = packet_ptr -> nx_packet_address;
712             }
713             else
714             {
715 
716                 /* Send the packet directly. */
717                 send_packet = packet_ptr;
718             }
719 
720             /* Now the send_packet can be sent. */
721             /* Set IP version. */
722             send_packet -> nx_packet_ip_version = (UCHAR)(socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version);
723 
724 #ifdef NX_IPSEC_ENABLE
725             send_packet -> nx_packet_ipsec_sa_ptr = socket_ptr -> nx_tcp_socket_egress_sa;
726 #endif /* NX_IPSEC_ENABLE */
727 
728             /* Prepend the TCP header to the packet.  First, make room for the TCP header.  */
729             send_packet -> nx_packet_prepend_ptr =  send_packet -> nx_packet_prepend_ptr - sizeof(NX_TCP_HEADER);
730 
731             /* Add the length of the TCP header.  */
732             send_packet -> nx_packet_length =  send_packet -> nx_packet_length + (ULONG)sizeof(NX_TCP_HEADER);
733 
734             /* Pickup the pointer to the head of the TCP packet.  */
735             /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
736             header_ptr =  (NX_TCP_HEADER *)send_packet -> nx_packet_prepend_ptr;
737 
738             /* Build the output request in the TCP header.  */
739             header_ptr -> nx_tcp_header_word_0 =        (((ULONG)(socket_ptr -> nx_tcp_socket_port)) << NX_SHIFT_BY_16) | (ULONG)socket_ptr -> nx_tcp_socket_connect_port;
740             header_ptr -> nx_tcp_acknowledgment_number = socket_ptr -> nx_tcp_socket_rx_sequence;
741 
742             /* Set window size. */
743 #ifdef NX_ENABLE_TCP_WINDOW_SCALING
744             window_size = socket_ptr -> nx_tcp_socket_rx_window_current >> socket_ptr -> nx_tcp_rcv_win_scale_value;
745 
746             /* Make sure the window_size is less than 0xFFFF. */
747             if (window_size > 0xFFFF)
748             {
749                 window_size = 0xFFFF;
750             }
751 #else
752             window_size = socket_ptr -> nx_tcp_socket_rx_window_current;
753 #endif /* NX_ENABLE_TCP_WINDOW_SCALING */
754 
755             header_ptr -> nx_tcp_header_word_3 =        NX_TCP_HEADER_SIZE | NX_TCP_ACK_BIT | NX_TCP_PSH_BIT | window_size;
756             header_ptr -> nx_tcp_header_word_4 =        0;
757 
758             /* Remember the last ACKed sequence and the last reported window size.  */
759             socket_ptr -> nx_tcp_socket_rx_sequence_acked =    socket_ptr -> nx_tcp_socket_rx_sequence;
760             socket_ptr -> nx_tcp_socket_rx_window_last_sent =  socket_ptr -> nx_tcp_socket_rx_window_current;
761 
762             /* Setup a new delayed ACK timeout.  */
763             socket_ptr -> nx_tcp_socket_delayed_ack_timeout =  _nx_tcp_ack_timer_rate;
764 
765             /* Endian swapping logic.  If NX_LITTLE_ENDIAN is specified, these macros will
766                swap the endian of the TCP header.  */
767             NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_0);
768             NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_acknowledgment_number);
769             NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_3);
770             NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_4);
771 
772             /* Release the protection.  */
773             tx_mutex_put(&(ip_ptr -> nx_ip_protection));
774 
775             /* Pickup the current transmit sequence number.  */
776             header_ptr -> nx_tcp_sequence_number =  socket_ptr -> nx_tcp_socket_tx_sequence;
777             sequence_number =  header_ptr -> nx_tcp_sequence_number;
778 
779             /* Swap the headers for endianness. */
780             NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_sequence_number);
781 
782 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
783             if (socket_ptr -> nx_tcp_socket_connect_interface -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM)
784             {
785                 compute_checksum = 0;
786             }
787 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
788 
789 #ifdef NX_IPSEC_ENABLE
790             if ((send_packet -> nx_packet_ipsec_sa_ptr != NX_NULL) && (((NX_IPSEC_SA *)(send_packet -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_sa_encryption_method != NX_CRYPTO_NONE))
791             {
792                 compute_checksum = 1;
793             }
794 #endif /* NX_IPSEC_ENABLE */
795 
796 #if defined(NX_DISABLE_TCP_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE)
797             if (compute_checksum)
798 #endif /* defined(NX_DISABLE_TCP_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */
799             {
800                 /* Calculate the TCP checksum without protection.  */
801                 checksum =  _nx_ip_checksum_compute(send_packet, NX_PROTOCOL_TCP,
802                                                     (UINT)send_packet -> nx_packet_length,
803                                                     source_ip, dest_ip);
804                 checksum = ~checksum & NX_LOWER_16_MASK;
805             }
806 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
807             else
808             {
809                 send_packet -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_TCP_TX_CHECKSUM;
810             }
811 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
812 
813             /* Place protection while we check the sequence number for the new TCP packet.  */
814             tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
815 
816             /* Determine if the sequence number is the same.  */
817             if (sequence_number != socket_ptr -> nx_tcp_socket_tx_sequence)
818             {
819 
820                 /* Another transmit on this socket took place and changed the sequence.  We need to
821                    recalculate the checksum with a new sequence number.  Release protection and
822                    just resume the loop.  */
823                 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
824 
825                 /* Release the packet when the sequence is changed. */
826                 if (send_packet != packet_ptr)
827                 {
828                     _nx_packet_release(send_packet);
829                 }
830 
831                 /* Regain exclusive access to IP instance. */
832                 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
833                 continue;
834             }
835 
836             /* Check for the socket being in an established state.  It's possible the connection could have gone
837                away during the TCP checksum calculation above.  */
838             if ((socket_ptr -> nx_tcp_socket_state != NX_TCP_ESTABLISHED) && (socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSE_WAIT))
839             {
840 
841                 /* Restore preemption? */
842                 if (preempted == NX_TRUE)
843                 {
844                     tx_thread_preemption_change(_tx_thread_current_ptr, old_threshold, &old_threshold);
845                 }
846 
847                 /* Release protection.  */
848                 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
849 
850                 /* Release the packet when the sequence is changed. */
851                 if (send_packet != packet_ptr)
852                 {
853                     _nx_packet_release(send_packet);
854                 }
855 
856                 /* Add debug information. */
857                 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
858 
859                 /* Socket is not connected, return an error message.  */
860                 return(NX_NOT_CONNECTED);
861             }
862 
863             /* Disable interrupts.  */
864             TX_DISABLE
865 
866             /* Adjust the transmit sequence number to reflect the output data.  */
867             socket_ptr -> nx_tcp_socket_tx_sequence = socket_ptr -> nx_tcp_socket_tx_sequence +
868                 (send_packet -> nx_packet_length - (ULONG)sizeof(NX_TCP_HEADER));
869 
870             /* Restore interrupts.  */
871             TX_RESTORE
872 
873             /* Reset zero window probe flag. */
874             socket_ptr -> nx_tcp_socket_zero_window_probe_has_data = NX_FALSE;
875 
876             /* Move the checksum into header.  */
877             NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_4);
878             header_ptr -> nx_tcp_header_word_4 =  (checksum << NX_SHIFT_BY_16);
879             NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_4);
880 
881             /* Place the packet on the sent list.  */
882             data_left -= (send_packet -> nx_packet_length - (ULONG)sizeof(NX_TCP_HEADER));
883             if (socket_ptr -> nx_tcp_socket_transmit_sent_head)
884             {
885 
886                 /* Yes, other packets are on the list already.  Just add this one to the tail.  */
887                 (socket_ptr -> nx_tcp_socket_transmit_sent_tail) -> nx_packet_union_next.nx_packet_tcp_queue_next =  send_packet;
888                 socket_ptr -> nx_tcp_socket_transmit_sent_tail =  send_packet;
889             }
890             else
891             {
892 
893                 /* Empty list, just setup the head and tail to the current packet.  */
894                 socket_ptr -> nx_tcp_socket_transmit_sent_head =  send_packet;
895                 socket_ptr -> nx_tcp_socket_transmit_sent_tail =  send_packet;
896 
897                 /* Setup a timeout for the packet at the head of the list.  */
898                 socket_ptr -> nx_tcp_socket_timeout =          socket_ptr -> nx_tcp_socket_timeout_rate;
899                 socket_ptr -> nx_tcp_socket_timeout_retries =  0;
900                 socket_ptr -> nx_tcp_socket_tx_outstanding_bytes = 0;
901             }
902 
903             /* Set the next pointer to NX_PACKET_ENQUEUED to indicate the packet is part of a TCP queue.  */
904             /*lint -e{923} suppress cast of ULONG to pointer.  */
905             send_packet -> nx_packet_union_next.nx_packet_tcp_queue_next =  (NX_PACKET *)NX_PACKET_ENQUEUED;
906 
907             /* Increment the packet sent count.  */
908             socket_ptr -> nx_tcp_socket_transmit_sent_count++;
909 
910             /* Increase the transmit outstanding byte count. */
911             socket_ptr -> nx_tcp_socket_tx_outstanding_bytes +=
912                 (send_packet -> nx_packet_length - (ULONG)sizeof(NX_TCP_HEADER));
913 #ifndef NX_DISABLE_TCP_INFO
914             /* Increment the TCP packet sent count and bytes sent count.  */
915             ip_ptr -> nx_ip_tcp_packets_sent++;
916             ip_ptr -> nx_ip_tcp_bytes_sent += send_packet -> nx_packet_length - (ULONG)sizeof(NX_TCP_HEADER);
917 
918             /* Increment the TCP packet sent count and bytes sent count for the socket.  */
919             socket_ptr -> nx_tcp_socket_packets_sent++;
920             socket_ptr -> nx_tcp_socket_bytes_sent += send_packet -> nx_packet_length - (ULONG)sizeof(NX_TCP_HEADER);
921 #endif /* NX_DISABLE_TCP_INFO */
922 
923 #ifdef NX_ENABLE_VLAN
924             if (socket_ptr -> nx_tcp_socket_vlan_priority != NX_VLAN_PRIORITY_INVALID)
925             {
926                 send_packet -> nx_packet_vlan_priority = socket_ptr -> nx_tcp_socket_vlan_priority;
927             }
928 #endif /* NX_ENABLE_VLAN */
929 
930             /* If trace is enabled, insert this event into the trace buffer.  */
931             NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_DATA_SEND, ip_ptr, socket_ptr, send_packet, socket_ptr -> nx_tcp_socket_tx_sequence - (send_packet -> nx_packet_length - sizeof(NX_TCP_HEADER)), NX_TRACE_INTERNAL_EVENTS, 0, 0);
932 
933             /* Send the TCP packet to the IP component.  */
934 #ifndef NX_DISABLE_IPV4
935             if (socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V4)
936             {
937 
938 
939                 _nx_ip_packet_send(ip_ptr, send_packet,
940                                    socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_address.v4,
941                                    socket_ptr -> nx_tcp_socket_type_of_service,
942                                    socket_ptr -> nx_tcp_socket_time_to_live,
943                                    NX_IP_TCP,
944                                    socket_ptr -> nx_tcp_socket_fragment_enable,
945                                    socket_ptr -> nx_tcp_socket_next_hop_address);
946             }
947 #endif /* !NX_DISABLE_IPV4  */
948 
949 #ifdef FEATURE_NX_IPV6
950             if (socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_version == NX_IP_VERSION_V6)
951             {
952 
953                 /* Ready to send the packet! */
954                 _nx_ipv6_packet_send(ip_ptr,
955                                      send_packet,
956                                      NX_PROTOCOL_TCP,
957                                      send_packet -> nx_packet_length,
958                                      ip_ptr -> nx_ipv6_hop_limit,
959                                      socket_ptr -> nx_tcp_socket_ipv6_addr -> nxd_ipv6_address,
960                                      socket_ptr -> nx_tcp_socket_connect_ip.nxd_ip_address.v6);
961             }
962 #endif /* FEATURE_NX_IPV6 */
963 
964             if (data_left == 0)
965             {
966 
967                 /* Release the packet. */
968                 if (send_packet != packet_ptr)
969                 {
970                     _nx_packet_release(packet_ptr);
971                 }
972 
973                 /* Restore preemption? */
974                 if (preempted == NX_TRUE)
975                 {
976                     tx_thread_preemption_change(_tx_thread_current_ptr, old_threshold, &old_threshold);
977                 }
978 
979                 /* Release the protection.  */
980                 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
981 
982                 /* Add debug information. */
983                 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
984 
985                 /* Return successful status.  */
986                 return(NX_SUCCESS);
987             }
988             else
989             {
990 
991                 /* Adjust the orginal packet. */
992                 current_packet = packet_ptr;
993 
994                 remaining_bytes = packet_ptr -> nx_packet_length - data_left;
995 #ifndef NX_DISABLE_PACKET_CHAIN
996                 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
997                 while (remaining_bytes >
998                        (UINT)(current_packet -> nx_packet_append_ptr - current_packet -> nx_packet_prepend_ptr))
999                 {
1000 
1001                     /* Trim all data in the train. */
1002                     /*lint -e{923} suppress cast of pointer to ULONG.  */
1003                     packet_ptr -> nx_packet_length -= (ULONG)((ALIGN_TYPE)current_packet -> nx_packet_append_ptr - (ALIGN_TYPE)current_packet -> nx_packet_prepend_ptr);
1004 
1005                     /*lint -e{923} suppress cast of pointer to ULONG.  */
1006                     remaining_bytes -= (ULONG)((ALIGN_TYPE)current_packet -> nx_packet_append_ptr - (ALIGN_TYPE)current_packet -> nx_packet_prepend_ptr);
1007 
1008                     /*lint -e{923} suppress cast between ULONG and pointer.  */
1009                     current_packet -> nx_packet_append_ptr = (UCHAR *)(((ALIGN_TYPE)current_packet -> nx_packet_append_ptr) & (ALIGN_TYPE)(~3));
1010                     current_packet -> nx_packet_prepend_ptr = current_packet -> nx_packet_append_ptr;
1011 
1012                     /* Pointer to next packet. */
1013                     current_packet = current_packet -> nx_packet_next;
1014                 }
1015 #endif /* NX_DISABLE_PACKET_CHAIN */
1016 
1017                 /* Trim partial data in the packet. */
1018                 packet_ptr -> nx_packet_length -= remaining_bytes;
1019                 current_packet -> nx_packet_prepend_ptr += remaining_bytes;
1020 
1021                 /* Release the protection.  */
1022                 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
1023 
1024                 /* Regain exclusive access to IP instance. */
1025                 tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
1026             }
1027         }
1028         else if ((wait_option) && (_tx_thread_current_ptr != &(ip_ptr -> nx_ip_thread)))
1029         {
1030 
1031             /* Suspend the thread on this socket's transmit queue.  */
1032 
1033             /* Save the return packet pointer address as well.  */
1034             _tx_thread_current_ptr -> tx_thread_additional_suspend_info =  (VOID *)packet_ptr;
1035 
1036             /* Add debug information. */
1037             NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
1038 
1039             /* Increment the suspended thread count.  */
1040             socket_ptr -> nx_tcp_socket_transmit_suspended_count++;
1041 
1042             if (socket_ptr -> nx_tcp_socket_zero_window_probe_has_data == NX_FALSE)
1043             {
1044 
1045                 /* Set data for zero window probe. */
1046                 socket_ptr -> nx_tcp_socket_zero_window_probe_has_data = NX_TRUE;
1047                 socket_ptr -> nx_tcp_socket_zero_window_probe_data = *(packet_ptr -> nx_packet_prepend_ptr);
1048                 socket_ptr -> nx_tcp_socket_zero_window_probe_sequence = socket_ptr -> nx_tcp_socket_tx_sequence;
1049                 socket_ptr -> nx_tcp_socket_zero_window_probe_failure = 0;
1050             }
1051 
1052             /* Need preemption? */
1053             if (preempted == NX_FALSE)
1054             {
1055             UINT ip_thread_priority;
1056 
1057                 /* Yes. It will be able to send packet out immediately TCP window is non zero. */
1058                 tx_thread_info_get(&ip_ptr -> nx_ip_thread, NX_NULL, NX_NULL, NX_NULL, &ip_thread_priority, NX_NULL,
1059                                    NX_NULL, NX_NULL, NX_NULL);
1060 
1061                 /*lint -e{644} suppress variable might not be initialized, since "ip_thread_priority" was initialized before TCP is enabled. */
1062                 tx_thread_preemption_change(_tx_thread_current_ptr, ip_thread_priority, &old_threshold);
1063                 preempted = NX_TRUE;
1064             }
1065 
1066             /* Suspend the thread on the transmit suspension list.  */
1067             _nx_tcp_socket_thread_suspend(&(socket_ptr -> nx_tcp_socket_transmit_suspension_list), _nx_tcp_transmit_cleanup, socket_ptr, &(ip_ptr -> nx_ip_protection), wait_option);
1068 
1069             /* Determine if the send request was successful.  */
1070             if (_tx_thread_current_ptr -> tx_thread_suspend_status)
1071             {
1072 
1073                 /* Restore preemption. */
1074                 tx_thread_preemption_change(_tx_thread_current_ptr, old_threshold, &old_threshold);
1075 
1076                 /* Add debug information. */
1077                 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
1078 
1079                 /* Just return the error code.  */
1080                 return(_tx_thread_current_ptr -> tx_thread_suspend_status);
1081             }
1082         }
1083         else
1084         {
1085 
1086             /* Check advertised window. */
1087             if (socket_ptr -> nx_tcp_socket_zero_window_probe_has_data == NX_FALSE)
1088             {
1089 
1090                 /* Set data for zero window probe. */
1091                 socket_ptr -> nx_tcp_socket_zero_window_probe_has_data = NX_TRUE;
1092                 socket_ptr -> nx_tcp_socket_zero_window_probe_data = *(packet_ptr -> nx_packet_prepend_ptr);
1093                 socket_ptr -> nx_tcp_socket_zero_window_probe_sequence = socket_ptr -> nx_tcp_socket_tx_sequence;
1094                 socket_ptr -> nx_tcp_socket_zero_window_probe_failure = 0;
1095             }
1096 
1097             /* Determine which transmit error is present.  */
1098             if (socket_ptr -> nx_tcp_socket_transmit_sent_count < socket_ptr -> nx_tcp_socket_transmit_queue_maximum)
1099             {
1100 
1101                 /* Release protection.  */
1102                 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
1103 
1104                 /* Add debug information. */
1105                 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
1106 
1107                 /* Not a queue depth problem, return a window overflow error.  */
1108                 return(NX_WINDOW_OVERFLOW);
1109             }
1110             else
1111             {
1112 
1113                 /* Release protection.  */
1114                 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
1115 
1116                 /* Add debug information. */
1117                 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
1118 
1119                 /* Return a transmit queue exceeded error.  */
1120                 return(NX_TX_QUEUE_DEPTH);
1121             }
1122         }
1123     }
1124 }