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 /** Internet Protocol (IP) */
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_ip.h"
29 #include "nx_igmp.h"
30 #include "nx_packet.h"
31 #include "nx_udp.h"
32
33 #ifndef NX_DISABLE_IPV4
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _nx_ipv4_packet_receive PORTABLE C */
39 /* 6.3.0 */
40 /* AUTHOR */
41 /* */
42 /* Yuxin Zhou, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function receives a packet from the nx_ip_packet_receive. */
47 /* nx_ip_packet_receive forwards only IPv4 packet to this function. */
48 /* Here it is either processes it or places it in a deferred */
49 /* processing queue, depending on the complexity of the packet. */
50 /* */
51 /* INPUT */
52 /* */
53 /* ip_ptr Pointer to IP control block */
54 /* packet_ptr Pointer to packet to send */
55 /* */
56 /* OUTPUT */
57 /* */
58 /* None */
59 /* */
60 /* CALLS */
61 /* */
62 /* _nx_ip_checksum_compute Compute IP checksum */
63 /* _nx_igmp_multicast_check Check for Multicast match */
64 /* _nx_packet_release Release packet to packet pool */
65 /* tx_event_flags_set Set events for IP thread */
66 /* _nx_ip_dispatch_process The routine that examines */
67 /* other optional headers and */
68 /* upper layer protocols. */
69 /* */
70 /* CALLED BY */
71 /* */
72 /* Application I/O Driver */
73 /* */
74 /* RELEASE HISTORY */
75 /* */
76 /* DATE NAME DESCRIPTION */
77 /* */
78 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
79 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
80 /* resulting in version 6.1 */
81 /* 10-31-2023 Tiejun Zhou Modified comment(s), */
82 /* validated packet length for */
83 /* fragments, */
84 /* resulting in version 6.3.0 */
85 /* */
86 /**************************************************************************/
_nx_ipv4_packet_receive(NX_IP * ip_ptr,NX_PACKET * packet_ptr)87 VOID _nx_ipv4_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr)
88 {
89
90 TX_INTERRUPT_SAVE_AREA
91 #ifndef NX_DISABLE_PACKET_CHAIN
92 NX_PACKET *before_last_packet;
93 NX_PACKET *last_packet;
94 #endif /* NX_DISABLE_PACKET_CHAIN */
95 NX_IPV4_HEADER *ip_header_ptr;
96 ULONG *word_ptr;
97 ULONG ip_header_length;
98 ULONG protocol;
99 ULONG delta;
100 ULONG val;
101 ULONG pkt_length;
102 ULONG checksum;
103 NX_INTERFACE *if_ptr;
104 NX_UDP_HEADER *udp_header_ptr;
105 UINT dest_port;
106 UINT option_processed;
107 #if defined(NX_DISABLE_IP_RX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY)
108 UINT compute_checksum = 1;
109 #endif /* defined(NX_DISABLE_IP_RX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) */
110 #ifdef NX_NAT_ENABLE
111 UINT packet_consumed;
112 #endif
113
114 #ifdef NX_DISABLE_IP_RX_CHECKSUM
115 compute_checksum = 0;
116 #endif /* NX_DISABLE_IP_RX_CHECKSUM */
117
118 /* It's assumed that the IP link driver has positioned the top pointer in the
119 packet to the start of the IP address... so that's where we will start. */
120 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
121 ip_header_ptr = (NX_IPV4_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
122
123 /* Add debug information. */
124 NX_PACKET_DEBUG(__FILE__, __LINE__, packet_ptr);
125
126 /* If trace is enabled, insert this event into the trace buffer. */
127 NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IP_RECEIVE, ip_ptr, ip_header_ptr -> nx_ip_header_source_ip, packet_ptr, packet_ptr -> nx_packet_length, NX_TRACE_INTERNAL_EVENTS, 0, 0);
128
129
130 /* Pick up the first word in the IP header. */
131 val = ip_header_ptr -> nx_ip_header_word_0;
132
133 /* Convert to host byte order. */
134 NX_CHANGE_ULONG_ENDIAN(val);
135
136 /* Obtain packet length. */
137 pkt_length = val & NX_LOWER_16_MASK;
138
139 /* Make sure the IP length matches the packet length. Some Ethernet devices
140 add padding to small packets, which results in a discrepancy between the
141 packet length and the IP header length. */
142 if (packet_ptr -> nx_packet_length != pkt_length)
143 {
144
145 /* Determine if the packet length is less than the size reported in the IP header. */
146 if (packet_ptr -> nx_packet_length < pkt_length)
147 {
148
149 /* Packet is too small! */
150
151 #ifndef NX_DISABLE_IP_INFO
152
153 /* Increment the IP invalid packet error. */
154 ip_ptr -> nx_ip_invalid_packets++;
155
156 /* Increment the IP receive packets dropped count. */
157 ip_ptr -> nx_ip_receive_packets_dropped++;
158 #endif
159
160 /* Invalid packet length, just release it. */
161 _nx_packet_release(packet_ptr);
162
163 /* The function is complete, just return! */
164 return;
165 }
166
167 /* Calculate the difference in the length. */
168 delta = packet_ptr -> nx_packet_length - pkt_length;
169
170 /* Adjust the packet length. */
171 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - delta;
172
173 /* Adjust the append pointer. */
174
175 #ifndef NX_DISABLE_PACKET_CHAIN
176 /* Loop to process adjustment that spans multiple packets. */
177 while (delta)
178 {
179
180 /* Determine if the packet is chained (or still chained after the adjustment). */
181 if (packet_ptr -> nx_packet_last == NX_NULL)
182 {
183
184 /* No, packet is not chained, simply adjust the append pointer in the packet. */
185 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - delta;
186
187 /* Break out of the loop, since the adjustment is complete. */
188 break;
189 }
190
191 /* Pickup the pointer to the last packet. */
192 last_packet = packet_ptr -> nx_packet_last;
193
194 /* Determine if the amount to adjust is less than the payload in the last packet. */
195 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
196 if (((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr)) > delta)
197 {
198
199 /* Yes, simply adjust the append pointer of the last packet in the chain. */
200 /*lint -e{946} -e{947} suppress pointer subtraction, since it is necessary. */
201 last_packet -> nx_packet_append_ptr = last_packet -> nx_packet_append_ptr - delta;
202
203 /* Get out of the loop, since the adjustment is complete. */
204 break;
205 }
206 else
207 {
208
209 /* Adjust the delta by the amount in the last packet. */
210 delta = delta - ((ULONG)(last_packet -> nx_packet_append_ptr - last_packet -> nx_packet_prepend_ptr));
211
212 /* Find the packet before the last packet. */
213 before_last_packet = packet_ptr;
214 while (before_last_packet -> nx_packet_next != last_packet)
215 {
216
217 /* Move to the next packet in the chain. */
218 before_last_packet = before_last_packet -> nx_packet_next;
219 }
220
221 /* At this point, we need to release the last packet and adjust the other packet
222 pointers. */
223
224 /* Ensure the next packet pointer is NULL in what is now the last packet. */
225 before_last_packet -> nx_packet_next = NX_NULL;
226
227 /* Determine if the packet is still chained. */
228 if (packet_ptr != before_last_packet)
229 {
230
231 /* Yes, the packet is still chained, setup the last packet pointer. */
232 packet_ptr -> nx_packet_last = before_last_packet;
233 }
234 else
235 {
236
237 /* The packet is no longer chained, set the last packet pointer to NULL. */
238 packet_ptr -> nx_packet_last = NX_NULL;
239 }
240
241 /* Release the last packet. */
242 _nx_packet_release(last_packet);
243 }
244 }
245 #else
246
247 /* Simply adjust the append pointer in the packet. */
248 packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_append_ptr - delta;
249 #endif /* NX_DISABLE_PACKET_CHAIN */
250 }
251
252 /* Get the incoming interface. */
253 if_ptr = packet_ptr -> nx_packet_address.nx_packet_interface_ptr;
254
255 /* Obtain IP header length. */
256 ip_header_length = (val & NX_IP_LENGTH_MASK) >> 24;
257
258 #ifndef NX_DISABLE_RX_SIZE_CHECKING
259
260 /* Check for minimal packet length. The check is done after the endian swapping
261 since the compiler may possibly be able to optimize the lookup of
262 "nx_packet_length" and therefore reduce the amount of work performing these
263 size checks. The endian logic is okay since packets must always have
264 payloads greater than the IP header in size. */
265 if ((packet_ptr -> nx_packet_length <= (ip_header_length << 2)) ||
266 (ip_header_length < NX_IP_NORMAL_LENGTH))
267 {
268
269 /* Packet is too small! */
270
271 #ifndef NX_DISABLE_IP_INFO
272
273 /* Increment the IP invalid packet error. */
274 ip_ptr -> nx_ip_invalid_packets++;
275
276 /* Increment the IP receive packets dropped count. */
277 ip_ptr -> nx_ip_receive_packets_dropped++;
278 #endif
279
280 /* Invalid packet length, just release it. */
281 _nx_packet_release(packet_ptr);
282
283 /* The function is complete, just return! */
284 return;
285 }
286 #endif
287
288 #ifdef NX_ENABLE_INTERFACE_CAPABILITY
289 if (if_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_IPV4_RX_CHECKSUM)
290 {
291 compute_checksum = 0;
292 }
293 #endif /* NX_ENABLE_INTERFACE_CAPABILITY */
294 #if defined(NX_DISABLE_IP_RX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY)
295 if (compute_checksum == 1)
296 #endif /* defined(NX_DISABLE_IP_RX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) */
297 {
298
299
300 checksum = _nx_ip_checksum_compute(packet_ptr, NX_IP_VERSION_V4,
301 /* length is the size of IP header, including options */
302 (UINT)(ip_header_length << 2),
303 /* IPv4 header checksum doesn't care src/dest addresses */
304 NULL, NULL);
305 checksum = ~checksum & NX_LOWER_16_MASK;
306
307 /* Check the checksum again. */
308 if (checksum)
309 {
310
311 #ifndef NX_DISABLE_IP_INFO
312
313 /* Increment the IP invalid packet error. */
314 ip_ptr -> nx_ip_invalid_packets++;
315
316 /* Increment the IP checksum error. */
317 ip_ptr -> nx_ip_receive_checksum_errors++;
318
319 /* Increment the IP receive packets dropped count. */
320 ip_ptr -> nx_ip_receive_packets_dropped++;
321 #endif
322
323 /* Checksum error, just release it. */
324 _nx_packet_release(packet_ptr);
325
326 /* The function is complete, just return! */
327 return;
328 }
329 }
330
331 /* IP receive checksum processing is disabled... just check for and remove if
332 necessary the IP option words. */
333
334 /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will
335 swap the endian of the IP header. */
336 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_0);
337 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_1);
338 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_word_2);
339 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_source_ip);
340 NX_CHANGE_ULONG_ENDIAN(ip_header_ptr -> nx_ip_header_destination_ip);
341
342 #ifdef NX_ENABLE_SOURCE_ADDRESS_CHECK
343 /* Check whether source address is valid. */
344 /* Section 3.2.1.3, page 30, RFC 1122. */
345 if (if_ptr -> nx_interface_address_mapping_needed == NX_TRUE)
346 {
347 if (((ip_header_ptr -> nx_ip_header_source_ip & ~(if_ptr -> nx_interface_ip_network_mask)) == ~(if_ptr -> nx_interface_ip_network_mask)) ||
348 (((ip_header_ptr -> nx_ip_header_source_ip & ~(if_ptr -> nx_interface_ip_network_mask)) == 0) &&
349 (ip_header_ptr -> nx_ip_header_source_ip != 0)) ||
350 ((ip_header_ptr -> nx_ip_header_source_ip & NX_IP_CLASS_D_MASK) == NX_IP_CLASS_D_TYPE))
351 {
352
353 #ifndef NX_DISABLE_IP_INFO
354
355 /* Increment the IP invalid address error. */
356 ip_ptr -> nx_ip_invalid_receive_address++;
357
358 /* Increment the IP receive packets dropped count. */
359 ip_ptr -> nx_ip_receive_packets_dropped++;
360 #endif
361
362 /* Toss the IP packet since we don't know what to do with it! */
363 _nx_packet_release(packet_ptr);
364
365 /* Return to caller. */
366 return;
367 }
368 }
369 #endif /* NX_ENABLE_SOURCE_ADDRESS_CHECK */
370
371 /* Determine if there are options in the IP header that make the length greater
372 than the default length. */
373 if (ip_header_length > NX_IP_NORMAL_LENGTH)
374 {
375
376 /* Process the IPv4 option. */
377 option_processed = _nx_ipv4_option_process(ip_ptr, packet_ptr);
378
379 /* Check the status. */
380 if (option_processed == NX_FALSE)
381 {
382
383 #ifndef NX_DISABLE_IP_INFO
384
385 /* Increment the IP receive packets dropped count. */
386 ip_ptr -> nx_ip_receive_packets_dropped++;
387 #endif
388
389 /* IPv4 option error, toss the packet! */
390 _nx_packet_release(packet_ptr);
391
392 /* In all cases, receive processing is finished. Return to caller. */
393 return;
394 }
395
396 /* Setup a pointer to the last option word. */
397 word_ptr = ((ULONG *)((VOID *)ip_header_ptr)) + ip_header_length - 1;
398
399 /* Remove the option words prior to handling the IP header. */
400 *word_ptr-- = ip_header_ptr -> nx_ip_header_destination_ip;
401 *word_ptr-- = ip_header_ptr -> nx_ip_header_source_ip;
402 *word_ptr-- = ip_header_ptr -> nx_ip_header_word_2;
403 *word_ptr-- = ip_header_ptr -> nx_ip_header_word_1;
404 *word_ptr = (ULONG)(((ip_header_ptr -> nx_ip_header_word_0) & (~NX_IP_LENGTH_MASK)) | NX_IP_VERSION);
405
406 /* Update the ip_header_ptr and the packet and the packet prepend pointer, ip header pointer and length. */
407 /*lint -e{929} -e{740} -e{826} suppress cast from pointer to pointer, since it is necessary */
408 ip_header_ptr = (NX_IPV4_HEADER *)word_ptr;
409
410 /*lint -e{928} suppress cast from pointer to pointer, since it is necessary */
411 packet_ptr -> nx_packet_prepend_ptr = (UCHAR *)word_ptr;
412 packet_ptr -> nx_packet_ip_header = packet_ptr -> nx_packet_prepend_ptr;
413 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - ((ip_header_length - NX_IP_NORMAL_LENGTH) * (ULONG)sizeof(ULONG));
414 }
415
416 /* Check if this IP interface has a NAT forwarding service. If so, let NAT get the
417 packet first and if it is not a packet that should be forwarded by NAT, then
418 let NetX process the packet in the normal way. */
419
420 #ifdef NX_NAT_ENABLE
421 /* Check if this IP interface has a NAT forwarding service. */
422 if (ip_ptr -> nx_ip_nat_packet_process)
423 {
424
425 /* Call NAT preprocess hanlder to check if NAT module can process this packet. */
426 if ((ip_ptr -> nx_ip_nat_packet_process)(ip_ptr, packet_ptr, NX_FALSE) == NX_TRUE)
427 {
428
429 /* NAT router would need to assemble the fragments together first
430 and then translate prior to forwarding. RFC2663, RFC2766. */
431
432 /* Determine if this packet is fragmented. If so, place it on the deferred processing
433 queue. The input packet will then be processed by an IP system thread. */
434 if (ip_header_ptr -> nx_ip_header_word_1 & NX_IP_FRAGMENT_MASK)
435 {
436
437 #ifndef NX_DISABLE_IP_INFO
438
439 /* Increment the IP receive fragments count. */
440 ip_ptr -> nx_ip_total_fragments_received++;
441 #endif
442
443 /* Yes, the incoming IP header is fragmented. Check to see if IP fragmenting
444 has been enabled. */
445 if (ip_ptr -> nx_ip_fragment_assembly)
446 {
447
448 /* Yes, fragmenting is available. Place the packet on the incoming
449 fragment queue. */
450
451 /* Disable interrupts. */
452 TX_DISABLE
453
454 /* Determine if the queue is empty. */
455 if (ip_ptr -> nx_ip_received_fragment_head)
456 {
457
458 /* Reassembly queue is not empty, add this packet to the end of
459 the queue. */
460 (ip_ptr -> nx_ip_received_fragment_tail) -> nx_packet_queue_next = packet_ptr;
461 packet_ptr -> nx_packet_queue_next = NX_NULL;
462 ip_ptr -> nx_ip_received_fragment_tail = packet_ptr;
463 }
464 else
465 {
466
467 /* Reassembly queue is empty. Just setup the head and tail pointers
468 to point to this packet. */
469 ip_ptr -> nx_ip_received_fragment_head = packet_ptr;
470 ip_ptr -> nx_ip_received_fragment_tail = packet_ptr;
471 packet_ptr -> nx_packet_queue_next = NX_NULL;
472 }
473
474 /* Add debug information. */
475 NX_PACKET_DEBUG(NX_PACKET_IP_FRAGMENT_QUEUE, __LINE__, packet_ptr);
476
477 /* Restore interrupts. */
478 TX_RESTORE
479
480 #ifndef NX_FRAGMENT_IMMEDIATE_ASSEMBLY
481 /* Wakeup IP helper thread to process the IP fragment re-assembly. */
482 tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_UNFRAG_EVENT, TX_OR);
483 #else
484 /* Process the IP fragment reassemble. */
485 (ip_ptr -> nx_ip_fragment_assembly)(ip_ptr);
486 #endif /* NX_FRAGMENT_IMMEDIATE_ASSEMBLY */
487 }
488 else
489 {
490
491 #ifndef NX_DISABLE_IP_INFO
492
493 /* Increment the IP receive packets dropped count. */
494 ip_ptr -> nx_ip_receive_packets_dropped++;
495 #endif
496
497 /* Fragmentation has not been enabled, toss the packet! */
498 _nx_packet_release(packet_ptr);
499 }
500
501 /* In all cases, receive processing is finished. Return to caller. */
502 return;
503 }
504
505 /* Normal packet, so forward this packet to the NAT handler. If NAT does not 'consume' this
506 packet, allow NetX to process the packet. */
507 packet_consumed = (ip_ptr -> nx_ip_nat_packet_process)(ip_ptr, packet_ptr, NX_TRUE);
508
509 /* Check to see if the packet has been consumed by NAT. */
510 if (packet_consumed)
511 {
512
513 #ifndef NX_DISABLE_IP_INFO
514
515 /* Increment the IP packets forwarded counter. */
516 ip_ptr -> nx_ip_packets_forwarded++;
517 #endif /* NX_DISABLE_IP_INFO */
518
519 return;
520 }
521 }
522
523 /* (NetX will process all packets that drop through here.) */
524 }
525 #endif
526
527 /* Determine if the IP datagram is for this IP address or a broadcast IP on this
528 network. */
529 if ((ip_header_ptr -> nx_ip_header_destination_ip == if_ptr -> nx_interface_ip_address) ||
530
531 /* Check for incoming IP address of zero. Incoming IP address of zero should
532 be received regardless of our current IP address. */
533 (ip_header_ptr -> nx_ip_header_destination_ip == 0) ||
534
535 /* Check for IP broadcast. */
536 (((ip_header_ptr -> nx_ip_header_destination_ip & if_ptr -> nx_interface_ip_network_mask) ==
537 if_ptr -> nx_interface_ip_network) &&
538 ((ip_header_ptr -> nx_ip_header_destination_ip & ~(if_ptr -> nx_interface_ip_network_mask)) ==
539 ~(if_ptr -> nx_interface_ip_network_mask))) ||
540
541 /* Check for limited broadcast. */
542 (ip_header_ptr -> nx_ip_header_destination_ip == NX_IP_LIMITED_BROADCAST) ||
543
544 /* Check for loopback address. */
545 ((ip_header_ptr -> nx_ip_header_destination_ip >= NX_IP_LOOPBACK_FIRST) &&
546 (ip_header_ptr -> nx_ip_header_destination_ip <= NX_IP_LOOPBACK_LAST)) ||
547
548 /* Check for valid Multicast address. */
549 (_nx_igmp_multicast_check(ip_ptr, ip_header_ptr -> nx_ip_header_destination_ip, if_ptr)))
550 {
551
552 /* Determine if this packet is fragmented. If so, place it on the deferred processing
553 queue. The input packet will then be processed by an IP system thread. */
554 if (ip_header_ptr -> nx_ip_header_word_1 & NX_IP_FRAGMENT_MASK)
555 {
556
557 #ifndef NX_DISABLE_IP_INFO
558
559 /* Increment the IP receive fragments count. */
560 ip_ptr -> nx_ip_total_fragments_received++;
561 #endif
562
563 /* Yes, the incoming IP header is fragmented. Check to see if IP fragmenting
564 has been enabled. */
565 #ifdef NX_ENABLE_LOW_WATERMARK
566 if (ip_ptr -> nx_ip_fragment_assembly &&
567 (packet_ptr -> nx_packet_pool_owner -> nx_packet_pool_available >=
568 packet_ptr -> nx_packet_pool_owner -> nx_packet_pool_low_watermark))
569 #else
570 if (ip_ptr -> nx_ip_fragment_assembly)
571 #endif
572 {
573
574 /* Yes, fragmenting is available. Place the packet on the incoming
575 fragment queue. */
576
577 /* Check packet length with more fragment bit. If not multiple of 8 bytes... */
578 if ((ip_header_ptr -> nx_ip_header_word_1 & NX_IP_MORE_FRAGMENT) &&
579 (((pkt_length - (ULONG)sizeof(NX_IPV4_HEADER)) & 0x7) != 0))
580 {
581
582 /* Invalid length. Drop the packet. */
583 #ifndef NX_DISABLE_IP_INFO
584
585 /* Increment the IP receive packets dropped count. */
586 ip_ptr -> nx_ip_receive_packets_dropped++;
587 #endif
588 _nx_packet_release(packet_ptr);
589 return;
590 }
591
592 /* Disable interrupts. */
593 TX_DISABLE
594
595 /* Determine if the queue is empty. */
596 if (ip_ptr -> nx_ip_received_fragment_head)
597 {
598
599 /* Reassembly queue is not empty, add this packet to the end of
600 the queue. */
601 (ip_ptr -> nx_ip_received_fragment_tail) -> nx_packet_queue_next = packet_ptr;
602 packet_ptr -> nx_packet_queue_next = NX_NULL;
603 ip_ptr -> nx_ip_received_fragment_tail = packet_ptr;
604 }
605 else
606 {
607
608 /* Reassembly queue is empty. Just setup the head and tail pointers
609 to point to this packet. */
610 ip_ptr -> nx_ip_received_fragment_head = packet_ptr;
611 ip_ptr -> nx_ip_received_fragment_tail = packet_ptr;
612 packet_ptr -> nx_packet_queue_next = NX_NULL;
613 }
614
615 /* Add debug information. */
616 NX_PACKET_DEBUG(NX_PACKET_IP_FRAGMENT_QUEUE, __LINE__, packet_ptr);
617
618 /* Restore interrupts. */
619 TX_RESTORE
620
621 #ifndef NX_FRAGMENT_IMMEDIATE_ASSEMBLY
622 /* Wakeup IP helper thread to process the IP fragment re-assembly. */
623 tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_UNFRAG_EVENT, TX_OR);
624 #else
625 /* Process the IP fragment reassemble. */
626 (ip_ptr -> nx_ip_fragment_assembly)(ip_ptr);
627 #endif /* NX_FRAGMENT_IMMEDIATE_ASSEMBLY */
628 }
629 else
630 {
631
632 #ifndef NX_DISABLE_IP_INFO
633
634 /* Increment the IP receive packets dropped count. */
635 ip_ptr -> nx_ip_receive_packets_dropped++;
636 #endif
637
638 /* Fragmentation has not been enabled, toss the packet! */
639 _nx_packet_release(packet_ptr);
640 }
641
642 /* In all cases, receive processing is finished. Return to caller. */
643 return;
644 }
645
646 /* Determine what protocol the current IP datagram is. */
647 protocol = (ip_header_ptr -> nx_ip_header_word_2 >> 16) & 0xFF;
648
649 /* Remove the IP header from the packet. */
650 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_IPV4_HEADER);
651
652 /* Adjust the length. */
653 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - (ULONG)sizeof(NX_IPV4_HEADER);
654
655 #ifndef NX_DISABLE_IP_INFO
656
657 /* Increment the number of packets delivered. */
658 ip_ptr -> nx_ip_total_packets_delivered++;
659
660 /* Increment the IP packet bytes received (not including the header). */
661 ip_ptr -> nx_ip_total_bytes_received += packet_ptr -> nx_packet_length;
662 #endif
663 if (_nx_ip_dispatch_process(ip_ptr, packet_ptr, (UINT)protocol))
664 {
665 _nx_packet_release(packet_ptr);
666 }
667 }
668 /* Try to receive the DHCP message before release this packet.
669 NetX should receive the unicast DHCP message when interface IP address is zero. */
670
671 /* Check if this IP interface has IP address. */
672 else if (if_ptr -> nx_interface_ip_address == 0)
673 {
674
675 /* Determine what protocol the current IP datagram is. */
676 protocol = ip_header_ptr -> nx_ip_header_word_2 & NX_IP_PROTOCOL_MASK;
677
678 /* Check if this packet is UDP message. */
679 if (protocol == NX_IP_UDP)
680 {
681
682 /* Remove the IP header from the packet. */
683 packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_IPV4_HEADER);
684
685 /* Adjust the length. */
686 packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - (ULONG)sizeof(NX_IPV4_HEADER);
687
688 #ifndef NX_DISABLE_IP_INFO
689
690 /* Increment the number of packets delivered. */
691 ip_ptr -> nx_ip_total_packets_delivered++;
692
693 /* Increment the IP packet bytes received (not including the header). */
694 ip_ptr -> nx_ip_total_bytes_received += packet_ptr -> nx_packet_length;
695 #endif
696
697 /* Pickup the pointer to the head of the UDP packet. */
698 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
699 udp_header_ptr = (NX_UDP_HEADER *)packet_ptr -> nx_packet_prepend_ptr;
700
701 /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will
702 swap the endian of the UDP header. */
703 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0);
704
705 /* Pickup the destination UDP port. */
706 dest_port = (UINT)(udp_header_ptr -> nx_udp_header_word_0 & NX_LOWER_16_MASK);
707
708 /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will
709 swap the endian of the UDP header. */
710 NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_0);
711
712 /* Check if this packet is DHCP message. */
713 if (dest_port == 68)
714 {
715 if (ip_ptr -> nx_ip_udp_packet_receive)
716 {
717
718 /* Yes, dispatch it to the appropriate UDP handler if present. */
719 (ip_ptr -> nx_ip_udp_packet_receive)(ip_ptr, packet_ptr);
720
721 return;
722 }
723 }
724 }
725
726 #ifndef NX_DISABLE_IP_INFO
727
728 /* Decrement the number of packets delivered. */
729 ip_ptr -> nx_ip_total_packets_delivered--;
730
731 /* Decrement the IP packet bytes received (not including the header). */
732 ip_ptr -> nx_ip_total_bytes_received -= packet_ptr -> nx_packet_length;
733
734 /* Increment the IP invalid address error. */
735 ip_ptr -> nx_ip_invalid_receive_address++;
736
737 /* Increment the IP receive packets dropped count. */
738 ip_ptr -> nx_ip_receive_packets_dropped++;
739 #endif
740
741 /* Toss the IP packet since we don't know what to do with it! */
742 _nx_packet_release(packet_ptr);
743
744 /* Return to caller. */
745 return;
746 }
747 else if (ip_ptr -> nx_ip_forward_packet_process)
748 {
749
750 #ifndef NX_DISABLE_IP_INFO
751
752 /* Increment the IP packets forwarded counter. */
753 ip_ptr -> nx_ip_packets_forwarded++;
754 #endif
755
756 /* The packet is not for this IP instance so call the
757 forward IP packet processing routine. */
758 (ip_ptr -> nx_ip_forward_packet_process)(ip_ptr, packet_ptr);
759 }
760 else
761 {
762
763 #ifndef NX_DISABLE_IP_INFO
764
765 /* Increment the IP invalid address error. */
766 ip_ptr -> nx_ip_invalid_receive_address++;
767
768 /* Increment the IP receive packets dropped count. */
769 ip_ptr -> nx_ip_receive_packets_dropped++;
770 #endif
771
772 /* Toss the IP packet since we don't know what to do with it! */
773 _nx_packet_release(packet_ptr);
774
775 /* Return to caller. */
776 return;
777 }
778 }
779 #endif /* !NX_DISABLE_IPV4 */
780
781