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_packet.h"
30 #include "nx_ipv6.h"
31 #include "nx_icmpv6.h"
32
33 #ifndef NX_DISABLE_FRAGMENTATION
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _nx_ip_fragment_assembly PORTABLE C */
39 /* 6.1 */
40 /* AUTHOR */
41 /* */
42 /* Yuxin Zhou, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function processes the received fragment queue and attempts to */
47 /* reassemble fragmented IP datagrams. Once a datagram is reassembled */
48 /* it is dispatched to the appropriate component. */
49 /* */
50 /* INPUT */
51 /* */
52 /* ip_ptr Pointer to IP instance */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* None */
57 /* */
58 /* CALLS */
59 /* */
60 /* _nx_packet_release Release packet */
61 /* _nx_ip_dispatch_process The routine that examines */
62 /* other optional headers and */
63 /* upper layer protocols. */
64 /* */
65 /* CALLED BY */
66 /* */
67 /* Application */
68 /* */
69 /* RELEASE HISTORY */
70 /* */
71 /* DATE NAME DESCRIPTION */
72 /* */
73 /* 05-19-2020 Yuxin Zhou Initial Version 6.0 */
74 /* 09-30-2020 Yuxin Zhou Modified comment(s), */
75 /* removed duplicated code, */
76 /* resulting in version 6.1 */
77 /* */
78 /**************************************************************************/
79
_nx_ip_fragment_assembly(NX_IP * ip_ptr)80 VOID _nx_ip_fragment_assembly(NX_IP *ip_ptr)
81 {
82 TX_INTERRUPT_SAVE_AREA
83
84 NX_PACKET *new_fragment_head;
85 NX_PACKET *current_fragment;
86 NX_PACKET *previous_fragment = NX_NULL;
87 NX_PACKET *fragment_head;
88 NX_PACKET *search_ptr;
89 NX_PACKET *previous_ptr;
90 NX_PACKET *found_ptr;
91 NX_PACKET *old_ptr;
92 #ifndef NX_DISABLE_IPV4
93 NX_IPV4_HEADER *search_header = NX_NULL;
94 NX_IPV4_HEADER *current_header = NX_NULL;
95 ULONG current_ttl = 0;
96 #endif /* NX_DISABLE_IPV4 */
97 ULONG current_id = 0;
98 ULONG current_offset = 0;
99 ULONG protocol = NX_PROTOCOL_NO_NEXT_HEADER;
100 ULONG incomplete;
101 ULONG ip_version = NX_IP_VERSION_V4;
102 UCHAR copy_packet;
103 #ifdef FEATURE_NX_IPV6
104 NX_IPV6_HEADER_FRAGMENT_OPTION *search_v6_fragment_option = NX_NULL;
105 NX_IPV6_HEADER_FRAGMENT_OPTION *current_v6_fragment_option = NX_NULL;
106 NX_IPV6_HEADER *current_pkt_ip_header = NX_NULL;
107 #endif /* FEATURE_NX_IPV6 */
108 #ifdef NX_NAT_ENABLE
109 UINT packet_consumed;
110 #endif
111
112
113 /* Disable interrupts. */
114 TX_DISABLE
115
116 /* Remove the packets from the incoming IP fragment queue. */
117 new_fragment_head = ip_ptr -> nx_ip_received_fragment_head;
118 ip_ptr -> nx_ip_received_fragment_head = NX_NULL;
119 ip_ptr -> nx_ip_received_fragment_tail = NX_NULL;
120
121 /* Restore interrupts. */
122 TX_RESTORE
123
124 /* Process each IP packet in the received IP fragment queue. */
125 while (new_fragment_head)
126 {
127
128 /* Setup the copy packet flag. */
129 copy_packet = NX_FALSE;
130
131 /* pick up the version number of this packet. */
132 ip_version = new_fragment_head -> nx_packet_ip_version;
133
134 /* Setup the current fragment pointer. */
135 current_fragment = new_fragment_head;
136
137 /* Move the head pointer. */
138 new_fragment_head = new_fragment_head -> nx_packet_queue_next;
139
140 #ifndef NX_DISABLE_IPV4
141 if (ip_version == NX_IP_VERSION_V4)
142 {
143
144 /* Setup header pointer for this packet. */
145 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
146 current_header = (NX_IPV4_HEADER *)current_fragment -> nx_packet_prepend_ptr;
147
148 /* Pickup the ID of this fragment. */
149 current_id = (current_header -> nx_ip_header_word_1 >> NX_SHIFT_BY_16);
150
151 /* Pickup the offset of the new IP fragment. */
152 current_offset = current_header -> nx_ip_header_word_1 & NX_IP_OFFSET_MASK;
153
154 /* Pickup the time to live of this fragment. */
155 current_ttl = (current_header -> nx_ip_header_word_2 & NX_IP_TIME_TO_LIVE_MASK) >> NX_IP_TIME_TO_LIVE_SHIFT;
156
157 /* Set the IPv4 reassembly time. RFC791, Section3.2, Page27. */
158 current_fragment -> nx_packet_reassembly_time = NX_IPV4_MAX_REASSEMBLY_TIME;
159 if (current_fragment -> nx_packet_reassembly_time < current_ttl)
160 {
161 current_fragment -> nx_packet_reassembly_time = current_ttl;
162 }
163 }
164 #endif /* NX_DISABLE_IPV4 */
165 #ifdef FEATURE_NX_IPV6
166 if (ip_version == NX_IP_VERSION_V6)
167 {
168
169 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
170 current_pkt_ip_header = (NX_IPV6_HEADER *)current_fragment -> nx_packet_ip_header;
171
172 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
173 current_v6_fragment_option = (NX_IPV6_HEADER_FRAGMENT_OPTION *)current_fragment -> nx_packet_prepend_ptr;
174
175 /* Pickup the ID of this fragment. Note that the fragment ID is still in network byte order.
176 The ID is only used as a way to make comparisons. We don't need to byte swap this field. */
177 current_id = current_v6_fragment_option -> nx_ipv6_header_fragment_option_packet_id;
178
179 /* The offset field is left shifted by 3 bits. However when we search through all the fragments
180 for the right location to insert this frame, we don't need get the accurate value of the offset
181 because the relative order of these offsets are preserved. In other words, the lower 3 bits do
182 not affect the outcome of a simple comparison. */
183 current_offset = (current_v6_fragment_option -> nx_ipv6_header_fragment_option_offset_flag & 0xFFF8);
184
185 /* Set the IPv6 reassembly time. RFC2460, Section4.5, Page22. */
186 current_fragment -> nx_packet_reassembly_time = NX_IPV6_MAX_REASSEMBLY_TIME;
187 }
188 #endif
189
190 /* Set the found pointer to NULL. */
191 found_ptr = NX_NULL;
192
193 /* Does the assembly list have anything in it? */
194 if (ip_ptr -> nx_ip_fragment_assembly_head)
195 {
196
197 /* Yes, we need to search the assembly queue to see if this fragment belongs
198 to another fragment. */
199 search_ptr = ip_ptr -> nx_ip_fragment_assembly_head;
200 previous_fragment = NX_NULL;
201 while (search_ptr)
202 {
203
204 /* Check this packet only if the version number matches. */
205 if (ip_version == search_ptr -> nx_packet_ip_version)
206 {
207 #ifndef NX_DISABLE_IPV4
208 if (ip_version == NX_IP_VERSION_V4)
209 {
210 /* Setup a pointer to the IP header of the packet in the assembly list. */
211 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
212 search_header = (NX_IPV4_HEADER *)search_ptr -> nx_packet_prepend_ptr;
213
214 /* Determine if the IP header fields match. RFC 791 Section 3.2 recommends that packet
215 fragments be compared for source IP, destination IP, protocol and IP header ID. */
216 /*lint -e{644} suppress variable might not be initialized, since "current_head" was initialized. */
217 if ((current_id == (search_header -> nx_ip_header_word_1 >> NX_SHIFT_BY_16)) &&
218 ((search_header -> nx_ip_header_word_2 & NX_IP_PROTOCOL_MASK) ==
219 (current_header -> nx_ip_header_word_2 & NX_IP_PROTOCOL_MASK)) &&
220 (search_header -> nx_ip_header_source_ip == current_header -> nx_ip_header_source_ip) &&
221 (search_header -> nx_ip_header_destination_ip == current_header -> nx_ip_header_destination_ip))
222 {
223
224 /* Yes, we found a match, just set the found_ptr and get out of
225 this loop! */
226 found_ptr = search_ptr;
227
228 /* The reassmebly timer should be MAX(reassembly time, Time To Live). RFC791, Section3.2, Page27. */
229 if (search_ptr -> nx_packet_reassembly_time < current_ttl)
230 {
231 search_ptr -> nx_packet_reassembly_time = current_ttl;
232 }
233
234 /* Updated the reassembly time. */
235 current_fragment -> nx_packet_reassembly_time = search_ptr -> nx_packet_reassembly_time;
236
237 break;
238 }
239 }
240 #endif /* NX_DISABLE_IPV4 */
241
242 #ifdef FEATURE_NX_IPV6
243 if (ip_version == NX_IP_VERSION_V6)
244 {
245
246 NX_IPV6_HEADER *search_pkt_ip_header;
247
248 /* Set up a pointer to the IPv6 fragment option field.*/
249 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
250 search_v6_fragment_option = (NX_IPV6_HEADER_FRAGMENT_OPTION *)search_ptr -> nx_packet_prepend_ptr;
251
252 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
253 search_pkt_ip_header = (NX_IPV6_HEADER *)search_ptr -> nx_packet_ip_header;
254
255 /* Determine if the IP packet IDs match. */
256 /*lint -e{613} suppress possible use of null pointer, since "current_pkt_ip_header" was set to none NULL above. */
257 if ((current_id == search_v6_fragment_option -> nx_ipv6_header_fragment_option_packet_id) &&
258 (CHECK_IPV6_ADDRESSES_SAME(search_pkt_ip_header -> nx_ip_header_source_ip, current_pkt_ip_header -> nx_ip_header_source_ip)) &&
259 (CHECK_IPV6_ADDRESSES_SAME(search_pkt_ip_header -> nx_ip_header_destination_ip, current_pkt_ip_header -> nx_ip_header_destination_ip)))
260 {
261
262 /* Yes, we found a match, just set the found_ptr and get out of
263 this loop! */
264 found_ptr = search_ptr;
265 current_fragment -> nx_packet_reassembly_time = search_ptr -> nx_packet_reassembly_time;
266 break;
267 }
268 }
269 #endif /* FEATURE_NX_IPV6 */
270 }
271
272 /* Remember the previous pointer. */
273 previous_fragment = search_ptr;
274
275 /* Move to the next IP fragment in the re-assembly queue. */
276 search_ptr = search_ptr -> nx_packet_queue_next;
277 }
278 }
279
280 /* Was another IP packet fragment found? */
281 if (found_ptr)
282 {
283
284 /* Save the fragment head pointer. */
285 fragment_head = found_ptr;
286
287 /* Another packet fragment was found... find the proper place in the list
288 for this packet and check for complete re-assembly. */
289
290 /* Setup the previous pointer. Note that the search pointer still points
291 to the first fragment in the list. */
292 previous_ptr = NX_NULL;
293 search_ptr = found_ptr;
294
295 /* Loop to walk through the fragment list. */
296 do
297 {
298
299 #ifndef NX_DISABLE_IPV4
300 if (ip_version == NX_IP_VERSION_V4)
301 {
302
303 /* Pickup a pointer to the IP header of the fragment. */
304 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
305 search_header = (NX_IPV4_HEADER *)search_ptr -> nx_packet_prepend_ptr;
306
307 /* Determine if the incoming IP fragment goes before this packet. */
308 if (current_offset <= (search_header -> nx_ip_header_word_1 & NX_IP_OFFSET_MASK))
309 {
310
311 /* Determine if the incoming IP fragment is the copy packet. Link the new packet before old packet. */
312 if (current_offset == (search_header -> nx_ip_header_word_1 & NX_IP_OFFSET_MASK))
313 {
314 copy_packet = NX_TRUE;
315 }
316
317 /* Yes, break out of the loop and insert the current packet. */
318 break;
319 }
320 }
321 #endif /* NX_DISABLE_IPV4 */
322
323 #ifdef FEATURE_NX_IPV6
324 if (ip_version == NX_IP_VERSION_V6)
325 {
326
327 /* Build the IP header pointer. */
328 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
329 search_v6_fragment_option = (NX_IPV6_HEADER_FRAGMENT_OPTION *)search_ptr -> nx_packet_prepend_ptr;
330
331 /* Determine if the incoming IP fragment goes before this packet. */
332 if (current_offset <= (ULONG)(search_v6_fragment_option -> nx_ipv6_header_fragment_option_offset_flag & 0xFFF8))
333 {
334
335 /* Determine if the incoming IP fragment is copy packet. Link the new packet before old packet. */
336 if (current_offset == (ULONG)(search_v6_fragment_option -> nx_ipv6_header_fragment_option_offset_flag & 0xFFF8))
337 {
338 copy_packet = NX_TRUE;
339 }
340
341 /* Yes, break out of the loop and insert the current packet. */
342 break;
343 }
344 }
345 #endif /* FEATURE_NX_IPV6 */
346
347 /* Otherwise, move the search and previous pointers to the next fragment in the
348 chain. */
349 previous_ptr = search_ptr;
350 search_ptr = search_ptr -> nx_packet_union_next.nx_packet_fragment_next;
351 } while (search_ptr);
352
353
354 /* At this point, the previous pointer determines where to place the new fragment. */
355 if (previous_ptr)
356 {
357
358 /* Add new fragment after the previous ptr. */
359 current_fragment -> nx_packet_union_next.nx_packet_fragment_next = previous_ptr -> nx_packet_union_next.nx_packet_fragment_next;
360 previous_ptr -> nx_packet_union_next.nx_packet_fragment_next = current_fragment;
361 }
362 else
363 {
364
365 /* This packet needs to be inserted at the front of the fragment chain. */
366 current_fragment -> nx_packet_queue_next = fragment_head -> nx_packet_queue_next;
367 current_fragment -> nx_packet_union_next.nx_packet_fragment_next = fragment_head;
368 if (previous_fragment)
369 {
370
371 /* We need to link up a different IP packet fragment chain that is in
372 front of this one on the re-assembly queue. */
373 previous_fragment -> nx_packet_queue_next = current_fragment;
374 }
375 else
376 {
377
378 /* Nothing prior to this IP fragment chain, we need to just change the
379 list header. */
380 ip_ptr -> nx_ip_fragment_assembly_head = current_fragment;
381
382 /* Clear the timeout fragment pointer. */
383 ip_ptr -> nx_ip_timeout_fragment = NX_NULL;
384 }
385
386 /* Determine if we need to adjust the tail pointer. */
387 if (fragment_head == ip_ptr -> nx_ip_fragment_assembly_tail)
388 {
389
390 /* Setup the new tail pointer. */
391 ip_ptr -> nx_ip_fragment_assembly_tail = current_fragment;
392 }
393
394 /* Setup the new fragment head. */
395 fragment_head = current_fragment;
396 }
397
398 /* Determine if the incoming IP fragment is the same packet. */
399 if (copy_packet == NX_TRUE)
400 {
401
402 /* Fragments contain the same data, use the more recently arrived copy. RFC791, Section3.2, Page29. */
403
404 /* Removed the old packet from the packet list, the old packet must be linked after new packet. */
405 old_ptr = current_fragment -> nx_packet_union_next.nx_packet_fragment_next;
406 current_fragment -> nx_packet_union_next.nx_packet_fragment_next = old_ptr -> nx_packet_union_next.nx_packet_fragment_next;
407
408 /* Reset tcp_queue_next before releasing. */
409 /* Cast the ULONG into a packet pointer. Since this is exactly what we wish to do, disable the lint warning with the following comment: */
410 /*lint -e{923} suppress cast of ULONG to pointer. */
411 old_ptr -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED;
412
413 /* Release the old packet. */
414 _nx_packet_release(old_ptr);
415 }
416
417 /* At this point, the new IP fragment is in its proper place on the re-assembly
418 list. We now need to walk the list and determine if all the fragments are
419 present. */
420
421 /* Setup the search pointer to the fragment head. */
422 search_ptr = fragment_head;
423
424 /* Set the current expected offset to 0. */
425 current_offset = 0;
426
427 /* Loop through the packet chain to see if all the fragments have
428 arrived. */
429 incomplete = 0;
430 do
431 {
432
433 #ifndef NX_DISABLE_IPV4
434 if (ip_version == NX_IP_VERSION_V4)
435 {
436
437 /* Build the IP header pointer. */
438 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
439 search_header = (NX_IPV4_HEADER *)search_ptr -> nx_packet_prepend_ptr;
440
441 /* Check for the expected current offset. */
442 if (current_offset != (search_header -> nx_ip_header_word_1 & NX_IP_OFFSET_MASK))
443 {
444
445 incomplete = 1;
446 /* There are still more fragments necessary to reassemble this packet
447 so just return. */
448 break;
449 }
450
451 /* Calculate the next expected offset. */
452 current_offset = current_offset +
453 ((search_header -> nx_ip_header_word_0 & NX_LOWER_16_MASK) - (ULONG)sizeof(NX_IPV4_HEADER)) /
454 NX_IP_ALIGN_FRAGS;
455 }
456 #endif /* NX_DISABLE_IPV4 */
457
458 #ifdef FEATURE_NX_IPV6
459 if (ip_version == NX_IP_VERSION_V6)
460 {
461
462 /* Build the IP header pointer. */
463 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
464 search_v6_fragment_option = (NX_IPV6_HEADER_FRAGMENT_OPTION *)search_ptr -> nx_packet_prepend_ptr;
465
466 /* Check for the expected current offset. */
467 if (current_offset != (ULONG)(search_v6_fragment_option -> nx_ipv6_header_fragment_option_offset_flag & 0xFFF8))
468 {
469
470 incomplete = 1;
471 /* There are still more fragments necessary to reassemble this packet
472 so just return. */
473 break;
474 }
475
476 /* Calculate the next expected offset. */
477 current_offset = current_offset +
478 (search_ptr -> nx_packet_length - (ULONG)sizeof(NX_IPV6_HEADER_FRAGMENT_OPTION));
479 }
480 #endif /* FEATURE_NX_IPV6 */
481
482 /* Move the search pointer forward to the next fragment. */
483 search_ptr = search_ptr -> nx_packet_union_next.nx_packet_fragment_next;
484 } while (search_ptr);
485
486 if (incomplete)
487 {
488 continue;
489 }
490
491 /* At this point the search header points to the last fragment in the chain. In
492 order for the packet to be complete, the "more fragments" bit in its IP header
493 must be clear. */
494 /*lint -e{613} suppress possible use of null pointer, since "search_header" and "search_v6_fragment_option" were set to none NULL in the while loop above. */
495 if (
496 #ifndef NX_DISABLE_IPV4
497 ((ip_version == NX_IP_VERSION_V4) && (search_header -> nx_ip_header_word_1 & NX_IP_MORE_FRAGMENT))
498 #ifdef FEATURE_NX_IPV6
499 ||
500 #endif /* FEATURE_NX_IPV6 */
501 #endif /* NX_DISABLE_IPV4 */
502 #ifdef FEATURE_NX_IPV6
503 ((ip_version == NX_IP_VERSION_V6) && (search_v6_fragment_option -> nx_ipv6_header_fragment_option_offset_flag & 1))
504 #endif /* FEATURE_NX_IPV6 */
505 )
506 {
507
508 /* There are still more fragments necessary to re-assembly this packet
509 so just return. */
510 continue;
511 }
512
513 /* The packet can be reassembled under the fragment head pointer now. It must now
514 be removed from the re-assembly list. */
515 if (previous_fragment)
516 {
517
518 /* Remove the fragment from a position other than the head of the assembly list. */
519 previous_fragment -> nx_packet_queue_next = fragment_head -> nx_packet_queue_next;
520 }
521 else
522 {
523
524 /* Modify the head of the re-assembly list. */
525 ip_ptr -> nx_ip_fragment_assembly_head = fragment_head -> nx_packet_queue_next;
526
527 /* Clear the timeout fragment pointer since we are removing the first
528 fragment (the oldest) on the assembly list. */
529 ip_ptr -> nx_ip_timeout_fragment = NX_NULL;
530 }
531
532 /* Determine if we need to adjust the tail pointer. */
533 if (fragment_head == ip_ptr -> nx_ip_fragment_assembly_tail)
534 {
535
536 /* Setup the new tail pointer. */
537 ip_ptr -> nx_ip_fragment_assembly_tail = previous_fragment;
538 }
539
540 /* If we get here, the necessary fragments to reassemble the packet
541 are indeed available. We now need to loop through the packet and reassemble
542 it. */
543 search_ptr = fragment_head -> nx_packet_union_next.nx_packet_fragment_next;
544 previous_fragment = fragment_head;
545
546 /* Loop through the fragments and assemble the IP fragment. */
547 while (search_ptr)
548 {
549
550 /* Reset tcp_queue_next before releasing. */
551 /*lint -e{923} suppress cast of ULONG to pointer. */
552 previous_fragment -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED;
553
554 #ifndef NX_DISABLE_IPV4
555 if (ip_version == NX_IP_VERSION_V4)
556 {
557 /* Accumulate the new length into the head packet. */
558 fragment_head -> nx_packet_length = fragment_head -> nx_packet_length +
559 search_ptr -> nx_packet_length - (ULONG)sizeof(NX_IPV4_HEADER);
560
561 /* Position past the IP header in the subsequent packets. */
562 search_ptr -> nx_packet_prepend_ptr = search_ptr -> nx_packet_prepend_ptr +
563 sizeof(NX_IPV4_HEADER);
564 }
565 #endif /* NX_DISABLE_IPV4 */
566 #ifdef FEATURE_NX_IPV6
567 if (ip_version == NX_IP_VERSION_V6)
568 {
569
570 /* For IPv6, we move the prepend ptr to the next option .*/
571 search_ptr -> nx_packet_prepend_ptr += sizeof(NX_IPV6_HEADER_FRAGMENT_OPTION);
572 search_ptr -> nx_packet_length -= (ULONG)sizeof(NX_IPV6_HEADER_FRAGMENT_OPTION);
573
574 /* Accumulate the new length into the head packet. */
575 fragment_head -> nx_packet_length += search_ptr -> nx_packet_length;
576 }
577
578 #endif /* FEATURE_NX_IPV6 */
579
580 /* Link the addition fragment to the head fragment. */
581 if (fragment_head -> nx_packet_last)
582 {
583 (fragment_head -> nx_packet_last) -> nx_packet_next = search_ptr;
584 }
585 else
586 {
587 fragment_head -> nx_packet_next = search_ptr;
588 }
589 if (search_ptr -> nx_packet_last)
590 {
591 fragment_head -> nx_packet_last = search_ptr -> nx_packet_last;
592 }
593 else
594 {
595 fragment_head -> nx_packet_last = search_ptr;
596 }
597
598 /* Set the previous fragment. */
599 previous_fragment = search_ptr;
600
601 /* Move to the next fragment in the chain. */
602 search_ptr = search_ptr -> nx_packet_union_next.nx_packet_fragment_next;
603 }
604
605 /* Reset tcp_queue_next before releasing. */
606 /*lint -e{923} suppress cast of ULONG to pointer. */
607 previous_fragment -> nx_packet_union_next.nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED;
608
609 /* We are now ready to dispatch this packet just like the normal IP receive packet
610 processing. */
611
612 #ifndef NX_DISABLE_IP_INFO
613
614 /* Increment the number of packets reassembled. */
615 ip_ptr -> nx_ip_packets_reassembled++;
616
617 /* Increment the number of packets delivered. */
618 ip_ptr -> nx_ip_total_packets_delivered++;
619
620 /* Increment the IP packet bytes received (not including the header). */
621 ip_ptr -> nx_ip_total_bytes_received += fragment_head -> nx_packet_length;
622 #endif
623
624 /* Build a pointer to the IP header. */
625 #ifndef NX_DISABLE_IPV4
626 if (ip_version == NX_IP_VERSION_V4)
627 {
628
629 /* The packet is now reassembled. */
630
631 /* Check if this IP interface has a NAT forwarding service. If so, let NAT get the
632 packet first and if it is not a packet that should be forwarded by NAT, then
633 let NetX process the packet in the normal way. */
634
635 #ifdef NX_NAT_ENABLE
636
637 /* Check if this IP interface has a NAT forwarding service. */
638 if (ip_ptr -> nx_ip_nat_packet_process)
639 {
640
641 /* Yes, so forward this packet to the NAT handler. If NAT does not 'consume' this
642 packet, allow NetX to process the packet. */
643 packet_consumed = (ip_ptr -> nx_ip_nat_packet_process)(ip_ptr, fragment_head, NX_TRUE);
644
645 /* Check to see if the packet has been consumed by NAT. */
646 if (packet_consumed)
647 {
648
649 #ifndef NX_DISABLE_IP_INFO
650
651 /* Increment the IP packets forwarded counter. */
652 ip_ptr -> nx_ip_packets_forwarded++;
653 #endif /* NX_DISABLE_IP_INFO */
654
655 continue;
656 }
657
658 /* (NetX will process all packets that drop through here.) */
659 }
660 #endif
661
662 /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */
663 current_header = (NX_IPV4_HEADER *)fragment_head -> nx_packet_ip_header;
664
665 /* Determine what protocol the current IP datagram is. */
666 protocol = (current_header -> nx_ip_header_word_2 >> 16) & 0xFF;
667
668 /* Remove the IP header from the packet. */
669 fragment_head -> nx_packet_prepend_ptr = fragment_head -> nx_packet_prepend_ptr + sizeof(NX_IPV4_HEADER);
670
671 /* Adjust the length. */
672 fragment_head -> nx_packet_length = fragment_head -> nx_packet_length - (ULONG)sizeof(NX_IPV4_HEADER);
673 }
674 #endif /* NX_DISABLE_IPV4 */
675 #ifdef FEATURE_NX_IPV6
676 if (ip_version == NX_IP_VERSION_V6)
677 {
678 fragment_head -> nx_packet_prepend_ptr += sizeof(NX_IPV6_HEADER_FRAGMENT_OPTION);
679 fragment_head -> nx_packet_length -= (ULONG)sizeof(NX_IPV6_HEADER_FRAGMENT_OPTION);
680
681 /*lint -e{613} suppress possible use of null pointer, since "current_pkt_ip_header" was set to none NULL above. */
682 protocol = current_v6_fragment_option -> nx_ipv6_header_fragment_option_next_header;
683 }
684 #endif
685
686 /* Call the dispatch function go to process the packet. */
687 if (_nx_ip_dispatch_process(ip_ptr, fragment_head, (UINT)protocol))
688 {
689
690 /* Toss the IP packet since we don't know what to do with it! */
691 _nx_packet_release(fragment_head);
692 }
693 }
694 else
695 {
696
697 /* No other packet was found on the re-assembly list so this packet must be the
698 first one of a new IP packet. Just add it to the end of the assembly queue. */
699 if (ip_ptr -> nx_ip_fragment_assembly_head)
700 {
701
702 /* Re-assembly list is not empty. Just place this IP packet at the
703 end of the IP fragment assembly list. */
704 ip_ptr -> nx_ip_fragment_assembly_tail -> nx_packet_queue_next = current_fragment;
705 ip_ptr -> nx_ip_fragment_assembly_tail = current_fragment;
706 current_fragment -> nx_packet_queue_next = NX_NULL;
707 current_fragment -> nx_packet_union_next.nx_packet_fragment_next = NX_NULL;
708 }
709 else
710 {
711
712 /* First IP fragment on the assembly list. Setup the head and tail pointers to
713 this packet. */
714 ip_ptr -> nx_ip_fragment_assembly_head = current_fragment;
715 ip_ptr -> nx_ip_fragment_assembly_tail = current_fragment;
716 current_fragment -> nx_packet_queue_next = NX_NULL;
717 current_fragment -> nx_packet_union_next.nx_packet_fragment_next = NX_NULL;
718 }
719 }
720 }
721 }
722 #endif /* NX_DISABLE_FRAGMENTATION */
723
724