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 /**   User Datagram Protocol (UDP)                                        */
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_udp.h"
30 #include "tx_thread.h"
31 
32 
33 #ifdef NX_ENABLE_TCPIP_OFFLOAD
34 /**************************************************************************/
35 /*                                                                        */
36 /*  FUNCTION                                               RELEASE        */
37 /*                                                                        */
38 /*    _nx_udp_socket_driver_bind                          PORTABLE C      */
39 /*                                                           6.1.8        */
40 /*  AUTHOR                                                                */
41 /*                                                                        */
42 /*    Yuxin Zhou, Microsoft Corporation                                   */
43 /*                                                                        */
44 /*  DESCRIPTION                                                           */
45 /*                                                                        */
46 /*    This function binds to a UDP port through TCP/IP offload interface. */
47 /*                                                                        */
48 /*  INPUT                                                                 */
49 /*                                                                        */
50 /*    socket_ptr                            Pointer to UDP socket         */
51 /*    port                                  16-bit UDP port number        */
52 /*    wait_option                           Suspension option             */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    status                                Completion status             */
57 /*                                                                        */
58 /*  CALLS                                                                 */
59 /*                                                                        */
60 /*    _nx_udp_socket_unbind                 Unbind UDP port               */
61 /*    tx_mutex_get                          Obtain protection mutex       */
62 /*    tx_mutex_put                          Release protection mutex      */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    _nx_udp_socket_bind                                                 */
67 /*                                                                        */
68 /*  RELEASE HISTORY                                                       */
69 /*                                                                        */
70 /*    DATE              NAME                      DESCRIPTION             */
71 /*                                                                        */
72 /*  08-02-2021     Yuxin Zhou               Initial Version 6.1.8         */
73 /*                                                                        */
74 /**************************************************************************/
_nx_udp_socket_driver_bind(NX_UDP_SOCKET * socket_ptr,UINT port,ULONG wait_option)75 static UINT _nx_udp_socket_driver_bind(NX_UDP_SOCKET *socket_ptr, UINT port, ULONG wait_option)
76 {
77 UINT          status = NX_SUCCESS;
78 UINT          i;
79 NX_INTERFACE *interface_ptr;
80 NX_IP        *ip_ptr;
81 
82 
83     /* Setup the pointer to the associated IP instance.  */
84     ip_ptr =  socket_ptr -> nx_udp_socket_ip_ptr;
85 
86     /* Obtain the IP mutex.  */
87     tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
88 
89     /* Loop all interfaces to bind to ones support TCP/IP offload.  */
90     for (i = 0; i < NX_MAX_IP_INTERFACES; i++)
91     {
92 
93         /* Use a local variable for convenience.  */
94         interface_ptr = &(ip_ptr -> nx_ip_interface[i]);
95 
96         /* Check for valid interfaces.  */
97         if ((interface_ptr -> nx_interface_valid == NX_FALSE) ||
98             (interface_ptr -> nx_interface_link_up == NX_FALSE))
99         {
100 
101             /* Skip interface not valid.  */
102             continue;
103         }
104 
105         /* Check for TCP/IP offload feature.  */
106         if (((interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCPIP_OFFLOAD) == 0) ||
107             (interface_ptr -> nx_interface_tcpip_offload_handler == NX_NULL))
108         {
109 
110             /* Skip interface not support TCP/IP offload.  */
111             continue;
112         }
113 
114         /* Let TCP/IP offload interface bind to port.  */
115         status = interface_ptr -> nx_interface_tcpip_offload_handler(ip_ptr, interface_ptr,
116                                                                      socket_ptr,
117                                                                      NX_TCPIP_OFFLOAD_UDP_SOCKET_BIND,
118                                                                      NX_NULL, NX_NULL, NX_NULL, port,
119                                                                      NX_NULL, wait_option);
120         if (status)
121         {
122 
123             /* At least one of the interface fails to bind to port.  */
124             _nx_udp_socket_unbind(socket_ptr);
125             status = NX_TCPIP_OFFLOAD_ERROR;
126             break;
127         }
128     }
129 
130     /* Release the IP protection.  */
131     tx_mutex_put(&(ip_ptr -> nx_ip_protection));
132 
133     return(status);
134 }
135 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
136 
137 
138 /**************************************************************************/
139 /*                                                                        */
140 /*  FUNCTION                                               RELEASE        */
141 /*                                                                        */
142 /*    _nx_udp_socket_bind                                 PORTABLE C      */
143 /*                                                           6.1.11       */
144 /*  AUTHOR                                                                */
145 /*                                                                        */
146 /*    Yuxin Zhou, Microsoft Corporation                                   */
147 /*                                                                        */
148 /*  DESCRIPTION                                                           */
149 /*                                                                        */
150 /*    This function binds the UDP socket a specific UDP port.  If the     */
151 /*    requested port number is currently bound to another socket,         */
152 /*    this function waits for specified period of time (wait_option)      */
153 /*    for the other socket to unbind the port number.                     */
154 /*                                                                        */
155 /*  INPUT                                                                 */
156 /*                                                                        */
157 /*    socket_ptr                            Pointer to UDP socket         */
158 /*    port                                  16-bit UDP port number        */
159 /*    wait_option                           Suspension option             */
160 /*                                                                        */
161 /*  OUTPUT                                                                */
162 /*                                                                        */
163 /*    status                                Completion status             */
164 /*                                                                        */
165 /*  CALLS                                                                 */
166 /*                                                                        */
167 /*    _nx_udp_free_port_find                Find a free UDP port          */
168 /*    tx_mutex_get                          Obtain protection mutex       */
169 /*    tx_mutex_put                          Release protection mutex      */
170 /*    _tx_thread_system_suspend             Suspend thread                */
171 /*                                                                        */
172 /*  CALLED BY                                                             */
173 /*                                                                        */
174 /*    Application Code                                                    */
175 /*                                                                        */
176 /*  RELEASE HISTORY                                                       */
177 /*                                                                        */
178 /*    DATE              NAME                      DESCRIPTION             */
179 /*                                                                        */
180 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
181 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
182 /*                                            resulting in version 6.1    */
183 /*  08-02-2021     Yuxin Zhou               Modified comment(s), and      */
184 /*                                            supported TCP/IP offload,   */
185 /*                                            resulting in version 6.1.8  */
186 /*  04-25-2022     Yuxin Zhou               Modified comment(s), and      */
187 /*                                            corrected the random value, */
188 /*                                            resulting in version 6.1.11 */
189 /*                                                                        */
190 /**************************************************************************/
_nx_udp_socket_bind(NX_UDP_SOCKET * socket_ptr,UINT port,ULONG wait_option)191 UINT  _nx_udp_socket_bind(NX_UDP_SOCKET *socket_ptr, UINT  port, ULONG wait_option)
192 {
193 
194 TX_INTERRUPT_SAVE_AREA
195 UINT           index;
196 #ifdef NX_NAT_ENABLE
197 UINT           bound;
198 #endif /* NX_NAT_ENABLE */
199 NX_IP         *ip_ptr;
200 TX_THREAD     *thread_ptr;
201 NX_UDP_SOCKET *search_ptr;
202 NX_UDP_SOCKET *end_ptr;
203 UINT           status = NX_SUCCESS;
204 
205 
206     /* Setup the pointer to the associated IP instance.  */
207     ip_ptr =  socket_ptr -> nx_udp_socket_ip_ptr;
208 
209     /* If trace is enabled, insert this event into the trace buffer.  */
210     NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOCKET_BIND, ip_ptr, socket_ptr, port, wait_option, NX_TRACE_UDP_EVENTS, 0, 0);
211 
212     /* Obtain the IP mutex so we can figure out whether or not the port has already
213        been bound to.  */
214     tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
215 
216     /* Determine if the socket has already been bound to port or if a socket bind is
217        already pending from another thread.  */
218     if ((socket_ptr -> nx_udp_socket_bound_next) ||
219         (socket_ptr -> nx_udp_socket_bind_in_progress))
220     {
221 
222         /* Release the protection mutex.  */
223         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
224 
225         /* Return an already bound error code.  */
226         return(NX_ALREADY_BOUND);
227     }
228 
229     /* Determine if the port needs to be allocated.  */
230     if (port == NX_ANY_PORT)
231     {
232 
233         /* Call the find routine to allocate a UDP port.  */
234         port = NX_SEARCH_PORT_START + (UINT)(((ULONG)NX_RAND()) % ((NX_MAX_PORT + 1) - NX_SEARCH_PORT_START));
235         if (_nx_udp_free_port_find(ip_ptr, port, &port) != NX_SUCCESS)
236         {
237 
238             /* Release the protection mutex.  */
239             tx_mutex_put(&(ip_ptr -> nx_ip_protection));
240 
241             /* There was no free port, return an error code.  */
242             return(NX_NO_FREE_PORTS);
243         }
244     }
245 #ifdef NX_NAT_ENABLE
246     else
247     {
248 
249         /* Check if this IP interface has a NAT service. */
250         if (ip_ptr -> nx_ip_nat_port_verify)
251         {
252 
253             /* Yes, so check the port by NAT handler.  */
254             bound = (ip_ptr -> nx_ip_nat_port_verify)(ip_ptr, NX_PROTOCOL_UDP, port);
255 
256             /* Check to see if the port has been bound by NAT.  */
257             if (bound == NX_TRUE)
258             {
259 
260                 /* Release the protection.  */
261                 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
262 
263                 /* Return the port unavailable error.  */
264                 return(NX_PORT_UNAVAILABLE);
265             }
266         }
267     }
268 #endif
269 
270     /* Save the port number in the UDP socket structure.  */
271     socket_ptr -> nx_udp_socket_port =  port;
272 
273     /* Calculate the hash index in the UDP port array of the associated IP instance.  */
274     index =  (UINT)((port + (port >> 8)) & NX_UDP_PORT_TABLE_MASK);
275 
276     /* Pickup the head of the UDP ports bound list.  */
277     search_ptr =  ip_ptr -> nx_ip_udp_port_table[index];
278 
279     /* Determine if we need to perform a list search.  */
280     if (search_ptr)
281     {
282 
283         /* Walk through the circular list of UDP sockets that are already
284            bound.  */
285         end_ptr = search_ptr;
286         do
287         {
288 
289             /* Determine if this entry is the same as the requested port.  */
290             if (search_ptr -> nx_udp_socket_port == port)
291             {
292 
293                 /* Yes, the port has already been allocated.  */
294                 break;
295             }
296 
297             /* Move to the next entry in the list.  */
298             search_ptr =  search_ptr -> nx_udp_socket_bound_next;
299         } while (search_ptr != end_ptr);
300     }
301 
302     /* Now determine if the port is available.  */
303     if ((search_ptr == NX_NULL) || (search_ptr -> nx_udp_socket_port != port))
304     {
305 
306         /* Place this UDP socket structure on the list of bound ports.  */
307 
308         /* Disable interrupts.  */
309         TX_DISABLE
310 
311         /* Determine if the list is NULL.  */
312         if (search_ptr)
313         {
314 
315             /* There are already sockets on this list... just add this one
316                to the end.  */
317             socket_ptr -> nx_udp_socket_bound_next =       ip_ptr -> nx_ip_udp_port_table[index];
318             socket_ptr -> nx_udp_socket_bound_previous =   (ip_ptr -> nx_ip_udp_port_table[index]) -> nx_udp_socket_bound_previous;
319             ((ip_ptr -> nx_ip_udp_port_table[index]) -> nx_udp_socket_bound_previous) -> nx_udp_socket_bound_next = socket_ptr;
320             (ip_ptr -> nx_ip_udp_port_table[index]) -> nx_udp_socket_bound_previous =   socket_ptr;
321         }
322         else
323         {
324 
325             /* Nothing is on the UDP port list.  Add this UDP socket to an
326                empty list.  */
327             socket_ptr -> nx_udp_socket_bound_next =      socket_ptr;
328             socket_ptr -> nx_udp_socket_bound_previous =  socket_ptr;
329             ip_ptr -> nx_ip_udp_port_table[index] =       socket_ptr;
330         }
331 
332         /* Restore interrupts.  */
333         TX_RESTORE
334 
335         /* Release the mutex protection.  */
336         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
337     }
338     else if (wait_option)
339     {
340 
341         /* Prepare for suspension of this thread.  */
342 
343         /* Disable interrupts.  */
344         TX_DISABLE
345 
346         /* Pickup thread pointer.  */
347         thread_ptr =  _tx_thread_current_ptr;
348 
349         /* Setup cleanup routine pointer.  */
350         thread_ptr -> tx_thread_suspend_cleanup =  _nx_udp_bind_cleanup;
351 
352         /* Setup cleanup information, i.e. this socket control
353            block.  */
354         thread_ptr -> tx_thread_suspend_control_block =  (void *)socket_ptr;
355 
356         /* Also remember the socket that has bound to the port, since the thread
357            is going to be suspended on that socket.  */
358         socket_ptr -> nx_udp_socket_bound_previous =  search_ptr;
359 
360         /* Set the socket bind in progress flag (thread pointer).  */
361         socket_ptr -> nx_udp_socket_bind_in_progress =  thread_ptr;
362 
363         /* Setup suspension list.  */
364         if (search_ptr -> nx_udp_socket_bind_suspension_list)
365         {
366 
367             /* This list is not NULL, add current thread to the end. */
368             thread_ptr -> tx_thread_suspended_next =       search_ptr -> nx_udp_socket_bind_suspension_list;
369             thread_ptr -> tx_thread_suspended_previous =  (search_ptr -> nx_udp_socket_bind_suspension_list) -> tx_thread_suspended_previous;
370             ((search_ptr -> nx_udp_socket_bind_suspension_list) -> tx_thread_suspended_previous) -> tx_thread_suspended_next =  thread_ptr;
371             (search_ptr -> nx_udp_socket_bind_suspension_list) -> tx_thread_suspended_previous =   thread_ptr;
372         }
373         else
374         {
375 
376             /* No other threads are suspended.  Setup the head pointer and
377                just setup this threads pointers to itself.  */
378             search_ptr -> nx_udp_socket_bind_suspension_list =         thread_ptr;
379             thread_ptr -> tx_thread_suspended_next =                   thread_ptr;
380             thread_ptr -> tx_thread_suspended_previous =               thread_ptr;
381         }
382 
383         /* Increment the suspended thread count.  */
384         search_ptr -> nx_udp_socket_bind_suspended_count++;
385 
386         /* Set the state to suspended.  */
387         thread_ptr -> tx_thread_state =  TX_TCP_IP;
388 
389         /* Set the suspending flag.  */
390         thread_ptr -> tx_thread_suspending =  TX_TRUE;
391 
392         /* Temporarily disable preemption.  */
393         _tx_thread_preempt_disable++;
394 
395         /* Save the timeout value.  */
396         thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks =  wait_option;
397 
398         /* Restore interrupts.  */
399         TX_RESTORE
400 
401         /* Release the mutex protection.  */
402         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
403 
404         /* Call actual thread suspension routine.  */
405         _tx_thread_system_suspend(thread_ptr);
406 
407         /* Return the completion status.  */
408         status = thread_ptr -> tx_thread_suspend_status;
409     }
410     else
411     {
412 
413         /* Release the IP protection.  */
414         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
415 
416         /* Return the port unavailable error.  */
417         status = NX_PORT_UNAVAILABLE;
418     }
419 
420 #ifdef NX_ENABLE_TCPIP_OFFLOAD
421     if (status == NX_SUCCESS)
422     {
423 
424         /* Bind to TCP/IP offload interface.  */
425         status = _nx_udp_socket_driver_bind(socket_ptr, port, wait_option);
426     }
427 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
428 
429     /* Return success to the caller.  */
430     return(status);
431 }
432 
433