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] 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] ExtHdrs The caller-supplied options.
488 @param[in] 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 EFI_IP6_HEADER
*Head
,
506 IN OUT UINT8
*LastHead
,
507 IN OUT NET_BUF
**Netbuf
,
509 IN UINT32 ExtHdrsLen
,
510 IN EFI_IPSEC_TRAFFIC_DIR Direction
,
514 NET_FRAGMENT
*FragmentTable
;
515 UINT32 FragmentCount
;
516 EFI_EVENT RecycleEvent
;
518 IP6_TXTOKEN_WRAP
*TxWrap
;
519 IP6_IPSEC_WRAP
*IpSecWrap
;
521 EFI_IP6_HEADER
*PacketHead
;
524 Status
= EFI_SUCCESS
;
528 FragmentTable
= NULL
;
531 TxWrap
= (IP6_TXTOKEN_WRAP
*) Context
;
532 FragmentCount
= Packet
->BlockOpNum
;
534 if (mIpSec
== NULL
) {
535 gBS
->LocateProtocol (&gEfiIpSecProtocolGuid
, NULL
, (VOID
**) &mIpSec
);
538 // Check whether the ipsec protocol is available.
540 if (mIpSec
== NULL
) {
546 // Check whether the ipsec enable variable is set.
548 if (mIpSec
->DisabledFlag
) {
550 // If IPsec is disabled, restore the original MTU
552 IpSb
->MaxPacketSize
= IpSb
->OldMaxPacketSize
;
556 // If IPsec is enabled, use the MTU which reduce the IPsec header length.
558 IpSb
->MaxPacketSize
= IpSb
->OldMaxPacketSize
- IP6_MAX_IPSEC_HEADLEN
;
563 // Bypass all multicast inbound or outbound traffic.
565 if (IP6_IS_MULTICAST (&Head
->DestinationAddress
) || IP6_IS_MULTICAST (&Head
->SourceAddress
)) {
570 // Rebuild fragment table from netbuf to ease ipsec process.
572 FragmentTable
= AllocateZeroPool (FragmentCount
* sizeof (NET_FRAGMENT
));
574 if (FragmentTable
== NULL
) {
575 Status
= EFI_OUT_OF_RESOURCES
;
579 Status
= NetbufBuildExt (Packet
, FragmentTable
, &FragmentCount
);
581 if (EFI_ERROR(Status
)) {
582 FreePool (FragmentTable
);
587 // Convert host byte order to network byte order
591 Status
= mIpSec
->Process (
599 (EFI_IPSEC_FRAGMENT_DATA
**) (&FragmentTable
),
605 // Convert back to host byte order
609 if (EFI_ERROR (Status
)) {
613 if (Direction
== EfiIPsecOutBound
&& TxWrap
!= NULL
) {
615 TxWrap
->IpSecRecycleSignal
= RecycleEvent
;
616 TxWrap
->Packet
= NetbufFromExt (
624 if (TxWrap
->Packet
== NULL
) {
625 Status
= EFI_OUT_OF_RESOURCES
;
629 *Netbuf
= TxWrap
->Packet
;
633 IpSecWrap
= AllocateZeroPool (sizeof (IP6_IPSEC_WRAP
));
635 if (IpSecWrap
== NULL
) {
639 IpSecWrap
->IpSecRecycleSignal
= RecycleEvent
;
640 IpSecWrap
->Packet
= Packet
;
641 Packet
= NetbufFromExt (
650 if (Packet
== NULL
) {
651 Status
= EFI_OUT_OF_RESOURCES
;
655 if (Direction
== EfiIPsecInBound
) {
657 PacketHead
= (EFI_IP6_HEADER
*) NetbufAllocSpace (
659 sizeof (EFI_IP6_HEADER
) + ExtHdrsLen
,
662 if (PacketHead
== NULL
) {
663 Status
= EFI_OUT_OF_RESOURCES
;
667 CopyMem (PacketHead
, Head
, sizeof (EFI_IP6_HEADER
));
668 Packet
->Ip
.Ip6
= PacketHead
;
670 if (ExtHdrs
!= NULL
) {
671 Buf
= (UINT8
*) (PacketHead
+ 1);
672 CopyMem (Buf
, ExtHdrs
, ExtHdrsLen
);
675 NetbufTrim (Packet
, sizeof (EFI_IP6_HEADER
) + ExtHdrsLen
, TRUE
);
677 IP6_GET_CLIP_INFO (Packet
),
678 IP6_GET_CLIP_INFO (IpSecWrap
->Packet
),
679 sizeof (IP6_CLIP_INFO
)
691 The IP6 input routine. It is called by the IP6_INTERFACE when an
692 IP6 fragment is received from MNP.
694 @param[in] Packet The IP6 packet received.
695 @param[in] IoStatus The return status of receive request.
696 @param[in] Flag The link layer flag for the packet received, such
698 @param[in] Context The IP6 service instance that owns the MNP.
704 IN EFI_STATUS IoStatus
,
711 EFI_IP6_HEADER
*Head
;
716 UINT32 FormerHeadOffset
;
717 UINT32 UnFragmentLen
;
721 IP6_FRAGMENT_HEADER
*FragmentHead
;
722 UINT16 FragmentOffset
;
724 EFI_IPv6_ADDRESS Loopback
;
726 IpSb
= (IP6_SERVICE
*) Context
;
727 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
732 // Check input parameters
734 if (EFI_ERROR (IoStatus
) || (IpSb
->State
== IP6_SERVICE_DESTROY
)) {
739 // Check whether the input packet is a valid packet
741 if (Packet
->TotalSize
< IP6_MIN_HEADLEN
) {
746 // Get header information of the packet.
748 Head
= (EFI_IP6_HEADER
*) NetbufGetByte (Packet
, 0, NULL
);
754 // Multicast addresses must not be used as source addresses in IPv6 packets.
756 if ((Head
->Version
!= 6) || (IP6_IS_MULTICAST (&Head
->SourceAddress
))) {
761 // A packet with a destination address of loopback ::1/128 or unspecified must be dropped.
763 ZeroMem (&Loopback
, sizeof (EFI_IPv6_ADDRESS
));
764 Loopback
.Addr
[15] = 0x1;
765 if ((CompareMem (&Loopback
, &Head
->DestinationAddress
, sizeof (EFI_IPv6_ADDRESS
)) == 0) ||
766 (NetIp6IsUnspecifiedAddr (&Head
->DestinationAddress
))) {
771 // Convert the IP header to host byte order.
773 Packet
->Ip
.Ip6
= Ip6NtohHead (Head
);
776 // Get the per packet info.
778 Info
= IP6_GET_CLIP_INFO (Packet
);
779 Info
->LinkFlag
= Flag
;
782 if (IpSb
->MnpConfigData
.EnablePromiscuousReceive
) {
783 Info
->CastType
= Ip6Promiscuous
;
786 if (Ip6IsOneOfSetAddress (IpSb
, &Head
->DestinationAddress
, NULL
, NULL
)) {
787 Info
->CastType
= Ip6Unicast
;
788 } else if (IP6_IS_MULTICAST (&Head
->DestinationAddress
)) {
789 if (Ip6FindMldEntry (IpSb
, &Head
->DestinationAddress
) != NULL
) {
790 Info
->CastType
= Ip6Multicast
;
795 // Drop the packet that is not delivered to us.
797 if (Info
->CastType
== 0) {
802 PayloadLen
= Head
->PayloadLength
;
805 Info
->Length
= PayloadLen
;
806 Info
->End
= Info
->Start
+ Info
->Length
;
807 Info
->HeadLen
= (UINT16
) sizeof (EFI_IP6_HEADER
);
808 Info
->Status
= EFI_SUCCESS
;
809 Info
->LastFrag
= FALSE
;
811 TotalLen
= (UINT16
) (PayloadLen
+ sizeof (EFI_IP6_HEADER
));
814 // Mnp may deliver frame trailer sequence up, trim it off.
816 if (TotalLen
< Packet
->TotalSize
) {
817 NetbufTrim (Packet
, Packet
->TotalSize
- TotalLen
, FALSE
);
820 if (TotalLen
!= Packet
->TotalSize
) {
825 // Check the extension headers, if exist validate them
827 if (PayloadLen
!= 0) {
828 Payload
= AllocatePool ((UINTN
) PayloadLen
);
829 if (Payload
== NULL
) {
833 NetbufCopy (Packet
, sizeof (EFI_IP6_HEADER
), PayloadLen
, Payload
);
837 if (!Ip6IsExtsValid (
853 HeadLen
= sizeof (EFI_IP6_HEADER
) + UnFragmentLen
;
857 // Get the fragment offset from the Fragment header
859 FragmentHead
= (IP6_FRAGMENT_HEADER
*) NetbufGetByte (Packet
, HeadLen
, NULL
);
860 if (FragmentHead
== NULL
) {
864 FragmentOffset
= NTOHS (FragmentHead
->FragmentOffset
);
866 if ((FragmentOffset
& 0x1) == 0) {
867 Info
->LastFrag
= TRUE
;
870 FragmentOffset
&= (~0x1);
873 // This is the first fragment of the packet
875 if (FragmentOffset
== 0) {
876 Info
->NextHeader
= FragmentHead
->NextHeader
;
879 Info
->HeadLen
= (UINT16
) HeadLen
;
880 HeadLen
+= sizeof (IP6_FRAGMENT_HEADER
);
881 Info
->Start
= FragmentOffset
;
882 Info
->Length
= TotalLen
- (UINT16
) HeadLen
;
883 Info
->End
= Info
->Start
+ Info
->Length
;
884 Info
->Id
= FragmentHead
->Identification
;
885 Info
->FormerNextHeader
= FormerHeadOffset
;
888 // Fragments should in the unit of 8 octets long except the last one.
890 if ((Info
->LastFrag
== 0) && (Info
->Length
% 8 != 0)) {
895 // Reassemble the packet.
897 Packet
= Ip6Reassemble (&IpSb
->Assemble
, Packet
);
898 if (Packet
== NULL
) {
903 // Re-check the assembled packet to get the right values.
905 Head
= Packet
->Ip
.Ip6
;
906 PayloadLen
= Head
->PayloadLength
;
907 if (PayloadLen
!= 0) {
908 if (Payload
!= NULL
) {
912 Payload
= AllocatePool ((UINTN
) PayloadLen
);
913 if (Payload
== NULL
) {
917 NetbufCopy (Packet
, sizeof (EFI_IP6_HEADER
), PayloadLen
, Payload
);
920 if (!Ip6IsExtsValid (
938 // Trim the head off, after this point, the packet is headless.
939 // and Packet->TotalLen == Info->Length.
941 NetbufTrim (Packet
, sizeof (EFI_IP6_HEADER
) + ExtHdrsLen
, TRUE
);
944 // After trim off, the packet is a esp/ah/udp/tcp/icmp6 net buffer,
945 // and no need consider any other ahead ext headers.
947 Status
= Ip6IpSecProcessPacket (
950 LastHead
, // need get the lasthead value for input
958 if (EFI_ERROR(Status
)) {
963 // TODO: may check the last head again, the same as the output routine
967 // Packet may have been changed. The ownership of the packet
968 // is transfered to the packet process logic.
970 Head
= Packet
->Ip
.Ip6
;
971 IP6_GET_CLIP_INFO (Packet
)->Status
= EFI_SUCCESS
;
975 Ip6IcmpHandle (IpSb
, Head
, Packet
);
978 Ip6Demultiplex (IpSb
, Head
, Packet
);
984 // Dispatch the DPCs queued by the NotifyFunction of the rx token's events
985 // which are signaled with received data.
990 if (Payload
!= NULL
) {
994 Ip6ReceiveFrame (Ip6AcceptFrame
, IpSb
);
997 if (Packet
!= NULL
) {
1005 Initialize an already allocated assemble table. This is generally
1006 the assemble table embedded in the IP6 service instance.
1008 @param[in, out] Table The assemble table to initialize.
1012 Ip6CreateAssembleTable (
1013 IN OUT IP6_ASSEMBLE_TABLE
*Table
1018 for (Index
= 0; Index
< IP6_ASSEMLE_HASH_SIZE
; Index
++) {
1019 InitializeListHead (&Table
->Bucket
[Index
]);
1024 Clean up the assemble table by removing all of the fragments
1025 and assemble entries.
1027 @param[in, out] Table The assemble table to clean up.
1031 Ip6CleanAssembleTable (
1032 IN OUT IP6_ASSEMBLE_TABLE
*Table
1037 IP6_ASSEMBLE_ENTRY
*Assemble
;
1040 for (Index
= 0; Index
< IP6_ASSEMLE_HASH_SIZE
; Index
++) {
1041 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &Table
->Bucket
[Index
]) {
1042 Assemble
= NET_LIST_USER_STRUCT (Entry
, IP6_ASSEMBLE_ENTRY
, Link
);
1044 RemoveEntryList (Entry
);
1045 Ip6FreeAssembleEntry (Assemble
);
1052 The signal handle of IP6's recycle event. It is called back
1053 when the upper layer releases the packet.
1055 @param[in] Event The IP6's recycle event.
1056 @param[in] Context The context of the handle, which is a IP6_RXDATA_WRAP.
1061 Ip6OnRecyclePacket (
1066 IP6_RXDATA_WRAP
*Wrap
;
1068 Wrap
= (IP6_RXDATA_WRAP
*) Context
;
1070 EfiAcquireLockOrFail (&Wrap
->IpInstance
->RecycleLock
);
1071 RemoveEntryList (&Wrap
->Link
);
1072 EfiReleaseLock (&Wrap
->IpInstance
->RecycleLock
);
1074 ASSERT (!NET_BUF_SHARED (Wrap
->Packet
));
1075 NetbufFree (Wrap
->Packet
);
1077 gBS
->CloseEvent (Wrap
->RxData
.RecycleSignal
);
1082 Wrap the received packet to a IP6_RXDATA_WRAP, which will be
1083 delivered to the upper layer. Each IP6 child that accepts the
1084 packet will get a not-shared copy of the packet which is wrapped
1085 in the IP6_RXDATA_WRAP. The IP6_RXDATA_WRAP->RxData is passed
1086 to the upper layer. The upper layer will signal the recycle event in
1087 it when it is done with the packet.
1089 @param[in] IpInstance The IP6 child to receive the packet.
1090 @param[in] Packet The packet to deliver up.
1092 @return NULL if it failed to wrap the packet; otherwise, the wrapper.
1097 IN IP6_PROTOCOL
*IpInstance
,
1101 IP6_RXDATA_WRAP
*Wrap
;
1102 EFI_IP6_RECEIVE_DATA
*RxData
;
1105 Wrap
= AllocatePool (IP6_RXDATA_WRAP_SIZE (Packet
->BlockOpNum
));
1111 InitializeListHead (&Wrap
->Link
);
1113 Wrap
->IpInstance
= IpInstance
;
1114 Wrap
->Packet
= Packet
;
1115 RxData
= &Wrap
->RxData
;
1117 ZeroMem (&RxData
->TimeStamp
, sizeof (EFI_TIME
));
1119 Status
= gBS
->CreateEvent (
1124 &RxData
->RecycleSignal
1127 if (EFI_ERROR (Status
)) {
1132 ASSERT (Packet
->Ip
.Ip6
!= NULL
);
1135 // The application expects a network byte order header.
1137 RxData
->HeaderLength
= sizeof (EFI_IP6_HEADER
);
1138 RxData
->Header
= (EFI_IP6_HEADER
*) Ip6NtohHead (Packet
->Ip
.Ip6
);
1139 RxData
->DataLength
= Packet
->TotalSize
;
1142 // Build the fragment table to be delivered up.
1144 RxData
->FragmentCount
= Packet
->BlockOpNum
;
1145 NetbufBuildExt (Packet
, (NET_FRAGMENT
*) RxData
->FragmentTable
, &RxData
->FragmentCount
);
1151 Check whether this IP child accepts the packet.
1153 @param[in] IpInstance The IP child to check.
1154 @param[in] Head The IP header of the packet.
1155 @param[in] Packet The data of the packet.
1157 @retval TRUE The child wants to receive the packet.
1158 @retval FALSE The child does not want to receive the packet.
1162 Ip6InstanceFrameAcceptable (
1163 IN IP6_PROTOCOL
*IpInstance
,
1164 IN EFI_IP6_HEADER
*Head
,
1168 IP6_ICMP_ERROR_HEAD Icmp
;
1169 EFI_IP6_CONFIG_DATA
*Config
;
1170 IP6_CLIP_INFO
*Info
;
1174 UINT16 ErrMsgPayloadLen
;
1175 UINT8
*ErrMsgPayload
;
1177 Config
= &IpInstance
->ConfigData
;
1181 // Dirty trick for the Tiano UEFI network stack implmentation. If
1182 // ReceiveTimeout == -1, the receive of the packet for this instance
1183 // is disabled. The UEFI spec don't have such captibility. We add
1184 // this to improve the performance because IP will make a copy of
1185 // the received packet for each accepting instance. Some IP instances
1186 // used by UDP/TCP only send packets, they don't wants to receive.
1188 if (Config
->ReceiveTimeout
== (UINT32
)(-1)) {
1192 if (Config
->AcceptPromiscuous
) {
1197 // Check whether the protocol is acceptable.
1199 ExtHdrs
= NetbufGetByte (Packet
, 0, NULL
);
1201 if (!Ip6IsExtsValid (
1202 IpInstance
->Service
,
1206 (UINT32
) Head
->PayloadLength
,
1218 // The upper layer driver may want to receive the ICMPv6 error packet
1219 // invoked by its packet, like UDP.
1221 if ((*Proto
== IP6_ICMP
) && (!Config
->AcceptAnyProtocol
) && (*Proto
!= Config
->DefaultProtocol
)) {
1222 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*) &Icmp
);
1224 if (Icmp
.Head
.Type
<= ICMP_V6_ERROR_MAX
) {
1225 if (!Config
->AcceptIcmpErrors
) {
1230 // Get the protocol of the invoking packet of ICMPv6 error packet.
1232 ErrMsgPayloadLen
= NTOHS (Icmp
.IpHead
.PayloadLength
);
1233 ErrMsgPayload
= NetbufGetByte (Packet
, sizeof (Icmp
), NULL
);
1235 if (!Ip6IsExtsValid (
1238 &Icmp
.IpHead
.NextHeader
,
1254 // Match the protocol
1256 if (!Config
->AcceptAnyProtocol
&& (*Proto
!= Config
->DefaultProtocol
)) {
1261 // Check for broadcast, the caller has computed the packet's
1262 // cast type for this child's interface.
1264 Info
= IP6_GET_CLIP_INFO (Packet
);
1267 // If it is a multicast packet, check whether we are in the group.
1269 if (Info
->CastType
== Ip6Multicast
) {
1271 // Receive the multicast if the instance wants to receive all packets.
1273 if (NetIp6IsUnspecifiedAddr (&IpInstance
->ConfigData
.StationAddress
)) {
1277 for (Index
= 0; Index
< IpInstance
->GroupCount
; Index
++) {
1278 if (EFI_IP6_EQUAL (IpInstance
->GroupList
+ Index
, &Head
->DestinationAddress
)) {
1283 return (BOOLEAN
)(Index
< IpInstance
->GroupCount
);
1290 Enqueue a shared copy of the packet to the IP6 child if the
1291 packet is acceptable to it. Here the data of the packet is
1292 shared, but the net buffer isn't.
1294 @param IpInstance The IP6 child to enqueue the packet to.
1295 @param Head The IP header of the received packet.
1296 @param Packet The data of the received packet.
1298 @retval EFI_NOT_STARTED The IP child hasn't been configured.
1299 @retval EFI_INVALID_PARAMETER The child doesn't want to receive the packet.
1300 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources
1301 @retval EFI_SUCCESS A shared copy the packet is enqueued to the child.
1305 Ip6InstanceEnquePacket (
1306 IN IP6_PROTOCOL
*IpInstance
,
1307 IN EFI_IP6_HEADER
*Head
,
1311 IP6_CLIP_INFO
*Info
;
1315 // Check whether the packet is acceptable to this instance.
1317 if (IpInstance
->State
!= IP6_STATE_CONFIGED
) {
1318 return EFI_NOT_STARTED
;
1321 if (!Ip6InstanceFrameAcceptable (IpInstance
, Head
, Packet
)) {
1322 return EFI_INVALID_PARAMETER
;
1326 // Enque a shared copy of the packet.
1328 Clone
= NetbufClone (Packet
);
1330 if (Clone
== NULL
) {
1331 return EFI_OUT_OF_RESOURCES
;
1335 // Set the receive time out for the assembled packet. If it expires,
1336 // packet will be removed from the queue.
1338 Info
= IP6_GET_CLIP_INFO (Clone
);
1339 Info
->Life
= IP6_US_TO_SEC (IpInstance
->ConfigData
.ReceiveTimeout
);
1341 InsertTailList (&IpInstance
->Received
, &Clone
->List
);
1346 Deliver the received packets to the upper layer if there are both received
1347 requests and enqueued packets. If the enqueued packet is shared, it will
1348 duplicate it to a non-shared packet, release the shared packet, then
1349 deliver the non-shared packet up.
1351 @param[in] IpInstance The IP child to deliver the packet up.
1353 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to deliver the
1355 @retval EFI_SUCCESS All the enqueued packets that can be delivered
1360 Ip6InstanceDeliverPacket (
1361 IN IP6_PROTOCOL
*IpInstance
1364 EFI_IP6_COMPLETION_TOKEN
*Token
;
1365 IP6_RXDATA_WRAP
*Wrap
;
1371 // Deliver a packet if there are both a packet and a receive token.
1373 while (!IsListEmpty (&IpInstance
->Received
) && !NetMapIsEmpty (&IpInstance
->RxTokens
)) {
1375 Packet
= NET_LIST_HEAD (&IpInstance
->Received
, NET_BUF
, List
);
1377 if (!NET_BUF_SHARED (Packet
)) {
1379 // If this is the only instance that wants the packet, wrap it up.
1381 Wrap
= Ip6WrapRxData (IpInstance
, Packet
);
1384 return EFI_OUT_OF_RESOURCES
;
1387 RemoveEntryList (&Packet
->List
);
1391 // Create a duplicated packet if this packet is shared
1393 Dup
= NetbufDuplicate (Packet
, NULL
, sizeof (EFI_IP6_HEADER
));
1396 return EFI_OUT_OF_RESOURCES
;
1400 // Copy the IP head over. The packet to deliver up is
1401 // headless. Trim the head off after copy. The IP head
1402 // may be not continuous before the data.
1404 Head
= NetbufAllocSpace (Dup
, sizeof (EFI_IP6_HEADER
), NET_BUF_HEAD
);
1405 ASSERT (Head
!= NULL
);
1406 Dup
->Ip
.Ip6
= (EFI_IP6_HEADER
*) Head
;
1408 CopyMem (Head
, Packet
->Ip
.Ip6
, sizeof (EFI_IP6_HEADER
));
1409 NetbufTrim (Dup
, sizeof (EFI_IP6_HEADER
), TRUE
);
1411 Wrap
= Ip6WrapRxData (IpInstance
, Dup
);
1415 return EFI_OUT_OF_RESOURCES
;
1418 RemoveEntryList (&Packet
->List
);
1419 NetbufFree (Packet
);
1425 // Insert it into the delivered packet, then get a user's
1426 // receive token, pass the wrapped packet up.
1428 EfiAcquireLockOrFail (&IpInstance
->RecycleLock
);
1429 InsertHeadList (&IpInstance
->Delivered
, &Wrap
->Link
);
1430 EfiReleaseLock (&IpInstance
->RecycleLock
);
1432 Token
= NetMapRemoveHead (&IpInstance
->RxTokens
, NULL
);
1433 Token
->Status
= IP6_GET_CLIP_INFO (Packet
)->Status
;
1434 Token
->Packet
.RxData
= &Wrap
->RxData
;
1436 gBS
->SignalEvent (Token
->Event
);
1443 Enqueue a received packet to all the IP children that share
1446 @param[in] IpSb The IP6 service instance that receive the packet.
1447 @param[in] Head The header of the received packet.
1448 @param[in] Packet The data of the received packet.
1449 @param[in] IpIf The interface to enqueue the packet to.
1451 @return The number of the IP6 children that accepts the packet.
1455 Ip6InterfaceEnquePacket (
1456 IN IP6_SERVICE
*IpSb
,
1457 IN EFI_IP6_HEADER
*Head
,
1459 IN IP6_INTERFACE
*IpIf
1462 IP6_PROTOCOL
*IpInstance
;
1463 IP6_CLIP_INFO
*Info
;
1470 // First, check that the packet is acceptable to this interface
1471 // and find the local cast type for the interface.
1474 Info
= IP6_GET_CLIP_INFO (Packet
);
1476 if (IpIf
->PromiscRecv
) {
1477 LocalType
= Ip6Promiscuous
;
1479 LocalType
= Info
->CastType
;
1483 // Iterate through the ip instances on the interface, enqueue
1484 // the packet if filter passed. Save the original cast type,
1485 // and pass the local cast type to the IP children on the
1486 // interface. The global cast type will be restored later.
1488 SavedType
= Info
->CastType
;
1489 Info
->CastType
= (UINT32
) LocalType
;
1493 NET_LIST_FOR_EACH (Entry
, &IpIf
->IpInstances
) {
1494 IpInstance
= NET_LIST_USER_STRUCT (Entry
, IP6_PROTOCOL
, AddrLink
);
1495 NET_CHECK_SIGNATURE (IpInstance
, IP6_PROTOCOL_SIGNATURE
);
1497 if (Ip6InstanceEnquePacket (IpInstance
, Head
, Packet
) == EFI_SUCCESS
) {
1502 Info
->CastType
= (UINT32
) SavedType
;
1507 Deliver the packet for each IP6 child on the interface.
1509 @param[in] IpSb The IP6 service instance that received the packet.
1510 @param[in] IpIf The IP6 interface to deliver the packet.
1514 Ip6InterfaceDeliverPacket (
1515 IN IP6_SERVICE
*IpSb
,
1516 IN IP6_INTERFACE
*IpIf
1519 IP6_PROTOCOL
*IpInstance
;
1522 NET_LIST_FOR_EACH (Entry
, &IpIf
->IpInstances
) {
1523 IpInstance
= NET_LIST_USER_STRUCT (Entry
, IP6_PROTOCOL
, AddrLink
);
1524 Ip6InstanceDeliverPacket (IpInstance
);
1529 De-multiplex the packet. the packet delivery is processed in two
1530 passes. The first pass will enqueue a shared copy of the packet
1531 to each IP6 child that accepts the packet. The second pass will
1532 deliver a non-shared copy of the packet to each IP6 child that
1533 has pending receive requests. Data is copied if more than one
1534 child wants to consume the packet, because each IP child needs
1535 its own copy of the packet to make changes.
1537 @param[in] IpSb The IP6 service instance that received the packet.
1538 @param[in] Head The header of the received packet.
1539 @param[in] Packet The data of the received packet.
1541 @retval EFI_NOT_FOUND No IP child accepts the packet.
1542 @retval EFI_SUCCESS The packet is enqueued or delivered to some IP
1548 IN IP6_SERVICE
*IpSb
,
1549 IN EFI_IP6_HEADER
*Head
,
1555 IP6_INTERFACE
*IpIf
;
1559 // Two pass delivery: first, enque a shared copy of the packet
1560 // to each instance that accept the packet.
1564 NET_LIST_FOR_EACH (Entry
, &IpSb
->Interfaces
) {
1565 IpIf
= NET_LIST_USER_STRUCT (Entry
, IP6_INTERFACE
, Link
);
1567 if (IpIf
->Configured
) {
1568 Enqueued
+= Ip6InterfaceEnquePacket (IpSb
, Head
, Packet
, IpIf
);
1573 // Second: deliver a duplicate of the packet to each instance.
1574 // Release the local reference first, so that the last instance
1575 // getting the packet will not copy the data.
1577 NetbufFree (Packet
);
1580 if (Enqueued
== 0) {
1581 return EFI_NOT_FOUND
;
1584 NET_LIST_FOR_EACH (Entry
, &IpSb
->Interfaces
) {
1585 IpIf
= NET_LIST_USER_STRUCT (Entry
, IP6_INTERFACE
, Link
);
1587 if (IpIf
->Configured
) {
1588 Ip6InterfaceDeliverPacket (IpSb
, IpIf
);
1596 Decrease the life of the transmitted packets. If it is
1597 decreased to zero, cancel the packet. This function is
1598 called by Ip6packetTimerTicking that provides timeout for both the
1599 received-but-not-delivered and transmitted-but-not-recycle
1602 @param[in] Map The IP6 child's transmit map.
1603 @param[in] Item Current transmitted packet.
1604 @param[in] Context Not used.
1606 @retval EFI_SUCCESS Always returns EFI_SUCCESS.
1611 Ip6SentPacketTicking (
1613 IN NET_MAP_ITEM
*Item
,
1617 IP6_TXTOKEN_WRAP
*Wrap
;
1619 Wrap
= (IP6_TXTOKEN_WRAP
*) Item
->Value
;
1620 ASSERT (Wrap
!= NULL
);
1622 if ((Wrap
->Life
> 0) && (--Wrap
->Life
== 0)) {
1623 Ip6CancelPacket (Wrap
->IpInstance
->Interface
, Wrap
->Packet
, EFI_ABORTED
);
1630 Timeout the fragments, and the enqueued, and transmitted packets.
1632 @param[in] IpSb The IP6 service instance to timeout.
1636 Ip6PacketTimerTicking (
1637 IN IP6_SERVICE
*IpSb
1640 LIST_ENTRY
*InstanceEntry
;
1643 IP6_PROTOCOL
*IpInstance
;
1644 IP6_ASSEMBLE_ENTRY
*Assemble
;
1646 IP6_CLIP_INFO
*Info
;
1650 // First, time out the fragments. The packet's life is counting down
1651 // once the first-arriving fragment of that packet was received.
1653 for (Index
= 0; Index
< IP6_ASSEMLE_HASH_SIZE
; Index
++) {
1654 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &(IpSb
->Assemble
.Bucket
[Index
])) {
1655 Assemble
= NET_LIST_USER_STRUCT (Entry
, IP6_ASSEMBLE_ENTRY
, Link
);
1657 if ((Assemble
->Life
> 0) && (--Assemble
->Life
== 0)) {
1659 // If the first fragment (the one with a Fragment Offset of zero)
1660 // has been received, an ICMP Time Exceeded - Fragment Reassembly
1661 // Time Exceeded message should be sent to the source of that fragment.
1663 if ((Assemble
->Packet
!= NULL
) &&
1664 !IP6_IS_MULTICAST (&Assemble
->Head
->DestinationAddress
)) {
1669 &Assemble
->Head
->SourceAddress
,
1670 ICMP_V6_TIME_EXCEEDED
,
1671 ICMP_V6_TIMEOUT_REASSEMBLE
,
1677 // If reassembly of a packet is not completed within 60 seconds of
1678 // the reception of the first-arriving fragment of that packet, the
1679 // reassembly must be abandoned and all the fragments that have been
1680 // received for that packet must be discarded.
1682 RemoveEntryList (Entry
);
1683 Ip6FreeAssembleEntry (Assemble
);
1688 NET_LIST_FOR_EACH (InstanceEntry
, &IpSb
->Children
) {
1689 IpInstance
= NET_LIST_USER_STRUCT (InstanceEntry
, IP6_PROTOCOL
, Link
);
1692 // Second, time out the assembled packets enqueued on each IP child.
1694 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &IpInstance
->Received
) {
1695 Packet
= NET_LIST_USER_STRUCT (Entry
, NET_BUF
, List
);
1696 Info
= IP6_GET_CLIP_INFO (Packet
);
1698 if ((Info
->Life
> 0) && (--Info
->Life
== 0)) {
1699 RemoveEntryList (Entry
);
1700 NetbufFree (Packet
);
1705 // Third: time out the transmitted packets.
1707 NetMapIterate (&IpInstance
->TxTokens
, Ip6SentPacketTicking
, NULL
);