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