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