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