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
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _nx_tcp_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 TCP 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_tcp_free_port_find(NX_IP * ip_ptr,UINT port,UINT * free_port_ptr)78 UINT _nx_tcp_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_TCP_SOCKET *search_ptr;
85 NX_TCP_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_TCP_FREE_PORT_FIND, ip_ptr, port, 0, 0, NX_TRACE_TCP_EVENTS, &trace_event, &trace_timestamp);
95
96 /* Save the original port. */
97 starting_port = port;
98
99 /* Loop through the TCP ports until a free entry is found. */
100 do
101 {
102
103 /* Calculate the hash index in the TCP port array of the associated IP instance. */
104 index = (UINT)((port + (port >> 8)) & NX_TCP_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 TCP ports bound list. */
111 search_ptr = ip_ptr -> nx_ip_tcp_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 TCP 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_tcp_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_tcp_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_TCP, 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_TCP_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