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