2 IP6 internal functions to process the incoming packets.
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Create an empty assemble entry for the packet identified by
20 (Dst, Src, Id). The default life for the packet is 60 seconds.
22 @param[in] Dst The destination address.
23 @param[in] Src The source address.
24 @param[in] Id The ID field in the IP header.
26 @return NULL if failed to allocate memory for the entry. Otherwise,
27 the pointer to the just created reassemble entry.
31 Ip6CreateAssembleEntry (
32 IN EFI_IPv6_ADDRESS
*Dst
,
33 IN EFI_IPv6_ADDRESS
*Src
,
37 IP6_ASSEMBLE_ENTRY
*Assemble
;
39 Assemble
= AllocatePool (sizeof (IP6_ASSEMBLE_ENTRY
));
40 if (Assemble
== NULL
) {
44 IP6_COPY_ADDRESS (&Assemble
->Dst
, Dst
);
45 IP6_COPY_ADDRESS (&Assemble
->Src
, Src
);
46 InitializeListHead (&Assemble
->Fragments
);
49 Assemble
->Life
= IP6_FRAGMENT_LIFE
+ 1;
51 Assemble
->TotalLen
= 0;
53 Assemble
->Head
= NULL
;
54 Assemble
->Info
= NULL
;
55 Assemble
->Packet
= NULL
;
61 Release all the fragments of a packet, then free the assemble entry.
63 @param[in] Assemble The assemble entry to free.
67 Ip6FreeAssembleEntry (
68 IN IP6_ASSEMBLE_ENTRY
*Assemble
75 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &Assemble
->Fragments
) {
76 Fragment
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
78 RemoveEntryList (Entry
);
79 NetbufFree (Fragment
);
82 if (Assemble
->Packet
!= NULL
) {
83 NetbufFree (Assemble
->Packet
);
90 Release all the fragments of the packet. This is the callback for
91 the assembled packet's OnFree. It will free the assemble entry,
92 which in turn frees all the fragments of the packet.
94 @param[in] Arg The assemble entry to free.
103 Ip6FreeAssembleEntry ((IP6_ASSEMBLE_ENTRY
*) Arg
);
107 Trim the packet to fit in [Start, End), and update per the
110 @param[in, out] Packet Packet to trim.
111 @param[in] Start The sequence of the first byte to fit in.
112 @param[in] End One beyond the sequence of last byte to fit in.
117 IN OUT NET_BUF
*Packet
,
125 Info
= IP6_GET_CLIP_INFO (Packet
);
127 ASSERT (Info
->Start
+ Info
->Length
== Info
->End
);
128 ASSERT ((Info
->Start
< End
) && (Start
< Info
->End
));
130 if (Info
->Start
< Start
) {
131 Len
= Start
- Info
->Start
;
133 NetbufTrim (Packet
, (UINT32
) Len
, NET_BUF_HEAD
);
134 Info
->Start
= (UINT32
) Start
;
135 Info
->Length
-= (UINT32
) Len
;
138 if (End
< Info
->End
) {
139 Len
= End
- Info
->End
;
141 NetbufTrim (Packet
, (UINT32
) Len
, NET_BUF_TAIL
);
142 Info
->End
= (UINT32
) End
;
143 Info
->Length
-= (UINT32
) Len
;
148 Reassemble the IP fragments. If all the fragments of the packet
149 have been received, it will wrap the packet in a net buffer then
150 return it to caller. If the packet can't be assembled, NULL is
153 @param[in, out] Table The assemble table used. A new assemble entry will be created
154 if the Packet is from a new chain of fragments.
155 @param[in] Packet The fragment to assemble. It might be freed if the fragment
156 can't be re-assembled.
158 @return NULL if the packet can't be reassembled. The pointer to the just assembled
159 packet if all the fragments of the packet have arrived.
164 IN OUT IP6_ASSEMBLE_TABLE
*Table
,
168 EFI_IP6_HEADER
*Head
;
171 IP6_ASSEMBLE_ENTRY
*Assemble
;
172 IP6_ASSEMBLE_ENTRY
*Entry
;
173 LIST_ENTRY
*ListHead
;
182 UINT16 UnFragmentLen
;
185 Head
= Packet
->Ip
.Ip6
;
186 This
= IP6_GET_CLIP_INFO (Packet
);
188 ASSERT (Head
!= NULL
);
191 // Find the corresponding assemble entry by (Dst, Src, Id)
194 Index
= IP6_ASSEMBLE_HASH (&Head
->DestinationAddress
, &Head
->SourceAddress
, This
->Id
);
196 NET_LIST_FOR_EACH (Cur
, &Table
->Bucket
[Index
]) {
197 Entry
= NET_LIST_USER_STRUCT (Cur
, IP6_ASSEMBLE_ENTRY
, Link
);
199 if (Entry
->Id
== This
->Id
&&
200 EFI_IP6_EQUAL (&Entry
->Src
, &Head
->SourceAddress
) &&
201 EFI_IP6_EQUAL (&Entry
->Dst
, &Head
->DestinationAddress
)
209 // Create a new entry if can not find an existing one, insert it to assemble table
211 if (Assemble
== NULL
) {
212 Assemble
= Ip6CreateAssembleEntry (
213 &Head
->DestinationAddress
,
214 &Head
->SourceAddress
,
218 if (Assemble
== NULL
) {
222 InsertHeadList (&Table
->Bucket
[Index
], &Assemble
->Link
);
226 // Find the point to insert the packet: before the first
227 // fragment with THIS.Start < CUR.Start. the previous one
228 // has PREV.Start <= THIS.Start < CUR.Start.
230 ListHead
= &Assemble
->Fragments
;
232 NET_LIST_FOR_EACH (Cur
, ListHead
) {
233 Fragment
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
235 if (This
->Start
< IP6_GET_CLIP_INFO (Fragment
)->Start
) {
241 // Check whether the current fragment overlaps with the previous one.
242 // It holds that: PREV.Start <= THIS.Start < THIS.End. Only need to
243 // check whether THIS.Start < PREV.End for overlap. If two fragments
244 // overlaps, trim the overlapped part off THIS fragment.
246 if ((Cur
!= ListHead
) && ((Prev
= Cur
->BackLink
) != ListHead
)) {
247 Fragment
= NET_LIST_USER_STRUCT (Prev
, NET_BUF
, List
);
248 Node
= IP6_GET_CLIP_INFO (Fragment
);
250 if (This
->Start
< Node
->End
) {
251 if (This
->End
<= Node
->End
) {
256 // Trim the previous fragment from tail.
258 Ip6TrimPacket (Fragment
, Node
->Start
, This
->Start
);
263 // Insert the fragment into the packet. The fragment may be removed
264 // from the list by the following checks.
266 NetListInsertBefore (Cur
, &Packet
->List
);
269 // Check the packets after the insert point. It holds that:
270 // THIS.Start <= NODE.Start < NODE.End. The equality holds
271 // if PREV and NEXT are continuous. THIS fragment may fill
272 // several holes. Remove the completely overlapped fragments
274 while (Cur
!= ListHead
) {
275 Fragment
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
276 Node
= IP6_GET_CLIP_INFO (Fragment
);
279 // Remove fragments completely overlapped by this fragment
281 if (Node
->End
<= This
->End
) {
282 Cur
= Cur
->ForwardLink
;
284 RemoveEntryList (&Fragment
->List
);
285 Assemble
->CurLen
-= Node
->Length
;
287 NetbufFree (Fragment
);
292 // The conditions are: THIS.Start <= NODE.Start, and THIS.End <
293 // NODE.End. Two fragments overlaps if NODE.Start < THIS.End.
294 // If two fragments start at the same offset, remove THIS fragment
295 // because ((THIS.Start == NODE.Start) && (THIS.End < NODE.End)).
297 if (Node
->Start
< This
->End
) {
298 if (This
->Start
== Node
->Start
) {
299 RemoveEntryList (&Packet
->List
);
303 Ip6TrimPacket (Packet
, This
->Start
, Node
->Start
);
310 // Update the assemble info: increase the current length. If it is
311 // the frist fragment, update the packet's IP head and per packet
312 // info. If it is the last fragment, update the total length.
314 Assemble
->CurLen
+= This
->Length
;
316 if (This
->Start
== 0) {
318 // Once the first fragment is enqueued, it can't be removed
319 // from the fragment list. So, Assemble->Head always point
320 // to valid memory area.
322 if ((Assemble
->Head
!= NULL
) || (Assemble
->Packet
!= NULL
)) {
327 // Backup the first fragment in case the reasembly of that packet fail.
329 Duplicate
= NetbufDuplicate (Packet
, NULL
, sizeof (EFI_IP6_HEADER
));
330 if (Duplicate
== NULL
) {
335 // Revert IP head to network order.
337 DupHead
= NetbufGetByte (Duplicate
, 0, NULL
);
338 ASSERT (DupHead
!= NULL
);
339 Duplicate
->Ip
.Ip6
= Ip6NtohHead ((EFI_IP6_HEADER
*) DupHead
);
340 Assemble
->Packet
= Duplicate
;
343 // Adjust the unfragmentable part in first fragment
345 UnFragmentLen
= (UINT16
) (This
->HeadLen
- sizeof (EFI_IP6_HEADER
));
346 if (UnFragmentLen
== 0) {
348 // There is not any unfragmentable extension header.
350 ASSERT (Head
->NextHeader
== IP6_FRAGMENT
);
351 Head
->NextHeader
= This
->NextHeader
;
353 NextHeader
= NetbufGetByte (
355 This
->FormerNextHeader
+ sizeof (EFI_IP6_HEADER
),
358 if (NextHeader
== NULL
) {
362 *NextHeader
= This
->NextHeader
;
365 Assemble
->Head
= Head
;
366 Assemble
->Info
= IP6_GET_CLIP_INFO (Packet
);
370 // Don't update the length more than once.
372 if ((This
->LastFrag
!= 0) && (Assemble
->TotalLen
== 0)) {
373 Assemble
->TotalLen
= This
->End
;
377 // Deliver the whole packet if all the fragments received.
378 // All fragments received if:
379 // 1. received the last one, so, the totoal length is know
380 // 2. received all the data. If the last fragment on the
381 // queue ends at the total length, all data is received.
383 if ((Assemble
->TotalLen
!= 0) && (Assemble
->CurLen
>= Assemble
->TotalLen
)) {
385 RemoveEntryList (&Assemble
->Link
);
388 // If the packet is properly formated, the last fragment's End
389 // equals to the packet's total length. Otherwise, the packet
390 // is a fake, drop it now.
392 Fragment
= NET_LIST_USER_STRUCT (ListHead
->BackLink
, NET_BUF
, List
);
393 if (IP6_GET_CLIP_INFO (Fragment
)->End
!= (INTN
) Assemble
->TotalLen
) {
394 Ip6FreeAssembleEntry (Assemble
);
398 Fragment
= NET_LIST_HEAD (ListHead
, NET_BUF
, List
);
399 This
= Assemble
->Info
;
402 // This TmpPacket is used to hold the unfragmentable part, i.e.,
403 // the IPv6 header and the unfragmentable extension headers. Be noted that
404 // the Fragment Header is exluded.
406 TmpPacket
= NetbufGetFragment (Fragment
, 0, This
->HeadLen
, 0);
407 ASSERT (TmpPacket
!= NULL
);
409 NET_LIST_FOR_EACH (Cur
, ListHead
) {
411 // Trim off the unfragment part plus the fragment header from all fragments.
413 Fragment
= NET_LIST_USER_STRUCT (Cur
, NET_BUF
, List
);
414 NetbufTrim (Fragment
, This
->HeadLen
+ sizeof (IP6_FRAGMENT_HEADER
), TRUE
);
417 InsertHeadList (ListHead
, &TmpPacket
->List
);
420 // Wrap the packet in a net buffer then deliver it up
422 NewPacket
= NetbufFromBufList (
423 &Assemble
->Fragments
,
430 if (NewPacket
== NULL
) {
431 Ip6FreeAssembleEntry (Assemble
);
435 NewPacket
->Ip
.Ip6
= Assemble
->Head
;
437 CopyMem (IP6_GET_CLIP_INFO (NewPacket
), Assemble
->Info
, sizeof (IP6_CLIP_INFO
));
451 The callback function for the net buffer that wraps the packet processed by
452 IPsec. It releases the wrap packet and also signals IPsec to free the resources.
454 @param[in] Arg The wrap context.
463 IP6_IPSEC_WRAP
*Wrap
;
465 Wrap
= (IP6_IPSEC_WRAP
*) Arg
;
467 if (Wrap
->IpSecRecycleSignal
!= NULL
) {
468 gBS
->SignalEvent (Wrap
->IpSecRecycleSignal
);
471 NetbufFree (Wrap
->Packet
);
479 The work function to locate the IPsec protocol to process the inbound or
480 outbound IP packets. The process routine handles the packet with the following
481 actions: bypass the packet, discard the packet, or protect the packet.
483 @param[in] IpSb The IP6 service instance.
484 @param[in, out] Head The caller-supplied IP6 header.
485 @param[in, out] LastHead The next header field of last IP header.
486 @param[in, out] Netbuf The IP6 packet to be processed by IPsec.
487 @param[in, out] ExtHdrs The caller-supplied options.
488 @param[in, out] ExtHdrsLen The length of the option.
489 @param[in] Direction The directionality in an SPD entry,
490 EfiIPsecInBound, or EfiIPsecOutBound.
491 @param[in] Context The token's wrap.
493 @retval EFI_SUCCESS The IPsec protocol is not available or disabled.
494 @retval EFI_SUCCESS The packet was bypassed, and all buffers remain the same.
495 @retval EFI_SUCCESS The packet was protected.
496 @retval EFI_ACCESS_DENIED The packet was discarded.
497 @retval EFI_OUT_OF_RESOURCES There are not suffcient resources to complete the operation.
498 @retval EFI_BUFFER_TOO_SMALL The number of non-empty blocks is bigger than the
499 number of input data blocks when building a fragment table.
503 Ip6IpSecProcessPacket (
504 IN IP6_SERVICE
*IpSb
,
505 IN OUT EFI_IP6_HEADER
**Head
,
506 IN OUT UINT8
*LastHead
,
507 IN OUT NET_BUF
**Netbuf
,
508 IN OUT UINT8
**ExtHdrs
,
509 IN OUT UINT32
*ExtHdrsLen
,
510 IN EFI_IPSEC_TRAFFIC_DIR Direction
,
514 NET_FRAGMENT
*FragmentTable
;
515 NET_FRAGMENT
*OriginalFragmentTable
;
516 UINT32 FragmentCount
;
517 UINT32 OriginalFragmentCount
;
518 EFI_EVENT RecycleEvent
;
520 IP6_TXTOKEN_WRAP
*TxWrap
;
521 IP6_IPSEC_WRAP
*IpSecWrap
;
523 EFI_IP6_HEADER
*PacketHead
;
525 EFI_IP6_HEADER ZeroHead
;
527 Status
= EFI_SUCCESS
;
531 FragmentTable
= NULL
;
534 TxWrap
= (IP6_TXTOKEN_WRAP
*) Context
;
535 FragmentCount
= Packet
->BlockOpNum
;
536 ZeroMem (&ZeroHead
, sizeof (EFI_IP6_HEADER
));
538 if (mIpSec
== NULL
) {
539 gBS
->LocateProtocol (&gEfiIpSecProtocolGuid
, NULL
, (VOID
**) &mIpSec
);
542 // Check whether the ipsec protocol is available.
544 if (mIpSec
== NULL
) {
550 // Check whether the ipsec enable variable is set.
552 if (mIpSec
->DisabledFlag
) {
554 // If IPsec is disabled, restore the original MTU
556 IpSb
->MaxPacketSize
= IpSb
->OldMaxPacketSize
;
560 // If IPsec is enabled, use the MTU which reduce the IPsec header length.
562 IpSb
->MaxPacketSize
= IpSb
->OldMaxPacketSize
- IP6_MAX_IPSEC_HEADLEN
;
567 // Bypass all multicast inbound or outbound traffic.
569 if (IP6_IS_MULTICAST (&(*Head
)->DestinationAddress
) || IP6_IS_MULTICAST (&(*Head
)->SourceAddress
)) {
574 // Rebuild fragment table from netbuf to ease ipsec process.
576 FragmentTable
= AllocateZeroPool (FragmentCount
* sizeof (NET_FRAGMENT
));
578 if (FragmentTable
== NULL
) {
579 Status
= EFI_OUT_OF_RESOURCES
;
583 Status
= NetbufBuildExt (Packet
, FragmentTable
, &FragmentCount
);
584 OriginalFragmentTable
= FragmentTable
;
585 OriginalFragmentCount
= FragmentCount
;
587 if (EFI_ERROR(Status
)) {
588 FreePool (FragmentTable
);
593 // Convert host byte order to network byte order
597 Status
= mIpSec
->ProcessExt (
605 (EFI_IPSEC_FRAGMENT_DATA
**) (&FragmentTable
),
611 // Convert back to host byte order
615 if (EFI_ERROR (Status
)) {
619 if (OriginalFragmentCount
== FragmentCount
&& OriginalFragmentTable
== FragmentTable
) {
626 if (Direction
== EfiIPsecOutBound
&& TxWrap
!= NULL
) {
627 TxWrap
->IpSecRecycleSignal
= RecycleEvent
;
628 TxWrap
->Packet
= NetbufFromExt (
636 if (TxWrap
->Packet
== NULL
) {
637 Status
= EFI_OUT_OF_RESOURCES
;
642 IP6_GET_CLIP_INFO (TxWrap
->Packet
),
643 IP6_GET_CLIP_INFO (Packet
),
644 sizeof (IP6_CLIP_INFO
)
647 NetIpSecNetbufFree(Packet
);
648 *Netbuf
= TxWrap
->Packet
;
652 IpSecWrap
= AllocateZeroPool (sizeof (IP6_IPSEC_WRAP
));
654 if (IpSecWrap
== NULL
) {
658 IpSecWrap
->IpSecRecycleSignal
= RecycleEvent
;
659 IpSecWrap
->Packet
= Packet
;
660 Packet
= NetbufFromExt (
669 if (Packet
== NULL
) {
670 Status
= EFI_OUT_OF_RESOURCES
;
674 if (Direction
== EfiIPsecInBound
&& 0 != CompareMem (&ZeroHead
, *Head
, sizeof (EFI_IP6_HEADER
))) {
676 PacketHead
= (EFI_IP6_HEADER
*) NetbufAllocSpace (
678 sizeof (EFI_IP6_HEADER
) + *ExtHdrsLen
,
681 if (PacketHead
== NULL
) {
682 Status
= EFI_OUT_OF_RESOURCES
;
686 CopyMem (PacketHead
, *Head
, sizeof (EFI_IP6_HEADER
));
688 Packet
->Ip
.Ip6
= PacketHead
;
690 if (*ExtHdrs
!= NULL
) {
691 Buf
= (UINT8
*) (PacketHead
+ 1);
692 CopyMem (Buf
, *ExtHdrs
, *ExtHdrsLen
);
695 NetbufTrim (Packet
, sizeof (EFI_IP6_HEADER
) + *ExtHdrsLen
, TRUE
);
697 IP6_GET_CLIP_INFO (Packet
),
698 IP6_GET_CLIP_INFO (IpSecWrap
->Packet
),
699 sizeof (IP6_CLIP_INFO
)
710 Pre-process the IPv6 packet. First validates the IPv6 packet, and
711 then reassembles packet if it is necessary.
713 @param[in] IpSb The IP6 service instance.
714 @param[in, out] Packet The received IP6 packet to be processed.
715 @param[in] Flag The link layer flag for the packet received, such
717 @param[out] Payload The pointer to the payload of the recieved packet.
718 it starts from the first byte of the extension header.
719 @param[out] LastHead The pointer of NextHeader of the last extension
720 header processed by IP6.
721 @param[out] ExtHdrsLen The length of the whole option.
722 @param[out] UnFragmentLen The length of unfragmented length of extension headers.
723 @param[out] Fragmented Indicate whether the packet is fragmented.
724 @param[out] Head The pointer to the EFI_IP6_Header.
726 @retval EFI_SUCCESS The received packet is well format.
727 @retval EFI_INVALID_PARAMETER The received packet is malformed.
731 Ip6PreProcessPacket (
732 IN IP6_SERVICE
*IpSb
,
733 IN OUT NET_BUF
**Packet
,
736 OUT UINT8
**LastHead
,
737 OUT UINT32
*ExtHdrsLen
,
738 OUT UINT32
*UnFragmentLen
,
739 OUT BOOLEAN
*Fragmented
,
740 OUT EFI_IP6_HEADER
**Head
747 UINT32 FormerHeadOffset
;
749 IP6_FRAGMENT_HEADER
*FragmentHead
;
750 UINT16 FragmentOffset
;
752 EFI_IPv6_ADDRESS Loopback
;
757 // Check whether the input packet is a valid packet
759 if ((*Packet
)->TotalSize
< IP6_MIN_HEADLEN
) {
760 return EFI_INVALID_PARAMETER
;
764 // Get header information of the packet.
766 *Head
= (EFI_IP6_HEADER
*) NetbufGetByte (*Packet
, 0, NULL
);
768 return EFI_INVALID_PARAMETER
;
772 // Multicast addresses must not be used as source addresses in IPv6 packets.
774 if (((*Head
)->Version
!= 6) || (IP6_IS_MULTICAST (&(*Head
)->SourceAddress
))) {
775 return EFI_INVALID_PARAMETER
;
779 // A packet with a destination address of loopback ::1/128 or unspecified must be dropped.
781 ZeroMem (&Loopback
, sizeof (EFI_IPv6_ADDRESS
));
782 Loopback
.Addr
[15] = 0x1;
783 if ((CompareMem (&Loopback
, &(*Head
)->DestinationAddress
, sizeof (EFI_IPv6_ADDRESS
)) == 0) ||
784 (NetIp6IsUnspecifiedAddr (&(*Head
)->DestinationAddress
))) {
785 return EFI_INVALID_PARAMETER
;
789 // Convert the IP header to host byte order.
791 (*Packet
)->Ip
.Ip6
= Ip6NtohHead (*Head
);
794 // Get the per packet info.
796 Info
= IP6_GET_CLIP_INFO (*Packet
);
797 Info
->LinkFlag
= Flag
;
800 if (IpSb
->MnpConfigData
.EnablePromiscuousReceive
) {
801 Info
->CastType
= Ip6Promiscuous
;
804 if (Ip6IsOneOfSetAddress (IpSb
, &(*Head
)->DestinationAddress
, NULL
, NULL
)) {
805 Info
->CastType
= Ip6Unicast
;
806 } else if (IP6_IS_MULTICAST (&(*Head
)->DestinationAddress
)) {
807 if (Ip6FindMldEntry (IpSb
, &(*Head
)->DestinationAddress
) != NULL
) {
808 Info
->CastType
= Ip6Multicast
;
813 // Drop the packet that is not delivered to us.
815 if (Info
->CastType
== 0) {
816 return EFI_INVALID_PARAMETER
;
820 PayloadLen
= (*Head
)->PayloadLength
;
823 Info
->Length
= PayloadLen
;
824 Info
->End
= Info
->Start
+ Info
->Length
;
825 Info
->HeadLen
= (UINT16
) sizeof (EFI_IP6_HEADER
);
826 Info
->Status
= EFI_SUCCESS
;
827 Info
->LastFrag
= FALSE
;
829 TotalLen
= (UINT16
) (PayloadLen
+ sizeof (EFI_IP6_HEADER
));
832 // Mnp may deliver frame trailer sequence up, trim it off.
834 if (TotalLen
< (*Packet
)->TotalSize
) {
835 NetbufTrim (*Packet
, (*Packet
)->TotalSize
- TotalLen
, FALSE
);
838 if (TotalLen
!= (*Packet
)->TotalSize
) {
839 return EFI_INVALID_PARAMETER
;
843 // Check the extension headers, if exist validate them
845 if (PayloadLen
!= 0) {
846 *Payload
= AllocatePool ((UINTN
) PayloadLen
);
847 if (*Payload
== NULL
) {
848 return EFI_INVALID_PARAMETER
;
851 NetbufCopy (*Packet
, sizeof (EFI_IP6_HEADER
), PayloadLen
, *Payload
);
854 if (!Ip6IsExtsValid (
857 &(*Head
)->NextHeader
,
867 return EFI_INVALID_PARAMETER
;
870 HeadLen
= sizeof (EFI_IP6_HEADER
) + *UnFragmentLen
;
874 // Get the fragment offset from the Fragment header
876 FragmentHead
= (IP6_FRAGMENT_HEADER
*) NetbufGetByte (*Packet
, HeadLen
, NULL
);
877 if (FragmentHead
== NULL
) {
878 return EFI_INVALID_PARAMETER
;
881 FragmentOffset
= NTOHS (FragmentHead
->FragmentOffset
);
883 if ((FragmentOffset
& 0x1) == 0) {
884 Info
->LastFrag
= TRUE
;
887 FragmentOffset
&= (~0x1);
890 // This is the first fragment of the packet
892 if (FragmentOffset
== 0) {
893 Info
->NextHeader
= FragmentHead
->NextHeader
;
896 Info
->HeadLen
= (UINT16
) HeadLen
;
897 HeadLen
+= sizeof (IP6_FRAGMENT_HEADER
);
898 Info
->Start
= FragmentOffset
;
899 Info
->Length
= TotalLen
- (UINT16
) HeadLen
;
900 Info
->End
= Info
->Start
+ Info
->Length
;
901 Info
->Id
= FragmentHead
->Identification
;
902 Info
->FormerNextHeader
= FormerHeadOffset
;
905 // Fragments should in the unit of 8 octets long except the last one.
907 if ((Info
->LastFrag
== 0) && (Info
->Length
% 8 != 0)) {
908 return EFI_INVALID_PARAMETER
;
912 // Reassemble the packet.
914 *Packet
= Ip6Reassemble (&IpSb
->Assemble
, *Packet
);
915 if (*Packet
== NULL
) {
916 return EFI_INVALID_PARAMETER
;
920 // Re-check the assembled packet to get the right values.
922 *Head
= (*Packet
)->Ip
.Ip6
;
923 PayloadLen
= (*Head
)->PayloadLength
;
924 if (PayloadLen
!= 0) {
925 if (*Payload
!= NULL
) {
929 *Payload
= AllocatePool ((UINTN
) PayloadLen
);
930 if (*Payload
== NULL
) {
931 return EFI_INVALID_PARAMETER
;
934 NetbufCopy (*Packet
, sizeof (EFI_IP6_HEADER
), PayloadLen
, *Payload
);
937 if (!Ip6IsExtsValid (
940 &(*Head
)->NextHeader
,
950 return EFI_INVALID_PARAMETER
;
955 // Trim the head off, after this point, the packet is headless.
956 // and Packet->TotalLen == Info->Length.
958 NetbufTrim (*Packet
, sizeof (EFI_IP6_HEADER
) + *ExtHdrsLen
, TRUE
);
964 The IP6 input routine. It is called by the IP6_INTERFACE when an
965 IP6 fragment is received from MNP.
967 @param[in] Packet The IP6 packet received.
968 @param[in] IoStatus The return status of receive request.
969 @param[in] Flag The link layer flag for the packet received, such
971 @param[in] Context The IP6 service instance that owns the MNP.
977 IN EFI_STATUS IoStatus
,
983 EFI_IP6_HEADER
*Head
;
986 UINT32 UnFragmentLen
;
990 EFI_IP6_HEADER ZeroHead
;
992 IpSb
= (IP6_SERVICE
*) Context
;
993 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
999 // Check input parameters
1001 if (EFI_ERROR (IoStatus
) || (IpSb
->State
== IP6_SERVICE_DESTROY
)) {
1006 // Pre-Process the Ipv6 Packet and then reassemble if it is necessary.
1008 Status
= Ip6PreProcessPacket (
1019 if (EFI_ERROR (Status
)) {
1023 // After trim off, the packet is a esp/ah/udp/tcp/icmp6 net buffer,
1024 // and no need consider any other ahead ext headers.
1026 Status
= Ip6IpSecProcessPacket (
1029 LastHead
, // need get the lasthead value for input
1037 if (EFI_ERROR (Status
)) {
1042 // If the packet is protected by IPsec Tunnel Mode, Check the Inner Ip Packet.
1044 ZeroMem (&ZeroHead
, sizeof (EFI_IP6_HEADER
));
1045 if (0 == CompareMem (Head
, &ZeroHead
, sizeof (EFI_IP6_HEADER
))) {
1046 Status
= Ip6PreProcessPacket (
1057 if (EFI_ERROR (Status
)) {
1063 // Packet may have been changed. The ownership of the packet
1064 // is transfered to the packet process logic.
1066 Head
= Packet
->Ip
.Ip6
;
1067 IP6_GET_CLIP_INFO (Packet
)->Status
= EFI_SUCCESS
;
1069 switch (*LastHead
) {
1071 Ip6IcmpHandle (IpSb
, Head
, Packet
);
1074 Ip6Demultiplex (IpSb
, Head
, Packet
);
1080 // Dispatch the DPCs queued by the NotifyFunction of the rx token's events
1081 // which are signaled with received data.
1086 if (Payload
!= NULL
) {
1090 Ip6ReceiveFrame (Ip6AcceptFrame
, IpSb
);
1093 if (Packet
!= NULL
) {
1094 NetbufFree (Packet
);
1101 Initialize an already allocated assemble table. This is generally
1102 the assemble table embedded in the IP6 service instance.
1104 @param[in, out] Table The assemble table to initialize.
1108 Ip6CreateAssembleTable (
1109 IN OUT IP6_ASSEMBLE_TABLE
*Table
1114 for (Index
= 0; Index
< IP6_ASSEMLE_HASH_SIZE
; Index
++) {
1115 InitializeListHead (&Table
->Bucket
[Index
]);
1120 Clean up the assemble table by removing all of the fragments
1121 and assemble entries.
1123 @param[in, out] Table The assemble table to clean up.
1127 Ip6CleanAssembleTable (
1128 IN OUT IP6_ASSEMBLE_TABLE
*Table
1133 IP6_ASSEMBLE_ENTRY
*Assemble
;
1136 for (Index
= 0; Index
< IP6_ASSEMLE_HASH_SIZE
; Index
++) {
1137 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &Table
->Bucket
[Index
]) {
1138 Assemble
= NET_LIST_USER_STRUCT (Entry
, IP6_ASSEMBLE_ENTRY
, Link
);
1140 RemoveEntryList (Entry
);
1141 Ip6FreeAssembleEntry (Assemble
);
1148 The signal handle of IP6's recycle event. It is called back
1149 when the upper layer releases the packet.
1151 @param[in] Event The IP6's recycle event.
1152 @param[in] Context The context of the handle, which is a IP6_RXDATA_WRAP.
1157 Ip6OnRecyclePacket (
1162 IP6_RXDATA_WRAP
*Wrap
;
1164 Wrap
= (IP6_RXDATA_WRAP
*) Context
;
1166 EfiAcquireLockOrFail (&Wrap
->IpInstance
->RecycleLock
);
1167 RemoveEntryList (&Wrap
->Link
);
1168 EfiReleaseLock (&Wrap
->IpInstance
->RecycleLock
);
1170 ASSERT (!NET_BUF_SHARED (Wrap
->Packet
));
1171 NetbufFree (Wrap
->Packet
);
1173 gBS
->CloseEvent (Wrap
->RxData
.RecycleSignal
);
1178 Wrap the received packet to a IP6_RXDATA_WRAP, which will be
1179 delivered to the upper layer. Each IP6 child that accepts the
1180 packet will get a not-shared copy of the packet which is wrapped
1181 in the IP6_RXDATA_WRAP. The IP6_RXDATA_WRAP->RxData is passed
1182 to the upper layer. The upper layer will signal the recycle event in
1183 it when it is done with the packet.
1185 @param[in] IpInstance The IP6 child to receive the packet.
1186 @param[in] Packet The packet to deliver up.
1188 @return NULL if it failed to wrap the packet; otherwise, the wrapper.
1193 IN IP6_PROTOCOL
*IpInstance
,
1197 IP6_RXDATA_WRAP
*Wrap
;
1198 EFI_IP6_RECEIVE_DATA
*RxData
;
1201 Wrap
= AllocatePool (IP6_RXDATA_WRAP_SIZE (Packet
->BlockOpNum
));
1207 InitializeListHead (&Wrap
->Link
);
1209 Wrap
->IpInstance
= IpInstance
;
1210 Wrap
->Packet
= Packet
;
1211 RxData
= &Wrap
->RxData
;
1213 ZeroMem (&RxData
->TimeStamp
, sizeof (EFI_TIME
));
1215 Status
= gBS
->CreateEvent (
1220 &RxData
->RecycleSignal
1223 if (EFI_ERROR (Status
)) {
1228 ASSERT (Packet
->Ip
.Ip6
!= NULL
);
1231 // The application expects a network byte order header.
1233 RxData
->HeaderLength
= sizeof (EFI_IP6_HEADER
);
1234 RxData
->Header
= (EFI_IP6_HEADER
*) Ip6NtohHead (Packet
->Ip
.Ip6
);
1235 RxData
->DataLength
= Packet
->TotalSize
;
1238 // Build the fragment table to be delivered up.
1240 RxData
->FragmentCount
= Packet
->BlockOpNum
;
1241 NetbufBuildExt (Packet
, (NET_FRAGMENT
*) RxData
->FragmentTable
, &RxData
->FragmentCount
);
1247 Check whether this IP child accepts the packet.
1249 @param[in] IpInstance The IP child to check.
1250 @param[in] Head The IP header of the packet.
1251 @param[in] Packet The data of the packet.
1253 @retval TRUE The child wants to receive the packet.
1254 @retval FALSE The child does not want to receive the packet.
1258 Ip6InstanceFrameAcceptable (
1259 IN IP6_PROTOCOL
*IpInstance
,
1260 IN EFI_IP6_HEADER
*Head
,
1264 IP6_ICMP_ERROR_HEAD Icmp
;
1265 EFI_IP6_CONFIG_DATA
*Config
;
1266 IP6_CLIP_INFO
*Info
;
1270 UINT16 ErrMsgPayloadLen
;
1271 UINT8
*ErrMsgPayload
;
1273 Config
= &IpInstance
->ConfigData
;
1277 // Dirty trick for the Tiano UEFI network stack implmentation. If
1278 // ReceiveTimeout == -1, the receive of the packet for this instance
1279 // is disabled. The UEFI spec don't have such captibility. We add
1280 // this to improve the performance because IP will make a copy of
1281 // the received packet for each accepting instance. Some IP instances
1282 // used by UDP/TCP only send packets, they don't wants to receive.
1284 if (Config
->ReceiveTimeout
== (UINT32
)(-1)) {
1288 if (Config
->AcceptPromiscuous
) {
1293 // Check whether the protocol is acceptable.
1295 ExtHdrs
= NetbufGetByte (Packet
, 0, NULL
);
1297 if (!Ip6IsExtsValid (
1298 IpInstance
->Service
,
1302 (UINT32
) Head
->PayloadLength
,
1314 // The upper layer driver may want to receive the ICMPv6 error packet
1315 // invoked by its packet, like UDP.
1317 if ((*Proto
== IP6_ICMP
) && (!Config
->AcceptAnyProtocol
) && (*Proto
!= Config
->DefaultProtocol
)) {
1318 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*) &Icmp
);
1320 if (Icmp
.Head
.Type
<= ICMP_V6_ERROR_MAX
) {
1321 if (!Config
->AcceptIcmpErrors
) {
1326 // Get the protocol of the invoking packet of ICMPv6 error packet.
1328 ErrMsgPayloadLen
= NTOHS (Icmp
.IpHead
.PayloadLength
);
1329 ErrMsgPayload
= NetbufGetByte (Packet
, sizeof (Icmp
), NULL
);
1331 if (!Ip6IsExtsValid (
1334 &Icmp
.IpHead
.NextHeader
,
1350 // Match the protocol
1352 if (!Config
->AcceptAnyProtocol
&& (*Proto
!= Config
->DefaultProtocol
)) {
1357 // Check for broadcast, the caller has computed the packet's
1358 // cast type for this child's interface.
1360 Info
= IP6_GET_CLIP_INFO (Packet
);
1363 // If it is a multicast packet, check whether we are in the group.
1365 if (Info
->CastType
== Ip6Multicast
) {
1367 // Receive the multicast if the instance wants to receive all packets.
1369 if (NetIp6IsUnspecifiedAddr (&IpInstance
->ConfigData
.StationAddress
)) {
1373 for (Index
= 0; Index
< IpInstance
->GroupCount
; Index
++) {
1374 if (EFI_IP6_EQUAL (IpInstance
->GroupList
+ Index
, &Head
->DestinationAddress
)) {
1379 return (BOOLEAN
)(Index
< IpInstance
->GroupCount
);
1386 Enqueue a shared copy of the packet to the IP6 child if the
1387 packet is acceptable to it. Here the data of the packet is
1388 shared, but the net buffer isn't.
1390 @param IpInstance The IP6 child to enqueue the packet to.
1391 @param Head The IP header of the received packet.
1392 @param Packet The data of the received packet.
1394 @retval EFI_NOT_STARTED The IP child hasn't been configured.
1395 @retval EFI_INVALID_PARAMETER The child doesn't want to receive the packet.
1396 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources
1397 @retval EFI_SUCCESS A shared copy the packet is enqueued to the child.
1401 Ip6InstanceEnquePacket (
1402 IN IP6_PROTOCOL
*IpInstance
,
1403 IN EFI_IP6_HEADER
*Head
,
1407 IP6_CLIP_INFO
*Info
;
1411 // Check whether the packet is acceptable to this instance.
1413 if (IpInstance
->State
!= IP6_STATE_CONFIGED
) {
1414 return EFI_NOT_STARTED
;
1417 if (!Ip6InstanceFrameAcceptable (IpInstance
, Head
, Packet
)) {
1418 return EFI_INVALID_PARAMETER
;
1422 // Enque a shared copy of the packet.
1424 Clone
= NetbufClone (Packet
);
1426 if (Clone
== NULL
) {
1427 return EFI_OUT_OF_RESOURCES
;
1431 // Set the receive time out for the assembled packet. If it expires,
1432 // packet will be removed from the queue.
1434 Info
= IP6_GET_CLIP_INFO (Clone
);
1435 Info
->Life
= IP6_US_TO_SEC (IpInstance
->ConfigData
.ReceiveTimeout
);
1437 InsertTailList (&IpInstance
->Received
, &Clone
->List
);
1442 Deliver the received packets to the upper layer if there are both received
1443 requests and enqueued packets. If the enqueued packet is shared, it will
1444 duplicate it to a non-shared packet, release the shared packet, then
1445 deliver the non-shared packet up.
1447 @param[in] IpInstance The IP child to deliver the packet up.
1449 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to deliver the
1451 @retval EFI_SUCCESS All the enqueued packets that can be delivered
1456 Ip6InstanceDeliverPacket (
1457 IN IP6_PROTOCOL
*IpInstance
1460 EFI_IP6_COMPLETION_TOKEN
*Token
;
1461 IP6_RXDATA_WRAP
*Wrap
;
1467 // Deliver a packet if there are both a packet and a receive token.
1469 while (!IsListEmpty (&IpInstance
->Received
) && !NetMapIsEmpty (&IpInstance
->RxTokens
)) {
1471 Packet
= NET_LIST_HEAD (&IpInstance
->Received
, NET_BUF
, List
);
1473 if (!NET_BUF_SHARED (Packet
)) {
1475 // If this is the only instance that wants the packet, wrap it up.
1477 Wrap
= Ip6WrapRxData (IpInstance
, Packet
);
1480 return EFI_OUT_OF_RESOURCES
;
1483 RemoveEntryList (&Packet
->List
);
1487 // Create a duplicated packet if this packet is shared
1489 Dup
= NetbufDuplicate (Packet
, NULL
, sizeof (EFI_IP6_HEADER
));
1492 return EFI_OUT_OF_RESOURCES
;
1496 // Copy the IP head over. The packet to deliver up is
1497 // headless. Trim the head off after copy. The IP head
1498 // may be not continuous before the data.
1500 Head
= NetbufAllocSpace (Dup
, sizeof (EFI_IP6_HEADER
), NET_BUF_HEAD
);
1501 ASSERT (Head
!= NULL
);
1502 Dup
->Ip
.Ip6
= (EFI_IP6_HEADER
*) Head
;
1504 CopyMem (Head
, Packet
->Ip
.Ip6
, sizeof (EFI_IP6_HEADER
));
1505 NetbufTrim (Dup
, sizeof (EFI_IP6_HEADER
), TRUE
);
1507 Wrap
= Ip6WrapRxData (IpInstance
, Dup
);
1511 return EFI_OUT_OF_RESOURCES
;
1514 RemoveEntryList (&Packet
->List
);
1515 NetbufFree (Packet
);
1521 // Insert it into the delivered packet, then get a user's
1522 // receive token, pass the wrapped packet up.
1524 EfiAcquireLockOrFail (&IpInstance
->RecycleLock
);
1525 InsertHeadList (&IpInstance
->Delivered
, &Wrap
->Link
);
1526 EfiReleaseLock (&IpInstance
->RecycleLock
);
1528 Token
= NetMapRemoveHead (&IpInstance
->RxTokens
, NULL
);
1529 Token
->Status
= IP6_GET_CLIP_INFO (Packet
)->Status
;
1530 Token
->Packet
.RxData
= &Wrap
->RxData
;
1532 gBS
->SignalEvent (Token
->Event
);
1539 Enqueue a received packet to all the IP children that share
1542 @param[in] IpSb The IP6 service instance that receive the packet.
1543 @param[in] Head The header of the received packet.
1544 @param[in] Packet The data of the received packet.
1545 @param[in] IpIf The interface to enqueue the packet to.
1547 @return The number of the IP6 children that accepts the packet.
1551 Ip6InterfaceEnquePacket (
1552 IN IP6_SERVICE
*IpSb
,
1553 IN EFI_IP6_HEADER
*Head
,
1555 IN IP6_INTERFACE
*IpIf
1558 IP6_PROTOCOL
*IpInstance
;
1559 IP6_CLIP_INFO
*Info
;
1566 // First, check that the packet is acceptable to this interface
1567 // and find the local cast type for the interface.
1570 Info
= IP6_GET_CLIP_INFO (Packet
);
1572 if (IpIf
->PromiscRecv
) {
1573 LocalType
= Ip6Promiscuous
;
1575 LocalType
= Info
->CastType
;
1579 // Iterate through the ip instances on the interface, enqueue
1580 // the packet if filter passed. Save the original cast type,
1581 // and pass the local cast type to the IP children on the
1582 // interface. The global cast type will be restored later.
1584 SavedType
= Info
->CastType
;
1585 Info
->CastType
= (UINT32
) LocalType
;
1589 NET_LIST_FOR_EACH (Entry
, &IpIf
->IpInstances
) {
1590 IpInstance
= NET_LIST_USER_STRUCT (Entry
, IP6_PROTOCOL
, AddrLink
);
1591 NET_CHECK_SIGNATURE (IpInstance
, IP6_PROTOCOL_SIGNATURE
);
1593 if (Ip6InstanceEnquePacket (IpInstance
, Head
, Packet
) == EFI_SUCCESS
) {
1598 Info
->CastType
= (UINT32
) SavedType
;
1603 Deliver the packet for each IP6 child on the interface.
1605 @param[in] IpSb The IP6 service instance that received the packet.
1606 @param[in] IpIf The IP6 interface to deliver the packet.
1610 Ip6InterfaceDeliverPacket (
1611 IN IP6_SERVICE
*IpSb
,
1612 IN IP6_INTERFACE
*IpIf
1615 IP6_PROTOCOL
*IpInstance
;
1618 NET_LIST_FOR_EACH (Entry
, &IpIf
->IpInstances
) {
1619 IpInstance
= NET_LIST_USER_STRUCT (Entry
, IP6_PROTOCOL
, AddrLink
);
1620 Ip6InstanceDeliverPacket (IpInstance
);
1625 De-multiplex the packet. the packet delivery is processed in two
1626 passes. The first pass will enqueue a shared copy of the packet
1627 to each IP6 child that accepts the packet. The second pass will
1628 deliver a non-shared copy of the packet to each IP6 child that
1629 has pending receive requests. Data is copied if more than one
1630 child wants to consume the packet, because each IP child needs
1631 its own copy of the packet to make changes.
1633 @param[in] IpSb The IP6 service instance that received the packet.
1634 @param[in] Head The header of the received packet.
1635 @param[in] Packet The data of the received packet.
1637 @retval EFI_NOT_FOUND No IP child accepts the packet.
1638 @retval EFI_SUCCESS The packet is enqueued or delivered to some IP
1644 IN IP6_SERVICE
*IpSb
,
1645 IN EFI_IP6_HEADER
*Head
,
1651 IP6_INTERFACE
*IpIf
;
1655 // Two pass delivery: first, enque a shared copy of the packet
1656 // to each instance that accept the packet.
1660 NET_LIST_FOR_EACH (Entry
, &IpSb
->Interfaces
) {
1661 IpIf
= NET_LIST_USER_STRUCT (Entry
, IP6_INTERFACE
, Link
);
1663 if (IpIf
->Configured
) {
1664 Enqueued
+= Ip6InterfaceEnquePacket (IpSb
, Head
, Packet
, IpIf
);
1669 // Second: deliver a duplicate of the packet to each instance.
1670 // Release the local reference first, so that the last instance
1671 // getting the packet will not copy the data.
1673 NetbufFree (Packet
);
1676 if (Enqueued
== 0) {
1677 return EFI_NOT_FOUND
;
1680 NET_LIST_FOR_EACH (Entry
, &IpSb
->Interfaces
) {
1681 IpIf
= NET_LIST_USER_STRUCT (Entry
, IP6_INTERFACE
, Link
);
1683 if (IpIf
->Configured
) {
1684 Ip6InterfaceDeliverPacket (IpSb
, IpIf
);
1692 Decrease the life of the transmitted packets. If it is
1693 decreased to zero, cancel the packet. This function is
1694 called by Ip6packetTimerTicking that provides timeout for both the
1695 received-but-not-delivered and transmitted-but-not-recycle
1698 @param[in] Map The IP6 child's transmit map.
1699 @param[in] Item Current transmitted packet.
1700 @param[in] Context Not used.
1702 @retval EFI_SUCCESS Always returns EFI_SUCCESS.
1707 Ip6SentPacketTicking (
1709 IN NET_MAP_ITEM
*Item
,
1713 IP6_TXTOKEN_WRAP
*Wrap
;
1715 Wrap
= (IP6_TXTOKEN_WRAP
*) Item
->Value
;
1716 ASSERT (Wrap
!= NULL
);
1718 if ((Wrap
->Life
> 0) && (--Wrap
->Life
== 0)) {
1719 Ip6CancelPacket (Wrap
->IpInstance
->Interface
, Wrap
->Packet
, EFI_ABORTED
);
1726 Timeout the fragments, and the enqueued, and transmitted packets.
1728 @param[in] IpSb The IP6 service instance to timeout.
1732 Ip6PacketTimerTicking (
1733 IN IP6_SERVICE
*IpSb
1736 LIST_ENTRY
*InstanceEntry
;
1739 IP6_PROTOCOL
*IpInstance
;
1740 IP6_ASSEMBLE_ENTRY
*Assemble
;
1742 IP6_CLIP_INFO
*Info
;
1746 // First, time out the fragments. The packet's life is counting down
1747 // once the first-arriving fragment of that packet was received.
1749 for (Index
= 0; Index
< IP6_ASSEMLE_HASH_SIZE
; Index
++) {
1750 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &(IpSb
->Assemble
.Bucket
[Index
])) {
1751 Assemble
= NET_LIST_USER_STRUCT (Entry
, IP6_ASSEMBLE_ENTRY
, Link
);
1753 if ((Assemble
->Life
> 0) && (--Assemble
->Life
== 0)) {
1755 // If the first fragment (the one with a Fragment Offset of zero)
1756 // has been received, an ICMP Time Exceeded - Fragment Reassembly
1757 // Time Exceeded message should be sent to the source of that fragment.
1759 if ((Assemble
->Packet
!= NULL
) &&
1760 !IP6_IS_MULTICAST (&Assemble
->Head
->DestinationAddress
)) {
1765 &Assemble
->Head
->SourceAddress
,
1766 ICMP_V6_TIME_EXCEEDED
,
1767 ICMP_V6_TIMEOUT_REASSEMBLE
,
1773 // If reassembly of a packet is not completed within 60 seconds of
1774 // the reception of the first-arriving fragment of that packet, the
1775 // reassembly must be abandoned and all the fragments that have been
1776 // received for that packet must be discarded.
1778 RemoveEntryList (Entry
);
1779 Ip6FreeAssembleEntry (Assemble
);
1784 NET_LIST_FOR_EACH (InstanceEntry
, &IpSb
->Children
) {
1785 IpInstance
= NET_LIST_USER_STRUCT (InstanceEntry
, IP6_PROTOCOL
, Link
);
1788 // Second, time out the assembled packets enqueued on each IP child.
1790 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &IpInstance
->Received
) {
1791 Packet
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
1792 Info
= IP6_GET_CLIP_INFO (Packet
);
1794 if ((Info
->Life
> 0) && (--Info
->Life
== 0)) {
1795 RemoveEntryList (Entry
);
1796 NetbufFree (Packet
);
1801 // Third: time out the transmitted packets.
1803 NetMapIterate (&IpInstance
->TxTokens
, Ip6SentPacketTicking
, NULL
);