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 
35 
36 /**************************************************************************/
37 /*                                                                        */
38 /*  FUNCTION                                               RELEASE        */
39 /*                                                                        */
40 /*    _nx_tcp_socket_state_transmit_check                 PORTABLE C      */
41 /*                                                           6.1          */
42 /*  AUTHOR                                                                */
43 /*                                                                        */
44 /*    Yuxin Zhou, Microsoft Corporation                                   */
45 /*                                                                        */
46 /*  DESCRIPTION                                                           */
47 /*                                                                        */
48 /*    This function determines if the new receive window value is large   */
49 /*    enough to satisfy a thread suspended trying to send data on the TCP */
50 /*    connection.  This is typically called from the ESTABLISHED state.   */
51 /*                                                                        */
52 /*  INPUT                                                                 */
53 /*                                                                        */
54 /*    socket_ptr                            Pointer to TCP socket         */
55 /*                                                                        */
56 /*  OUTPUT                                                                */
57 /*                                                                        */
58 /*    None                                                                */
59 /*                                                                        */
60 /*  CALLS                                                                 */
61 /*                                                                        */
62 /*    _nx_tcp_socket_thread_resume          Resume suspended thread       */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    _nx_tcp_socket_packet_process         Process TCP packet for socket */
67 /*                                                                        */
68 /*  RELEASE HISTORY                                                       */
69 /*                                                                        */
70 /*    DATE              NAME                      DESCRIPTION             */
71 /*                                                                        */
72 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
73 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
74 /*                                            resulting in version 6.1    */
75 /*                                                                        */
76 /**************************************************************************/
_nx_tcp_socket_state_transmit_check(NX_TCP_SOCKET * socket_ptr)77 VOID  _nx_tcp_socket_state_transmit_check(NX_TCP_SOCKET *socket_ptr)
78 {
79 
80 ULONG tx_window_current;
81 
82     /* Now check to see if there is a thread suspended attempting to transmit.  */
83     if (socket_ptr -> nx_tcp_socket_transmit_suspension_list)
84     {
85 
86         /* Yes, a thread is suspended attempting to transmit when the transmit window
87            is lower than its request size.  Determine if the current transmit window
88            size can now accommodate the request.  */
89 
90         /* Pick up the min(cwnd, swnd) */
91         if (socket_ptr -> nx_tcp_socket_tx_window_advertised > socket_ptr -> nx_tcp_socket_tx_window_congestion)
92         {
93             tx_window_current = socket_ptr -> nx_tcp_socket_tx_window_congestion;
94 
95             /* On the first and second duplicate ACKs received, the total FlightSize would
96                remain less than or equal to cwnd plus 2*SMSS.
97                Section 3.2, Page 9, RFC5681. */
98             if ((socket_ptr -> nx_tcp_socket_duplicated_ack_received == 1) ||
99                 (socket_ptr -> nx_tcp_socket_duplicated_ack_received == 2))
100             {
101                 tx_window_current += (socket_ptr -> nx_tcp_socket_connect_mss << 1);
102             }
103 
104             /* Make sure the tx_window_current is less or equal to swnd. */
105             if (tx_window_current > socket_ptr -> nx_tcp_socket_tx_window_advertised)
106             {
107                 tx_window_current = socket_ptr -> nx_tcp_socket_tx_window_advertised;
108             }
109         }
110         else
111         {
112             tx_window_current = socket_ptr -> nx_tcp_socket_tx_window_advertised;
113         }
114 
115         /* Substract any data transmitted but unacked (outstanding bytes) */
116         if (tx_window_current > socket_ptr -> nx_tcp_socket_tx_outstanding_bytes)
117         {
118             tx_window_current -= socket_ptr -> nx_tcp_socket_tx_outstanding_bytes;
119         }
120         else    /* Set tx_window_current to zero. */
121         {
122             tx_window_current = 0;
123         }
124 
125 
126         /* Determine if the current transmit window (received from the connected socket)
127            is large enough to handle the transmit.  */
128         if ((tx_window_current) &&
129             (socket_ptr -> nx_tcp_socket_transmit_sent_count < socket_ptr -> nx_tcp_socket_transmit_queue_maximum))
130         {
131 
132             /* Is NetX set up with a windows update callback? */
133             if (socket_ptr -> nx_tcp_socket_window_update_notify)
134             {
135 
136                 /* Yes; Call this function when there is a change in transmit windows size. */
137                 (socket_ptr -> nx_tcp_socket_window_update_notify)(socket_ptr);
138             }
139 
140 
141             /* Decrement the suspension count.  */
142             socket_ptr -> nx_tcp_socket_transmit_suspended_count--;
143 
144             /* Remove the suspended thread from the list.  */
145             _nx_tcp_socket_thread_resume(&(socket_ptr -> nx_tcp_socket_transmit_suspension_list), NX_SUCCESS);
146         }
147     }
148 }
149 
150