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 /**   User Datagram Protocol (UDP)                                        */
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_udp.h"
29 
30 
31 /**************************************************************************/
32 /*                                                                        */
33 /*  FUNCTION                                               RELEASE        */
34 /*                                                                        */
35 /*    _nx_udp_free_port_find                              PORTABLE C      */
36 /*                                                           6.3.0        */
37 /*  AUTHOR                                                                */
38 /*                                                                        */
39 /*    Yuxin Zhou, Microsoft Corporation                                   */
40 /*                                                                        */
41 /*  DESCRIPTION                                                           */
42 /*                                                                        */
43 /*    This function finds the first available UDP port, starting from the */
44 /*    supplied port.  If no available ports are found, an error is        */
45 /*    returned.                                                           */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    ip_ptr                                IP instance pointer           */
50 /*    port                                  Starting port                 */
51 /*    free_port_ptr                         Pointer to return free port   */
52 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    status                                Completion status             */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    tx_mutex_get                          Obtain protection mutex       */
60 /*    tx_mutex_put                          Release protection mutex      */
61 /*                                                                        */
62 /*  CALLED BY                                                             */
63 /*                                                                        */
64 /*    Application Code                                                    */
65 /*                                                                        */
66 /*  RELEASE HISTORY                                                       */
67 /*                                                                        */
68 /*    DATE              NAME                      DESCRIPTION             */
69 /*                                                                        */
70 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
71 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
72 /*                                            resulting in version 6.1    */
73 /*  10-31-2023     Haiqing Zhao             Modified comment(s), improved */
74 /*                                            internal logic,             */
75 /*                                            resulting in version 6.3.0  */
76 /*                                                                        */
77 /**************************************************************************/
_nx_udp_free_port_find(NX_IP * ip_ptr,UINT port,UINT * free_port_ptr)78 UINT  _nx_udp_free_port_find(NX_IP *ip_ptr, UINT port, UINT *free_port_ptr)
79 {
80 
81 UINT           index;
82 UINT           bound;
83 UINT           starting_port;
84 NX_UDP_SOCKET *search_ptr;
85 NX_UDP_SOCKET *end_ptr;
86 
87 #ifdef TX_ENABLE_EVENT_TRACE
88 TX_TRACE_BUFFER_ENTRY *trace_event;
89 ULONG                  trace_timestamp;
90 #endif
91 
92 
93     /* If trace is enabled, insert this event into the trace buffer.  */
94     NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_FREE_PORT_FIND, ip_ptr, port, 0, 0, NX_TRACE_UDP_EVENTS, &trace_event, &trace_timestamp);
95 
96     /* Save the original port.  */
97     starting_port =  port;
98 
99     /* Loop through the UDP ports until a free entry is found.  */
100     do
101     {
102 
103         /* Calculate the hash index in the UDP port array of the associated IP instance.  */
104         index =  (UINT)((port + (port >> 8)) & NX_UDP_PORT_TABLE_MASK);
105 
106         /* Obtain the IP mutex so we can figure out whether or not the port has already
107            been bound to.  */
108         tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
109 
110         /* Pickup the head of the UDP ports bound list.  */
111         search_ptr =  ip_ptr -> nx_ip_udp_port_table[index];
112 
113         /* Set the bound flag to false.  */
114         bound =  NX_FALSE;
115 
116         /* Determine if we need to perform a list search.  */
117         if (search_ptr)
118         {
119 
120             /* Walk through the circular list of UDP sockets that are already
121                bound.  */
122             end_ptr =     search_ptr;
123             do
124             {
125 
126                 /* Determine if this entry is the same as the requested port.  */
127                 if (search_ptr -> nx_udp_socket_port == port)
128                 {
129 
130                     /* Set the bound flag.  */
131                     bound =  NX_TRUE;
132 
133                     /* Get out of the loop.  */
134                     break;
135                 }
136 
137                 /* Move to the next entry in the list.  */
138                 search_ptr =  search_ptr -> nx_udp_socket_bound_next;
139             } while (search_ptr != end_ptr);
140         }
141 
142 #ifdef NX_NAT_ENABLE
143         if (bound == NX_FALSE)
144         {
145 
146             /* Check if this IP interface has a NAT service. */
147             if (ip_ptr -> nx_ip_nat_port_verify)
148             {
149 
150                 /* Yes, so check the port by NAT handler. If NAT does not use this port, allow NetX to use it.  */
151                 bound = (ip_ptr -> nx_ip_nat_port_verify)(ip_ptr, NX_PROTOCOL_UDP, port);
152             }
153         }
154 #endif
155 
156         /* Release protection.  */
157         tx_mutex_put(&(ip_ptr -> nx_ip_protection));
158 
159         /* Determine if the port is available.  */
160         if (!bound)
161         {
162 
163             /* Setup the return port number.  */
164             *free_port_ptr =  port;
165 
166             /* Update the trace event with the status.  */
167             NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_UDP_FREE_PORT_FIND, 0, 0, port, 0);
168 
169             /* Return success.  */
170             return(NX_SUCCESS);
171         }
172 
173         /* Move to the next port.  */
174         port++;
175 
176         /* Determine if we need to wrap.  */
177         if (port > NX_MAX_PORT)
178         {
179 
180             /* Jump out if the original port is ahead of the defined search start port. */
181             if (starting_port <= NX_SEARCH_PORT_START)
182             {
183                 break;
184             }
185 
186             /* Yes, we need to wrap around.  */
187             port =  NX_SEARCH_PORT_START;
188         }
189     } while (starting_port != port);
190 
191     /* A free port was not found, return an error.  */
192     return(NX_NO_FREE_PORTS);
193 }
194 
195