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