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