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