1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** NetX Component                                                        */
16 /**                                                                       */
17 /**   Transmission Control Protocol (TCP)                                 */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define NX_SOURCE_CODE
23 
24 
25 /* Include necessary system files.  */
26 
27 #include "nx_api.h"
28 #include "nx_tcp.h"
29 #include "nx_ipv6.h"
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _nx_tcp_client_socket_unbind                        PORTABLE C      */
37 /*                                                           6.1          */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Yuxin Zhou, Microsoft Corporation                                   */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function unbinds the TCP client socket structure from the      */
45 /*    previously bound TCP port.                                          */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    socket_ptr                            Pointer to TCP client socket  */
50 /*                                                                        */
51 /*  OUTPUT                                                                */
52 /*                                                                        */
53 /*    status                                Completion status             */
54 /*                                                                        */
55 /*  CALLS                                                                 */
56 /*                                                                        */
57 /*    _nx_tcp_client_bind_cleanup           Remove and cleanup bind req   */
58 /*    _nx_tcp_socket_thread_resume          Resume thread suspended on    */
59 /*                                            port                        */
60 /*    _nx_tcp_socket_block_cleanup          Cleanup the socket block      */
61 /*    tx_mutex_get                          Obtain protection mutex       */
62 /*    tx_mutex_put                          Release protection mutex      */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    Application Code                                                    */
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_client_socket_unbind(NX_TCP_SOCKET * socket_ptr)77 UINT  _nx_tcp_client_socket_unbind(NX_TCP_SOCKET *socket_ptr)
78 {
79 TX_INTERRUPT_SAVE_AREA
80 
81 UINT           index;
82 UINT           port;
83 NX_IP         *ip_ptr;
84 NX_TCP_SOCKET *new_socket_ptr;
85 
86 
87     /* Setup the pointer to the associated IP instance.  */
88     ip_ptr =  socket_ptr -> nx_tcp_socket_ip_ptr;
89 
90     /* If trace is enabled, insert this event into the trace buffer.  */
91     NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_CLIENT_SOCKET_UNBIND, ip_ptr, socket_ptr, 0, 0, NX_TRACE_TCP_EVENTS, 0, 0);
92 
93     /* Obtain the IP mutex so we can figure out whether or not the port has already
94        been bound to.  */
95     tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
96 
97     /* Determine if the socket is still in the timed wait state.  */
98     if (socket_ptr -> nx_tcp_socket_state == NX_TCP_TIMED_WAIT)
99     {
100 
101         /* Cleanup the transmission control block.  */
102         _nx_tcp_socket_block_cleanup(socket_ptr);
103     }
104 
105     /* Determine if the socket is still in the closed state.  */
106     if (socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSED)
107     {
108 
109         /* No, release the IP protection.  */
110         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
111 
112         /* Return an error code.  */
113         return(NX_NOT_CLOSED);
114     }
115 
116     /* Determine if the socket is bound to port.  */
117     if (!socket_ptr -> nx_tcp_socket_bound_next)
118     {
119 
120         /* Determine if there is a special condition for the socket not being in
121            a bound condition...  i.e. the socket is in a pending-to-be-bound condition
122            in a call from a different thread.  */
123         if (socket_ptr -> nx_tcp_socket_bind_in_progress)
124         {
125 
126             /* Execute the bind suspension cleanup routine.  */
127             _nx_tcp_client_bind_cleanup(socket_ptr -> nx_tcp_socket_bind_in_progress NX_CLEANUP_ARGUMENT);
128 
129             /* Release the protection mutex.  */
130             tx_mutex_put(&(ip_ptr -> nx_ip_protection));
131 
132             /* Return success.  */
133             return(NX_SUCCESS);
134         }
135         else
136         {
137 
138             /* Release the protection mutex.  */
139             tx_mutex_put(&(ip_ptr -> nx_ip_protection));
140 
141             /* Return a not bound error code.  */
142             return(NX_NOT_BOUND);
143         }
144     }
145 
146     /* Otherwise, the socket is bound.  We need to remove this socket from the
147        port and check for any other TCP socket bind requests that are queued.  */
148 
149     /* Pickup the port number in the TCP socket structure.  */
150     port =  socket_ptr -> nx_tcp_socket_port;
151 
152     /* Calculate the hash index in the TCP port array of the associated IP instance.  */
153     index =  (UINT)((port + (port >> 8)) & NX_TCP_PORT_TABLE_MASK);
154 
155     /* Disable interrupts while we unlink the current socket.  */
156     TX_DISABLE
157 
158     /* The socket is off the bound list...  we need to check for queued receive packets and
159        if found they need to be released.  */
160     if (socket_ptr -> nx_tcp_socket_receive_queue_count)
161     {
162 
163         /* Remove all packets on the socket's receive queue.  */
164         _nx_tcp_socket_receive_queue_flush(socket_ptr);
165     }
166 
167     /* Determine if this is the only socket bound on this port list.  */
168     if (socket_ptr -> nx_tcp_socket_bound_next == socket_ptr)
169     {
170 
171         /* Yes, this is the only socket on the port list.  */
172 
173         /* Clear the list head pointer and the next pointer in the socket.  */
174         ip_ptr -> nx_ip_tcp_port_table[index] =   NX_NULL;
175         socket_ptr -> nx_tcp_socket_bound_next =  NX_NULL;
176     }
177     else
178     {
179 
180         /* Relink the neighbors of this TCP socket.  */
181 
182         /* Update the links of the adjacent sockets.  */
183         (socket_ptr -> nx_tcp_socket_bound_next) -> nx_tcp_socket_bound_previous =
184             socket_ptr -> nx_tcp_socket_bound_previous;
185         (socket_ptr -> nx_tcp_socket_bound_previous) -> nx_tcp_socket_bound_next =
186             socket_ptr -> nx_tcp_socket_bound_next;
187 
188         /* Determine if the head of the port list points to the socket being removed.
189            If so, we need to move the head pointer.  */
190         if (ip_ptr -> nx_ip_tcp_port_table[index] == socket_ptr)
191         {
192 
193             /* Yes, we need to move the port list head pointer.  */
194             ip_ptr -> nx_ip_tcp_port_table[index] =  socket_ptr -> nx_tcp_socket_bound_next;
195         }
196 
197         /* Clear the next pointer in the socket to indicate it is no longer bound.  */
198         socket_ptr -> nx_tcp_socket_bound_next =  NX_NULL;
199     }
200 
201     /* Restore interrupts.  */
202     TX_RESTORE
203 
204     /* Determine if there are any threads suspended on trying to bind to the
205        same port.  */
206     if (socket_ptr -> nx_tcp_socket_bind_suspension_list)
207     {
208 
209         /* Pickup the new socket structure to link to the port list.  */
210         new_socket_ptr =  (NX_TCP_SOCKET *)(socket_ptr -> nx_tcp_socket_bind_suspension_list) -> tx_thread_suspend_control_block;
211 
212         /* Clear the new socket's bind in progress flag.  */
213         new_socket_ptr -> nx_tcp_socket_bind_in_progress =  NX_NULL;
214 
215         /* Inherit the suspension list from the previously bound socket.  Decrement the suspension count
216            early since this thread will be resumed and removed from the list later.  */
217         new_socket_ptr -> nx_tcp_socket_bind_suspension_list =
218             socket_ptr -> nx_tcp_socket_bind_suspension_list;
219         new_socket_ptr -> nx_tcp_socket_bind_suspended_count =   socket_ptr -> nx_tcp_socket_bind_suspended_count - 1;
220 
221         /* Clear the original socket's information.  */
222         socket_ptr -> nx_tcp_socket_bind_suspension_list =  NX_NULL;
223         socket_ptr -> nx_tcp_socket_bind_suspended_count =  0;
224 
225         /* Disable interrupts.  */
226         TX_DISABLE
227 
228         /* Link the new socket to the bound list.  */
229         if (ip_ptr -> nx_ip_tcp_port_table[index])
230         {
231 
232             /* There are already sockets on this list... just add this one
233                to the end.  */
234             new_socket_ptr -> nx_tcp_socket_bound_next =
235                 ip_ptr -> nx_ip_tcp_port_table[index];
236             new_socket_ptr -> nx_tcp_socket_bound_previous =
237                 (ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous;
238             ((ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous) -> nx_tcp_socket_bound_next =
239                 new_socket_ptr;
240             (ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous =   new_socket_ptr;
241         }
242         else
243         {
244 
245             /* Nothing is on the TCP port list.  Add this TCP socket to an
246                empty list.  */
247             new_socket_ptr -> nx_tcp_socket_bound_next =      new_socket_ptr;
248             new_socket_ptr -> nx_tcp_socket_bound_previous =  new_socket_ptr;
249             ip_ptr -> nx_ip_tcp_port_table[index] =           new_socket_ptr;
250         }
251 
252         /* Restore interrupts.  */
253         TX_RESTORE
254 
255         /* Resume the thread suspended on the bind call.  */
256         _nx_tcp_socket_thread_resume(&(new_socket_ptr -> nx_tcp_socket_bind_suspension_list), NX_SUCCESS);
257     }
258 
259     /* Release the protection mutex.  */
260     tx_mutex_put(&(ip_ptr -> nx_ip_protection));
261 
262     /* Return success.  */
263     return(NX_SUCCESS);
264 }
265 
266