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 #include "nx_ip.h"
30 #include "nx_packet.h"
31 #ifdef FEATURE_NX_IPV6
32 #include "nx_ipv6.h"
33 #endif /* FEATURE_NX_IPV6 */
34 
35 #ifdef NX_IPSEC_ENABLE
36 #include "nx_ipsec.h"
37 #endif /* NX_IPSEC_ENABLE */
38 
39 
40 #ifdef NX_ENABLE_TCPIP_OFFLOAD
41 /**************************************************************************/
42 /*                                                                        */
43 /*  FUNCTION                                               RELEASE        */
44 /*                                                                        */
45 /*    _nx_udp_socket_driver_send                          PORTABLE C      */
46 /*                                                           6.4.0        */
47 /*  AUTHOR                                                                */
48 /*                                                                        */
49 /*    Yuxin Zhou, Microsoft Corporation                                   */
50 /*                                                                        */
51 /*  DESCRIPTION                                                           */
52 /*                                                                        */
53 /*    This function sends a UDP packet through TCP/IP offload interface.  */
54 /*                                                                        */
55 /*  INPUT                                                                 */
56 /*                                                                        */
57 /*    socket_ptr                            Pointer to UDP socket         */
58 /*    packet_ptr                            Pointer to UDP packet         */
59 /*    ip_src_address                        Source IP address             */
60 /*    ip_dst_address                        Destination IP address        */
61 /*    port                                  16-bit UDP port number        */
62 /*                                                                        */
63 /*  OUTPUT                                                                */
64 /*                                                                        */
65 /*    status                                Completion status             */
66 /*                                                                        */
67 /*  CALLS                                                                 */
68 /*                                                                        */
69 /*    _nx_ip_packet_send                    Packet send function          */
70 /*    _nx_ipv6_packet_send                  Packet send function          */
71 /*                                                                        */
72 /*  CALLED BY                                                             */
73 /*                                                                        */
74 /*    _nxd_udp_socket_send                                                */
75 /*                                                                        */
76 /*  RELEASE HISTORY                                                       */
77 /*                                                                        */
78 /*    DATE              NAME                      DESCRIPTION             */
79 /*                                                                        */
80 /*  08-02-2021     Yuxin Zhou               Initial Version 6.1.8         */
81 /*  01-31-2022     Yuxin Zhou               Modified comment(s), corrected*/
82 /*                                            the logic for queued packet,*/
83 /*                                            resulting in version 6.1.10 */
84 /*  12-31-2023     Yajun Xia                Modified comment(s),          */
85 /*                                            supported VLAN,             */
86 /*                                            resulting in version 6.4.0  */
87 /*                                                                        */
88 /**************************************************************************/
_nx_udp_socket_driver_send(NX_UDP_SOCKET * socket_ptr,NX_PACKET * packet_ptr,NXD_ADDRESS * ip_src_address,NXD_ADDRESS * ip_dst_address,UINT port)89 static UINT _nx_udp_socket_driver_send(NX_UDP_SOCKET *socket_ptr,
90                                        NX_PACKET     *packet_ptr,
91                                        NXD_ADDRESS   *ip_src_address,
92                                        NXD_ADDRESS   *ip_dst_address,
93                                        UINT           port)
94 {
95 UINT            status;
96 NX_IP          *ip_ptr;
97 NX_INTERFACE   *interface_ptr = NX_NULL;
98 UCHAR          *original_ptr = packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_UDP_HEADER);
99 ULONG           original_length = packet_ptr -> nx_packet_length - sizeof(NX_UDP_HEADER);
100 UINT            packet_reset = NX_FALSE;
101 
102     /* Set up the pointer to the associated IP instance.  */
103     ip_ptr =  socket_ptr -> nx_udp_socket_ip_ptr;
104 
105     /* Get the outgoing interface. */
106 #ifndef NX_DISABLE_IPV4
107     if (ip_dst_address -> nxd_ip_version == NX_IP_VERSION_V4)
108     {
109         interface_ptr = packet_ptr -> nx_packet_address.nx_packet_interface_ptr;
110     }
111 #endif /* NX_DISABLE_IPV4 */
112 #ifdef FEATURE_NX_IPV6
113     if (ip_dst_address -> nxd_ip_version == NX_IP_VERSION_V6)
114     {
115         interface_ptr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached;
116     }
117 #endif /* FEATURE_NX_IPV6 */
118 
119 #ifdef NX_ENABLE_IP_PACKET_FILTER
120     /* Check if the IP packet filter is set. */
121     if (ip_ptr -> nx_ip_packet_filter || ip_ptr -> nx_ip_packet_filter_extended)
122     {
123 
124         /* Add the IP Header to trigger filtering.  */
125 #ifndef NX_DISABLE_IPV4
126         if (ip_dst_address -> nxd_ip_version == NX_IP_VERSION_V4)
127         {
128             _nx_ip_header_add(ip_ptr, packet_ptr,
129                               ip_src_address -> nxd_ip_address.v4,
130                               ip_dst_address -> nxd_ip_address.v4,
131                               socket_ptr -> nx_udp_socket_type_of_service,
132                               socket_ptr -> nx_udp_socket_time_to_live,
133                               NX_IP_UDP, socket_ptr -> nx_udp_socket_fragment_enable);
134         }
135 #endif /* !NX_DISABLE_IPV4  */
136 
137 #ifdef FEATURE_NX_IPV6
138         if (ip_dst_address -> nxd_ip_version == NX_IP_VERSION_V6)
139         {
140             if (_nx_ipv6_header_add(ip_ptr, &packet_ptr, NX_PROTOCOL_UDP,
141                                     packet_ptr -> nx_packet_length,
142                                     ip_ptr -> nx_ipv6_hop_limit,
143                                     ip_src_address -> nxd_ip_address.v6,
144                                     ip_dst_address -> nxd_ip_address.v6, NX_NULL))
145             {
146 
147                 /* Packet consumed by IPv6 layer. Just return success.  */
148                 tx_mutex_put(&(ip_ptr -> nx_ip_protection));
149                 return(NX_SUCCESS);
150             }
151 
152             /* Reset IP header.  */
153             packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_IPV6_HEADER);
154             packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - sizeof(NX_IPV6_HEADER);
155         }
156 #endif /* FEATURE_NX_IPV6 */
157 
158         if (ip_ptr -> nx_ip_packet_filter)
159         {
160             if (ip_ptr -> nx_ip_packet_filter((VOID *)(packet_ptr -> nx_packet_prepend_ptr),
161                                               NX_IP_PACKET_OUT) != NX_SUCCESS)
162             {
163 
164                 /* Packet consumed by IP filter. Just return success.  */
165                 _nx_packet_transmit_release(packet_ptr);
166                 return(NX_SUCCESS);
167             }
168         }
169 
170         /* Check if the IP packet filter extended is set. */
171         if (ip_ptr -> nx_ip_packet_filter_extended)
172         {
173 
174             /* Yes, call the IP packet filter extended routine. */
175             if (ip_ptr -> nx_ip_packet_filter_extended(ip_ptr, packet_ptr, NX_IP_PACKET_OUT) != NX_SUCCESS)
176             {
177 
178                 /* Packet consumed by IP filter. Just return success.  */
179                 _nx_packet_transmit_release(packet_ptr);
180                 return(NX_SUCCESS);
181             }
182         }
183     }
184 #endif /* NX_ENABLE_IP_PACKET_FILTER */
185 
186     /* Reset UDP and IP header.  */
187     packet_ptr -> nx_packet_prepend_ptr = original_ptr;
188     packet_ptr -> nx_packet_length = original_length;
189 
190     /* Determine if the packet is a queued data packet. _nx_packet_transmit_release in Offload handler
191        does not release the packet immediately and only adjusts the prepend pointer to User data,
192        since the packet may need to be resent. To keep the same logic for retransmission in upper layer,
193        the prepend pointer must be reset to UDP header.  */
194     if ((packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next != ((NX_PACKET*)NX_PACKET_ALLOCATED)) &&
195         (packet_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next != ((NX_PACKET*)NX_PACKET_FREE)))
196     {
197         packet_reset = NX_TRUE;
198     }
199 
200     /* Let TCP/IP offload interface send the packet.  */
201     status = interface_ptr -> nx_interface_tcpip_offload_handler(ip_ptr, interface_ptr, socket_ptr,
202                                                                  NX_TCPIP_OFFLOAD_UDP_SOCKET_SEND,
203                                                                  packet_ptr, ip_src_address, ip_dst_address,
204                                                                  socket_ptr -> nx_udp_socket_port,
205                                                                  &port, NX_NO_WAIT);
206 
207     /* Release the IP protection.  */
208     tx_mutex_put(&(ip_ptr -> nx_ip_protection));
209 
210     if (status)
211     {
212         return(NX_TCPIP_OFFLOAD_ERROR);
213     }
214     else
215     {
216 
217         /* Reset prepend pointer to UDP header for queued packet.  */
218         if (packet_reset == NX_TRUE)
219         {
220             packet_ptr -> nx_packet_prepend_ptr = original_ptr - sizeof(NX_UDP_HEADER);
221             packet_ptr -> nx_packet_length = original_length + sizeof(NX_UDP_HEADER);
222         }
223 
224         return(NX_SUCCESS);
225     }
226 }
227 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
228 
229 /**************************************************************************/
230 /*                                                                        */
231 /*  FUNCTION                                               RELEASE        */
232 /*                                                                        */
233 /*    _nxd_udp_socket_send                                PORTABLE C      */
234 /*                                                           6.1.8        */
235 /*  AUTHOR                                                                */
236 /*                                                                        */
237 /*    Yuxin Zhou, Microsoft Corporation                                   */
238 /*                                                                        */
239 /*  DESCRIPTION                                                           */
240 /*                                                                        */
241 /*    This function sends a UDP packet through the specified socket       */
242 /*    with the input IP address and port.                                 */
243 /*                                                                        */
244 /*  INPUT                                                                 */
245 /*                                                                        */
246 /*    socket_ptr                            Pointer to UDP socket         */
247 /*    packet_ptr                            Pointer to UDP packet         */
248 /*    ip_address                            IP address                    */
249 /*    port                                  16-bit UDP port number        */
250 /*                                                                        */
251 /*  OUTPUT                                                                */
252 /*                                                                        */
253 /*    status                                Completion status             */
254 /*    NX_IPSEC_REJECTED                     Failed IPSec check            */
255 /*    NX_NOT_BOUND                          Socket not bound to a port    */
256 /*    NX_NO_INTERFACE_ADDRESS               Socket interface not marked   */
257 /*                                             valid                      */
258 /*  CALLS                                                                 */
259 /*                                                                        */
260 /*    _nx_ip_packet_send                    Send UDP packet over IPv4     */
261 /*    _nx_ipv6_packet_send                  Send UDP packet over IPv6     */
262 /*    nx_ip_checksum_compute                Compute UDP header checksum   */
263 /*    tx_mutex_get                          Get protection mutex          */
264 /*    tx_mutex_put                          Put protection mutex          */
265 /*    _nxd_ipv6_interface_find              Find interface for input      */
266 /*                                             address in IP address table*/
267 /*    [_nx_packet_egress_sa_lookup]         IPsec process                 */
268 /*                                                                        */
269 /*  CALLED BY                                                             */
270 /*                                                                        */
271 /*    Application Code                                                    */
272 /*                                                                        */
273 /*  RELEASE HISTORY                                                       */
274 /*                                                                        */
275 /*    DATE              NAME                      DESCRIPTION             */
276 /*                                                                        */
277 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
278 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
279 /*                                            resulting in version 6.1    */
280 /*  08-02-2021     Yuxin Zhou               Modified comment(s), and      */
281 /*                                            supported TCP/IP offload,   */
282 /*                                            resulting in version 6.1.8  */
283 /*                                                                        */
284 /**************************************************************************/
_nxd_udp_socket_send(NX_UDP_SOCKET * socket_ptr,NX_PACKET * packet_ptr,NXD_ADDRESS * ip_address,UINT port)285 UINT  _nxd_udp_socket_send(NX_UDP_SOCKET *socket_ptr,
286                            NX_PACKET     *packet_ptr,
287                            NXD_ADDRESS   *ip_address,
288                            UINT           port)
289 {
290 TX_INTERRUPT_SAVE_AREA
291 
292 NX_IP         *ip_ptr;
293 NX_UDP_HEADER *udp_header_ptr;
294 ULONG         *ip_src_addr = NX_NULL, *ip_dest_addr = NX_NULL;
295 #ifndef NX_DISABLE_IPV4
296 ULONG          next_hop_address = 0;
297 #endif /* !NX_DISABLE_IPV4  */
298 #if !defined(NX_DISABLE_IPV4) || (defined(FEATURE_NX_IPV6) && defined(NX_ENABLE_INTERFACE_CAPABILITY))
299 NX_INTERFACE  *interface_ptr = NX_NULL;
300 #endif /* !NX_DISABLE_IPV4 || (FEATURE_NX_IPV6 && NX_ENABLE_INTERFACE_CAPABILITY) */
301 #ifdef FEATURE_NX_IPV6
302 UINT           status;
303 #endif /* FEATURE_NX_IPV6 */
304 
305 #ifdef NX_ENABLE_TCPIP_OFFLOAD
306 NXD_ADDRESS    ip_src_address;
307 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
308 
309 #ifdef NX_IPSEC_ENABLE
310 VOID          *sa = NX_NULL;
311 ULONG          data_offset;
312 NXD_ADDRESS    src_addr;
313 UINT           ret;
314 #endif /* NX_IPSEC_ENABLE */
315 
316 #ifdef TX_ENABLE_EVENT_TRACE
317 UINT           ip_address_log = 0;
318 #endif /* TX_ENABLE_EVENT_TRACE */
319 
320 #if defined(NX_DISABLE_UDP_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE)
321 UINT           compute_checksum = 1;
322 #endif /* defined(NX_DISABLE_UDP_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */
323 
324 #ifdef NX_DISABLE_UDP_TX_CHECKSUM
325     /* Disable UDP TX checksum. */
326     compute_checksum = 0;
327 #endif /* NX_DISABLE_UDP_TX_CHECKSUM */
328 
329     /* Lockout interrupts.  */
330     TX_DISABLE
331 
332     /* Add debug information. */
333     NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
334 
335     /* Determine if the socket is currently bound to a UDP port.  */
336     if (!socket_ptr ->  nx_udp_socket_bound_next)
337     {
338 
339         /* Restore interrupts.  */
340         TX_RESTORE
341 
342         /* Socket is not bound, return an error message.  */
343         return(NX_NOT_BOUND);
344     }
345 
346     /* Pickup the important information from the socket.  */
347 
348     /* Set up the pointer to the associated IP instance.  */
349     ip_ptr =  socket_ptr -> nx_udp_socket_ip_ptr;
350 
351 #ifdef TX_ENABLE_EVENT_TRACE
352 
353 #ifndef NX_DISABLE_IPV4
354     /* For IPv4 packets, log the whole IP address. */
355     if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4)
356     {
357         ip_address_log = ip_address -> nxd_ip_address.v4;
358     }
359 #endif /* !NX_DISABLE_IPV4  */
360 
361 #ifdef FEATURE_NX_IPV6
362 
363     /* For IPv6 packets, log the least significant 32-bit of the IP address. */
364     if (ip_address -> nxd_ip_version == NX_IP_VERSION_V6)
365     {
366         ip_address_log = ip_address -> nxd_ip_address.v6[3];
367     }
368 #endif /* FEATURE_NX_IPV6  */
369 
370     /* If trace is enabled, insert this event into the trace buffer.  */
371     NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOCKET_SEND, socket_ptr, packet_ptr, packet_ptr -> nx_packet_length, ip_address_log, NX_TRACE_UDP_EVENTS, 0, 0);
372 
373 #endif /* TX_ENABLE_EVENT_TRACE */
374 
375     /* Restore interrupts.  */
376     TX_RESTORE
377 
378 #ifndef NX_DISABLE_IPV4
379     if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4)
380     {
381 
382         /* Look for a suitable interface. */
383         _nx_ip_route_find(ip_ptr, ip_address -> nxd_ip_address.v4, &packet_ptr -> nx_packet_address.nx_packet_interface_ptr,
384                           &next_hop_address);
385 
386         /* Check the packet interface.  */
387         if (!packet_ptr -> nx_packet_address.nx_packet_interface_ptr)
388         {
389 
390             /* None found; return the error status. */
391             return(NX_IP_ADDRESS_ERROR);
392         }
393 
394         interface_ptr = packet_ptr -> nx_packet_address.nx_packet_interface_ptr;
395 
396         /* Fill in the IP src/dest address */
397         ip_dest_addr = &ip_address -> nxd_ip_address.v4;
398         ip_src_addr = &interface_ptr -> nx_interface_ip_address;
399 
400 #ifdef NX_ENABLE_TCPIP_OFFLOAD
401         ip_src_address.nxd_ip_version = NX_IP_VERSION_V4;
402         ip_src_address.nxd_ip_address.v4 = interface_ptr -> nx_interface_ip_address;
403 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
404     }
405 #endif /* NX_DISABLE_IPV4 */
406 
407 #ifdef FEATURE_NX_IPV6
408     if (ip_address -> nxd_ip_version == NX_IP_VERSION_V6)
409     {
410 
411         if (packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr == NX_NULL)
412         {
413 
414             /* Determine if the IP instance has a matching address for the packet destination. */
415             status = _nxd_ipv6_interface_find(ip_ptr, ip_address -> nxd_ip_address.v6,
416                                               &packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr,
417                                               NX_NULL);
418 
419             /* If not, return the error status. */
420             if (status != NX_SUCCESS)
421             {
422                 return(status);
423             }
424         }
425 
426         /* Fill in the IP src/dest address */
427         ip_dest_addr = &ip_address -> nxd_ip_address.v6[0];
428         ip_src_addr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address;
429 
430 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
431         /* Get the packet interface information. */
432         interface_ptr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached;
433 #endif /* NX_ENABLE_INTERFACE_CAPABILITY  */
434 
435 #ifdef NX_ENABLE_TCPIP_OFFLOAD
436         ip_src_address.nxd_ip_version = NX_IP_VERSION_V6;
437         COPY_IPV6_ADDRESS(ip_src_addr, ip_src_address.nxd_ip_address.v6);
438 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
439     }
440 #endif /* FEATURE_NX_IPV6 */
441 
442 #ifdef NX_IPSEC_ENABLE
443 #ifndef NX_DISABLE_IPV4
444     if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4)
445     {
446 
447         /* Copy IP version and address for internal IPSec (SA) processing. */
448         src_addr.nxd_ip_version = NX_IP_VERSION_V4;
449         src_addr.nxd_ip_address.v4 = interface_ptr -> nx_interface_ip_address;
450     }
451 #endif /* NX_DISABLE_IPV4 */
452 
453 #ifdef FEATURE_NX_IPV6
454     if (ip_address -> nxd_ip_version == NX_IP_VERSION_V6)
455     {
456 
457         /* Handle for IPv6 packets. */
458         src_addr.nxd_ip_version = NX_IP_VERSION_V6;
459         COPY_IPV6_ADDRESS(packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address, src_addr.nxd_ip_address.v6);
460     }
461 #endif /* FEATURE_NX_IPV6 */
462 
463     /* Check for possible SA match. */
464     if (ip_ptr -> nx_ip_packet_egress_sa_lookup != NX_NULL)               /* IPsec is enabled. */
465     {
466         /* If the SA has not been set. */
467         ret = ip_ptr -> nx_ip_packet_egress_sa_lookup(ip_ptr,                                    /* IP ptr */
468                                                       &src_addr,                                 /* src_addr */
469                                                       ip_address,                                /* dest_addr */
470                                                       NX_PROTOCOL_UDP,                           /* protocol */
471                                                       socket_ptr -> nx_udp_socket_port,          /* src_port */
472                                                       port,                                      /* dest_port */
473                                                       &data_offset, &sa, 0);
474         if (ret == NX_IPSEC_TRAFFIC_PROTECT)
475         {
476 
477             /* Save the SA to the packet. */
478             packet_ptr -> nx_packet_ipsec_sa_ptr = sa;
479         }
480         else if (ret == NX_IPSEC_TRAFFIC_DROP || ret == NX_IPSEC_TRAFFIC_PENDING_IKEV2)
481         {
482             return(NX_IPSEC_REJECTED);
483         }
484         else
485         {
486             /* Zero out sa information. */
487             packet_ptr -> nx_packet_ipsec_sa_ptr = NX_NULL;
488         }
489     }
490 #endif /* NX_IPSEC_ENABLE */
491 
492     /* Prepend the UDP header to the packet.  First, make room for the UDP header.  */
493     packet_ptr -> nx_packet_prepend_ptr =  packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER);
494 
495     /* Set the correct IP version. */
496     packet_ptr -> nx_packet_ip_version = (UCHAR)(ip_address -> nxd_ip_version);
497 
498 #ifndef NX_DISABLE_UDP_INFO
499     /* Increment the total UDP packets sent count.  */
500     ip_ptr -> nx_ip_udp_packets_sent++;
501 
502     /* Increment the total UDP bytes sent.  */
503     ip_ptr -> nx_ip_udp_bytes_sent +=  packet_ptr -> nx_packet_length;
504 
505     /* Increment the total UDP packets sent count for this socket.  */
506     socket_ptr -> nx_udp_socket_packets_sent++;
507 
508     /* Increment the total UDP bytes sent for this socket.  */
509     socket_ptr -> nx_udp_socket_bytes_sent +=  packet_ptr -> nx_packet_length;
510 #endif
511 
512     /* Increase the packet length.  */
513     packet_ptr -> nx_packet_length =  packet_ptr -> nx_packet_length + (ULONG)sizeof(NX_UDP_HEADER);
514 
515     /* Setup the UDP header pointer.  */
516     /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
517     udp_header_ptr =  (NX_UDP_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
518 
519     /* Build the first 32-bit word of the UDP header.  */
520     udp_header_ptr -> nx_udp_header_word_0 =
521         (((ULONG)socket_ptr -> nx_udp_socket_port) << NX_SHIFT_BY_16) | (ULONG)port;
522 
523     /* Build the second 32-bit word of the UDP header.  */
524     udp_header_ptr -> nx_udp_header_word_1 =  (packet_ptr -> nx_packet_length << NX_SHIFT_BY_16);
525 
526     /* If trace is enabled, insert this event into the trace buffer.  */
527     NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_UDP_SEND, ip_ptr, socket_ptr, packet_ptr, udp_header_ptr -> nx_udp_header_word_0, NX_TRACE_INTERNAL_EVENTS, 0, 0);
528 
529     /* Endian swapping logic.  If NX_LITTLE_ENDIAN is specified, these macros will
530     swap the endian of the UDP header.  */
531     NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0);
532     NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
533 
534     /* Determine if we need to compute the UDP checksum.
535 
536     Note that with IPv6, UDP packet checksum is mandatory. However if the underly device
537     driver is able to compute UDP checksum in hardware, let the driver handle the checksum
538     computation.
539     */
540 
541     if ((!socket_ptr -> nx_udp_socket_disable_checksum) ||
542         (ip_address -> nxd_ip_version == NX_IP_VERSION_V6))
543     {
544 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
545         if (interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM)
546         {
547             compute_checksum = 0;
548         }
549 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
550 
551 #ifdef NX_IPSEC_ENABLE
552         /* In case this packet is going through the IPsec protected channel, the checksum would have to be computed
553         in software even if the hardware checksum is available at driver layer.  The checksum value must be present
554         in order when applying IPsec process. */
555 
556         if ((packet_ptr -> nx_packet_ipsec_sa_ptr != NX_NULL) && (((NX_IPSEC_SA *)(packet_ptr -> nx_packet_ipsec_sa_ptr)) -> nx_ipsec_sa_encryption_method != NX_CRYPTO_NONE))
557         {
558             compute_checksum = 1;
559         }
560 #endif /* NX_IPSEC_ENABLE */
561 
562 #if defined(NX_DISABLE_UDP_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE)
563         if (compute_checksum)
564 #endif /* defined(NX_DISABLE_UDP_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */
565         {
566 
567         ULONG checksum;
568 
569             /* Yes, we need to compute the UDP checksum.  */
570             checksum = _nx_ip_checksum_compute(packet_ptr,
571                                                NX_PROTOCOL_UDP,
572                                                (UINT)packet_ptr -> nx_packet_length,
573                                                ip_src_addr,
574                                                ip_dest_addr);
575             checksum = ~checksum & NX_LOWER_16_MASK;
576 
577             /* If the computed checksum is zero, it will be transmitted as all ones. */
578             /* RFC 768, page 2. */
579             if (checksum == 0)
580             {
581                 checksum = 0xFFFF;
582             }
583 
584             NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
585 
586             udp_header_ptr -> nx_udp_header_word_1 = udp_header_ptr -> nx_udp_header_word_1 | checksum;
587 
588             NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1);
589         }
590 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
591         else
592         {
593             /* Set CHECKSUM flag so the driver would invoke the HW checksum. */
594             packet_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_UDP_TX_CHECKSUM;
595         }
596 #endif
597     }
598 
599     /* Get mutex protection.  */
600     tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
601 
602 #ifdef NX_ENABLE_TCPIP_OFFLOAD
603     if ((interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_TCPIP_OFFLOAD) &&
604         (interface_ptr -> nx_interface_tcpip_offload_handler))
605     {
606         return(_nx_udp_socket_driver_send(socket_ptr, packet_ptr, &ip_src_address, ip_address, port));
607     }
608 #endif /* NX_ENABLE_TCPIP_OFFLOAD */
609 
610 #ifdef NX_ENABLE_VLAN
611     if (socket_ptr -> nx_udp_socket_vlan_priority != NX_VLAN_PRIORITY_INVALID)
612     {
613         packet_ptr -> nx_packet_vlan_priority = socket_ptr -> nx_udp_socket_vlan_priority;
614     }
615 #endif /* NX_ENABLE_VLAN */
616 
617 #ifndef NX_DISABLE_IPV4
618     /* Send the UDP packet to the IPv4 component.  */
619     if (ip_address -> nxd_ip_version == NX_IP_VERSION_V4)
620     {
621 
622         /*lint -e{644} suppress variable might not be initialized, since "next_hop_address" was initialized in _nx_ip_route_find. */
623         _nx_ip_packet_send(ip_ptr, packet_ptr, ip_address -> nxd_ip_address.v4,
624                            socket_ptr -> nx_udp_socket_type_of_service,
625                            socket_ptr -> nx_udp_socket_time_to_live,
626                            NX_IP_UDP, socket_ptr -> nx_udp_socket_fragment_enable,
627                            next_hop_address);
628     }
629 #endif /* NX_DISABLE_IPV4 */
630 
631 #ifdef FEATURE_NX_IPV6
632     if (ip_address -> nxd_ip_version == NX_IP_VERSION_V6)
633     {
634 
635         /* Set the source IPv6 address */
636         _nx_ipv6_packet_send(ip_ptr, packet_ptr, NX_PROTOCOL_UDP,
637                              packet_ptr -> nx_packet_length, ip_ptr -> nx_ipv6_hop_limit,
638                              ip_src_addr,
639                              ip_dest_addr);
640     }
641 #endif /* FEATURE_NX_IPV6 */
642 
643     /* Release mutex protection.  */
644     tx_mutex_put(&(ip_ptr -> nx_ip_protection));
645 
646     /* Return a successful status.  */
647     return(NX_SUCCESS);
648 }
649 
650