1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813 |
- /** @file
- IP6 internal functions to process the incoming packets.
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "Ip6Impl.h"
- /**
- Create an empty assemble entry for the packet identified by
- (Dst, Src, Id). The default life for the packet is 60 seconds.
- @param[in] Dst The destination address.
- @param[in] Src The source address.
- @param[in] Id The ID field in the IP header.
- @return NULL if failed to allocate memory for the entry. Otherwise,
- the pointer to the just created reassemble entry.
- **/
- IP6_ASSEMBLE_ENTRY *
- Ip6CreateAssembleEntry (
- IN EFI_IPv6_ADDRESS *Dst,
- IN EFI_IPv6_ADDRESS *Src,
- IN UINT32 Id
- )
- {
- IP6_ASSEMBLE_ENTRY *Assemble;
- Assemble = AllocatePool (sizeof (IP6_ASSEMBLE_ENTRY));
- if (Assemble == NULL) {
- return NULL;
- }
- IP6_COPY_ADDRESS (&Assemble->Dst, Dst);
- IP6_COPY_ADDRESS (&Assemble->Src, Src);
- InitializeListHead (&Assemble->Fragments);
- Assemble->Id = Id;
- Assemble->Life = IP6_FRAGMENT_LIFE + 1;
- Assemble->TotalLen = 0;
- Assemble->CurLen = 0;
- Assemble->Head = NULL;
- Assemble->Info = NULL;
- Assemble->Packet = NULL;
- return Assemble;
- }
- /**
- Release all the fragments of a packet, then free the assemble entry.
- @param[in] Assemble The assemble entry to free.
- **/
- VOID
- Ip6FreeAssembleEntry (
- IN IP6_ASSEMBLE_ENTRY *Assemble
- )
- {
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- NET_BUF *Fragment;
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &Assemble->Fragments) {
- Fragment = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
- RemoveEntryList (Entry);
- NetbufFree (Fragment);
- }
- if (Assemble->Packet != NULL) {
- NetbufFree (Assemble->Packet);
- }
- FreePool (Assemble);
- }
- /**
- Release all the fragments of the packet. This is the callback for
- the assembled packet's OnFree. It will free the assemble entry,
- which in turn frees all the fragments of the packet.
- @param[in] Arg The assemble entry to free.
- **/
- VOID
- EFIAPI
- Ip6OnFreeFragments (
- IN VOID *Arg
- )
- {
- Ip6FreeAssembleEntry ((IP6_ASSEMBLE_ENTRY *)Arg);
- }
- /**
- Trim the packet to fit in [Start, End), and update per the
- packet information.
- @param[in, out] Packet Packet to trim.
- @param[in] Start The sequence of the first byte to fit in.
- @param[in] End One beyond the sequence of last byte to fit in.
- **/
- VOID
- Ip6TrimPacket (
- IN OUT NET_BUF *Packet,
- IN INTN Start,
- IN INTN End
- )
- {
- IP6_CLIP_INFO *Info;
- INTN Len;
- Info = IP6_GET_CLIP_INFO (Packet);
- ASSERT (Info->Start + Info->Length == Info->End);
- ASSERT ((Info->Start < End) && (Start < Info->End));
- if (Info->Start < Start) {
- Len = Start - Info->Start;
- NetbufTrim (Packet, (UINT32)Len, NET_BUF_HEAD);
- Info->Start = (UINT32)Start;
- Info->Length -= (UINT32)Len;
- }
- if (End < Info->End) {
- Len = End - Info->End;
- NetbufTrim (Packet, (UINT32)Len, NET_BUF_TAIL);
- Info->End = (UINT32)End;
- Info->Length -= (UINT32)Len;
- }
- }
- /**
- Reassemble the IP fragments. If all the fragments of the packet
- have been received, it will wrap the packet in a net buffer then
- return it to caller. If the packet can't be assembled, NULL is
- returned.
- @param[in, out] Table The assemble table used. A new assemble entry will be created
- if the Packet is from a new chain of fragments.
- @param[in] Packet The fragment to assemble. It might be freed if the fragment
- can't be re-assembled.
- @return NULL if the packet can't be reassembled. The pointer to the just assembled
- packet if all the fragments of the packet have arrived.
- **/
- NET_BUF *
- Ip6Reassemble (
- IN OUT IP6_ASSEMBLE_TABLE *Table,
- IN NET_BUF *Packet
- )
- {
- EFI_IP6_HEADER *Head;
- IP6_CLIP_INFO *This;
- IP6_CLIP_INFO *Node;
- IP6_ASSEMBLE_ENTRY *Assemble;
- IP6_ASSEMBLE_ENTRY *Entry;
- LIST_ENTRY *ListHead;
- LIST_ENTRY *Prev;
- LIST_ENTRY *Cur;
- NET_BUF *Fragment;
- NET_BUF *TmpPacket;
- NET_BUF *NewPacket;
- NET_BUF *Duplicate;
- UINT8 *DupHead;
- INTN Index;
- UINT16 UnFragmentLen;
- UINT8 *NextHeader;
- Head = Packet->Ip.Ip6;
- This = IP6_GET_CLIP_INFO (Packet);
- ASSERT (Head != NULL);
- //
- // Find the corresponding assemble entry by (Dst, Src, Id)
- //
- Assemble = NULL;
- Index = IP6_ASSEMBLE_HASH (&Head->DestinationAddress, &Head->SourceAddress, This->Id);
- NET_LIST_FOR_EACH (Cur, &Table->Bucket[Index]) {
- Entry = NET_LIST_USER_STRUCT (Cur, IP6_ASSEMBLE_ENTRY, Link);
- if ((Entry->Id == This->Id) &&
- EFI_IP6_EQUAL (&Entry->Src, &Head->SourceAddress) &&
- EFI_IP6_EQUAL (&Entry->Dst, &Head->DestinationAddress)
- )
- {
- Assemble = Entry;
- break;
- }
- }
- //
- // Create a new entry if can not find an existing one, insert it to assemble table
- //
- if (Assemble == NULL) {
- Assemble = Ip6CreateAssembleEntry (
- &Head->DestinationAddress,
- &Head->SourceAddress,
- This->Id
- );
- if (Assemble == NULL) {
- goto Error;
- }
- InsertHeadList (&Table->Bucket[Index], &Assemble->Link);
- }
- //
- // Find the point to insert the packet: before the first
- // fragment with THIS.Start < CUR.Start. the previous one
- // has PREV.Start <= THIS.Start < CUR.Start.
- //
- ListHead = &Assemble->Fragments;
- NET_LIST_FOR_EACH (Cur, ListHead) {
- Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
- if (This->Start < IP6_GET_CLIP_INFO (Fragment)->Start) {
- break;
- }
- }
- //
- // Check whether the current fragment overlaps with the previous one.
- // It holds that: PREV.Start <= THIS.Start < THIS.End. Only need to
- // check whether THIS.Start < PREV.End for overlap. If two fragments
- // overlaps, trim the overlapped part off THIS fragment.
- //
- if ((Prev = Cur->BackLink) != ListHead) {
- Fragment = NET_LIST_USER_STRUCT (Prev, NET_BUF, List);
- Node = IP6_GET_CLIP_INFO (Fragment);
- if (This->Start < Node->End) {
- if (This->End <= Node->End) {
- goto Error;
- }
- //
- // Trim the previous fragment from tail.
- //
- Ip6TrimPacket (Fragment, Node->Start, This->Start);
- }
- }
- //
- // Insert the fragment into the packet. The fragment may be removed
- // from the list by the following checks.
- //
- NetListInsertBefore (Cur, &Packet->List);
- //
- // Check the packets after the insert point. It holds that:
- // THIS.Start <= NODE.Start < NODE.End. The equality holds
- // if PREV and NEXT are continuous. THIS fragment may fill
- // several holes. Remove the completely overlapped fragments
- //
- while (Cur != ListHead) {
- Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
- Node = IP6_GET_CLIP_INFO (Fragment);
- //
- // Remove fragments completely overlapped by this fragment
- //
- if (Node->End <= This->End) {
- Cur = Cur->ForwardLink;
- RemoveEntryList (&Fragment->List);
- Assemble->CurLen -= Node->Length;
- NetbufFree (Fragment);
- continue;
- }
- //
- // The conditions are: THIS.Start <= NODE.Start, and THIS.End <
- // NODE.End. Two fragments overlaps if NODE.Start < THIS.End.
- // If two fragments start at the same offset, remove THIS fragment
- // because ((THIS.Start == NODE.Start) && (THIS.End < NODE.End)).
- //
- if (Node->Start < This->End) {
- if (This->Start == Node->Start) {
- RemoveEntryList (&Packet->List);
- goto Error;
- }
- Ip6TrimPacket (Packet, This->Start, Node->Start);
- }
- break;
- }
- //
- // Update the assemble info: increase the current length. If it is
- // the frist fragment, update the packet's IP head and per packet
- // info. If it is the last fragment, update the total length.
- //
- Assemble->CurLen += This->Length;
- if (This->Start == 0) {
- //
- // Once the first fragment is enqueued, it can't be removed
- // from the fragment list. So, Assemble->Head always point
- // to valid memory area.
- //
- if ((Assemble->Head != NULL) || (Assemble->Packet != NULL)) {
- goto Error;
- }
- //
- // Backup the first fragment in case the reassembly of that packet fail.
- //
- Duplicate = NetbufDuplicate (Packet, NULL, sizeof (EFI_IP6_HEADER));
- if (Duplicate == NULL) {
- goto Error;
- }
- //
- // Revert IP head to network order.
- //
- DupHead = NetbufGetByte (Duplicate, 0, NULL);
- ASSERT (DupHead != NULL);
- Duplicate->Ip.Ip6 = Ip6NtohHead ((EFI_IP6_HEADER *)DupHead);
- Assemble->Packet = Duplicate;
- //
- // Adjust the unfragmentable part in first fragment
- //
- UnFragmentLen = (UINT16)(This->HeadLen - sizeof (EFI_IP6_HEADER));
- if (UnFragmentLen == 0) {
- //
- // There is not any unfragmentable extension header.
- //
- ASSERT (Head->NextHeader == IP6_FRAGMENT);
- Head->NextHeader = This->NextHeader;
- } else {
- NextHeader = NetbufGetByte (
- Packet,
- This->FormerNextHeader + sizeof (EFI_IP6_HEADER),
- 0
- );
- if (NextHeader == NULL) {
- goto Error;
- }
- *NextHeader = This->NextHeader;
- }
- Assemble->Head = Head;
- Assemble->Info = IP6_GET_CLIP_INFO (Packet);
- }
- //
- // Don't update the length more than once.
- //
- if ((This->LastFrag != 0) && (Assemble->TotalLen == 0)) {
- Assemble->TotalLen = This->End;
- }
- //
- // Deliver the whole packet if all the fragments received.
- // All fragments received if:
- // 1. received the last one, so, the total length is known
- // 2. received all the data. If the last fragment on the
- // queue ends at the total length, all data is received.
- //
- if ((Assemble->TotalLen != 0) && (Assemble->CurLen >= Assemble->TotalLen)) {
- RemoveEntryList (&Assemble->Link);
- //
- // If the packet is properly formatted, the last fragment's End
- // equals to the packet's total length. Otherwise, the packet
- // is a fake, drop it now.
- //
- Fragment = NET_LIST_USER_STRUCT (ListHead->BackLink, NET_BUF, List);
- if (IP6_GET_CLIP_INFO (Fragment)->End != (INTN)Assemble->TotalLen) {
- Ip6FreeAssembleEntry (Assemble);
- goto Error;
- }
- Fragment = NET_LIST_HEAD (ListHead, NET_BUF, List);
- This = Assemble->Info;
- //
- // This TmpPacket is used to hold the unfragmentable part, i.e.,
- // the IPv6 header and the unfragmentable extension headers. Be noted that
- // the Fragment Header is excluded.
- //
- TmpPacket = NetbufGetFragment (Fragment, 0, This->HeadLen, 0);
- ASSERT (TmpPacket != NULL);
- NET_LIST_FOR_EACH (Cur, ListHead) {
- //
- // Trim off the unfragment part plus the fragment header from all fragments.
- //
- Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
- NetbufTrim (Fragment, This->HeadLen + sizeof (IP6_FRAGMENT_HEADER), TRUE);
- }
- InsertHeadList (ListHead, &TmpPacket->List);
- //
- // Wrap the packet in a net buffer then deliver it up
- //
- NewPacket = NetbufFromBufList (
- &Assemble->Fragments,
- 0,
- 0,
- Ip6OnFreeFragments,
- Assemble
- );
- if (NewPacket == NULL) {
- Ip6FreeAssembleEntry (Assemble);
- goto Error;
- }
- NewPacket->Ip.Ip6 = Assemble->Head;
- CopyMem (IP6_GET_CLIP_INFO (NewPacket), Assemble->Info, sizeof (IP6_CLIP_INFO));
- return NewPacket;
- }
- return NULL;
- Error:
- NetbufFree (Packet);
- return NULL;
- }
- /**
- The callback function for the net buffer that wraps the packet processed by
- IPsec. It releases the wrap packet and also signals IPsec to free the resources.
- @param[in] Arg The wrap context.
- **/
- VOID
- EFIAPI
- Ip6IpSecFree (
- IN VOID *Arg
- )
- {
- IP6_IPSEC_WRAP *Wrap;
- Wrap = (IP6_IPSEC_WRAP *)Arg;
- if (Wrap->IpSecRecycleSignal != NULL) {
- gBS->SignalEvent (Wrap->IpSecRecycleSignal);
- }
- NetbufFree (Wrap->Packet);
- FreePool (Wrap);
- return;
- }
- /**
- The work function to locate the IPsec protocol to process the inbound or
- outbound IP packets. The process routine handles the packet with the following
- actions: bypass the packet, discard the packet, or protect the packet.
- @param[in] IpSb The IP6 service instance.
- @param[in, out] Head The caller-supplied IP6 header.
- @param[in, out] LastHead The next header field of last IP header.
- @param[in, out] Netbuf The IP6 packet to be processed by IPsec.
- @param[in, out] ExtHdrs The caller-supplied options.
- @param[in, out] ExtHdrsLen The length of the option.
- @param[in] Direction The directionality in an SPD entry,
- EfiIPsecInBound, or EfiIPsecOutBound.
- @param[in] Context The token's wrap.
- @retval EFI_SUCCESS The IPsec protocol is not available or disabled.
- @retval EFI_SUCCESS The packet was bypassed, and all buffers remain the same.
- @retval EFI_SUCCESS The packet was protected.
- @retval EFI_ACCESS_DENIED The packet was discarded.
- @retval EFI_OUT_OF_RESOURCES There are not sufficient resources to complete the operation.
- @retval EFI_BUFFER_TOO_SMALL The number of non-empty blocks is bigger than the
- number of input data blocks when building a fragment table.
- **/
- EFI_STATUS
- Ip6IpSecProcessPacket (
- IN IP6_SERVICE *IpSb,
- IN OUT EFI_IP6_HEADER **Head,
- IN OUT UINT8 *LastHead,
- IN OUT NET_BUF **Netbuf,
- IN OUT UINT8 **ExtHdrs,
- IN OUT UINT32 *ExtHdrsLen,
- IN EFI_IPSEC_TRAFFIC_DIR Direction,
- IN VOID *Context
- )
- {
- NET_FRAGMENT *FragmentTable;
- NET_FRAGMENT *OriginalFragmentTable;
- UINT32 FragmentCount;
- UINT32 OriginalFragmentCount;
- EFI_EVENT RecycleEvent;
- NET_BUF *Packet;
- IP6_TXTOKEN_WRAP *TxWrap;
- IP6_IPSEC_WRAP *IpSecWrap;
- EFI_STATUS Status;
- EFI_IP6_HEADER *PacketHead;
- UINT8 *Buf;
- EFI_IP6_HEADER ZeroHead;
- Status = EFI_SUCCESS;
- if (!mIpSec2Installed) {
- goto ON_EXIT;
- }
- ASSERT (mIpSec != NULL);
- Packet = *Netbuf;
- RecycleEvent = NULL;
- IpSecWrap = NULL;
- FragmentTable = NULL;
- PacketHead = NULL;
- Buf = NULL;
- TxWrap = (IP6_TXTOKEN_WRAP *)Context;
- FragmentCount = Packet->BlockOpNum;
- ZeroMem (&ZeroHead, sizeof (EFI_IP6_HEADER));
- //
- // Check whether the ipsec enable variable is set.
- //
- if (mIpSec->DisabledFlag) {
- //
- // If IPsec is disabled, restore the original MTU
- //
- IpSb->MaxPacketSize = IpSb->OldMaxPacketSize;
- goto ON_EXIT;
- } else {
- //
- // If IPsec is enabled, use the MTU which reduce the IPsec header length.
- //
- IpSb->MaxPacketSize = IpSb->OldMaxPacketSize - IP6_MAX_IPSEC_HEADLEN;
- }
- //
- // Bypass all multicast inbound or outbound traffic.
- //
- if (IP6_IS_MULTICAST (&(*Head)->DestinationAddress) || IP6_IS_MULTICAST (&(*Head)->SourceAddress)) {
- goto ON_EXIT;
- }
- //
- // Rebuild fragment table from netbuf to ease ipsec process.
- //
- FragmentTable = AllocateZeroPool (FragmentCount * sizeof (NET_FRAGMENT));
- if (FragmentTable == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_EXIT;
- }
- Status = NetbufBuildExt (Packet, FragmentTable, &FragmentCount);
- OriginalFragmentTable = FragmentTable;
- OriginalFragmentCount = FragmentCount;
- if (EFI_ERROR (Status)) {
- FreePool (FragmentTable);
- goto ON_EXIT;
- }
- //
- // Convert host byte order to network byte order
- //
- Ip6NtohHead (*Head);
- Status = mIpSec->ProcessExt (
- mIpSec,
- IpSb->Controller,
- IP_VERSION_6,
- (VOID *)(*Head),
- LastHead,
- (VOID **)ExtHdrs,
- ExtHdrsLen,
- (EFI_IPSEC_FRAGMENT_DATA **)(&FragmentTable),
- &FragmentCount,
- Direction,
- &RecycleEvent
- );
- //
- // Convert back to host byte order
- //
- Ip6NtohHead (*Head);
- if (EFI_ERROR (Status)) {
- FreePool (OriginalFragmentTable);
- goto ON_EXIT;
- }
- if ((OriginalFragmentCount == FragmentCount) && (OriginalFragmentTable == FragmentTable)) {
- //
- // For ByPass Packet
- //
- FreePool (FragmentTable);
- goto ON_EXIT;
- } else {
- //
- // Free the FragmentTable which allocated before calling the IPsec.
- //
- FreePool (OriginalFragmentTable);
- }
- if ((Direction == EfiIPsecOutBound) && (TxWrap != NULL)) {
- TxWrap->IpSecRecycleSignal = RecycleEvent;
- TxWrap->Packet = NetbufFromExt (
- FragmentTable,
- FragmentCount,
- IP6_MAX_HEADLEN,
- 0,
- Ip6FreeTxToken,
- TxWrap
- );
- if (TxWrap->Packet == NULL) {
- TxWrap->Packet = *Netbuf;
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_EXIT;
- }
- CopyMem (
- IP6_GET_CLIP_INFO (TxWrap->Packet),
- IP6_GET_CLIP_INFO (Packet),
- sizeof (IP6_CLIP_INFO)
- );
- NetIpSecNetbufFree (Packet);
- *Netbuf = TxWrap->Packet;
- } else {
- IpSecWrap = AllocateZeroPool (sizeof (IP6_IPSEC_WRAP));
- if (IpSecWrap == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- gBS->SignalEvent (RecycleEvent);
- goto ON_EXIT;
- }
- IpSecWrap->IpSecRecycleSignal = RecycleEvent;
- IpSecWrap->Packet = Packet;
- Packet = NetbufFromExt (
- FragmentTable,
- FragmentCount,
- IP6_MAX_HEADLEN,
- 0,
- Ip6IpSecFree,
- IpSecWrap
- );
- if (Packet == NULL) {
- Packet = IpSecWrap->Packet;
- gBS->SignalEvent (RecycleEvent);
- FreePool (IpSecWrap);
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_EXIT;
- }
- if ((Direction == EfiIPsecInBound) && (0 != CompareMem (&ZeroHead, *Head, sizeof (EFI_IP6_HEADER)))) {
- PacketHead = (EFI_IP6_HEADER *)NetbufAllocSpace (
- Packet,
- sizeof (EFI_IP6_HEADER) + *ExtHdrsLen,
- NET_BUF_HEAD
- );
- if (PacketHead == NULL) {
- *Netbuf = Packet;
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_EXIT;
- }
- CopyMem (PacketHead, *Head, sizeof (EFI_IP6_HEADER));
- *Head = PacketHead;
- Packet->Ip.Ip6 = PacketHead;
- if (*ExtHdrs != NULL) {
- Buf = (UINT8 *)(PacketHead + 1);
- CopyMem (Buf, *ExtHdrs, *ExtHdrsLen);
- }
- NetbufTrim (Packet, sizeof (EFI_IP6_HEADER) + *ExtHdrsLen, TRUE);
- CopyMem (
- IP6_GET_CLIP_INFO (Packet),
- IP6_GET_CLIP_INFO (IpSecWrap->Packet),
- sizeof (IP6_CLIP_INFO)
- );
- }
- *Netbuf = Packet;
- }
- ON_EXIT:
- return Status;
- }
- /**
- Pre-process the IPv6 packet. First validates the IPv6 packet, and
- then reassembles packet if it is necessary.
- @param[in] IpSb The IP6 service instance.
- @param[in, out] Packet The received IP6 packet to be processed.
- @param[in] Flag The link layer flag for the packet received, such
- as multicast.
- @param[out] Payload The pointer to the payload of the received packet.
- it starts from the first byte of the extension header.
- @param[out] LastHead The pointer of NextHeader of the last extension
- header processed by IP6.
- @param[out] ExtHdrsLen The length of the whole option.
- @param[out] UnFragmentLen The length of unfragmented length of extension headers.
- @param[out] Fragmented Indicate whether the packet is fragmented.
- @param[out] Head The pointer to the EFI_IP6_Header.
- @retval EFI_SUCCESS The received packet is well format.
- @retval EFI_INVALID_PARAMETER The received packet is malformed.
- **/
- EFI_STATUS
- Ip6PreProcessPacket (
- IN IP6_SERVICE *IpSb,
- IN OUT NET_BUF **Packet,
- IN UINT32 Flag,
- OUT UINT8 **Payload,
- OUT UINT8 **LastHead,
- OUT UINT32 *ExtHdrsLen,
- OUT UINT32 *UnFragmentLen,
- OUT BOOLEAN *Fragmented,
- OUT EFI_IP6_HEADER **Head
- )
- {
- UINT16 PayloadLen;
- UINT16 TotalLen;
- UINT32 FormerHeadOffset;
- UINT32 HeadLen;
- IP6_FRAGMENT_HEADER *FragmentHead;
- UINT16 FragmentOffset;
- IP6_CLIP_INFO *Info;
- EFI_IPv6_ADDRESS Loopback;
- HeadLen = 0;
- PayloadLen = 0;
- //
- // Check whether the input packet is a valid packet
- //
- if ((*Packet)->TotalSize < IP6_MIN_HEADLEN) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Get header information of the packet.
- //
- *Head = (EFI_IP6_HEADER *)NetbufGetByte (*Packet, 0, NULL);
- if (*Head == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Multicast addresses must not be used as source addresses in IPv6 packets.
- //
- if (((*Head)->Version != 6) || (IP6_IS_MULTICAST (&(*Head)->SourceAddress))) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // A packet with a destination address of loopback ::1/128 or unspecified must be dropped.
- //
- ZeroMem (&Loopback, sizeof (EFI_IPv6_ADDRESS));
- Loopback.Addr[15] = 0x1;
- if ((CompareMem (&Loopback, &(*Head)->DestinationAddress, sizeof (EFI_IPv6_ADDRESS)) == 0) ||
- (NetIp6IsUnspecifiedAddr (&(*Head)->DestinationAddress)))
- {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Convert the IP header to host byte order.
- //
- (*Packet)->Ip.Ip6 = Ip6NtohHead (*Head);
- //
- // Get the per packet info.
- //
- Info = IP6_GET_CLIP_INFO (*Packet);
- Info->LinkFlag = Flag;
- Info->CastType = 0;
- if (IpSb->MnpConfigData.EnablePromiscuousReceive) {
- Info->CastType = Ip6Promiscuous;
- }
- if (Ip6IsOneOfSetAddress (IpSb, &(*Head)->DestinationAddress, NULL, NULL)) {
- Info->CastType = Ip6Unicast;
- } else if (IP6_IS_MULTICAST (&(*Head)->DestinationAddress)) {
- if (Ip6FindMldEntry (IpSb, &(*Head)->DestinationAddress) != NULL) {
- Info->CastType = Ip6Multicast;
- }
- }
- //
- // Drop the packet that is not delivered to us.
- //
- if (Info->CastType == 0) {
- return EFI_INVALID_PARAMETER;
- }
- PayloadLen = (*Head)->PayloadLength;
- Info->Start = 0;
- Info->Length = PayloadLen;
- Info->End = Info->Start + Info->Length;
- Info->HeadLen = (UINT16)sizeof (EFI_IP6_HEADER);
- Info->Status = EFI_SUCCESS;
- Info->LastFrag = FALSE;
- TotalLen = (UINT16)(PayloadLen + sizeof (EFI_IP6_HEADER));
- //
- // Mnp may deliver frame trailer sequence up, trim it off.
- //
- if (TotalLen < (*Packet)->TotalSize) {
- NetbufTrim (*Packet, (*Packet)->TotalSize - TotalLen, FALSE);
- }
- if (TotalLen != (*Packet)->TotalSize) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Check the extension headers, if exist validate them
- //
- if (PayloadLen != 0) {
- *Payload = AllocatePool ((UINTN)PayloadLen);
- if (*Payload == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- NetbufCopy (*Packet, sizeof (EFI_IP6_HEADER), PayloadLen, *Payload);
- }
- if (!Ip6IsExtsValid (
- IpSb,
- *Packet,
- &(*Head)->NextHeader,
- *Payload,
- (UINT32)PayloadLen,
- TRUE,
- &FormerHeadOffset,
- LastHead,
- ExtHdrsLen,
- UnFragmentLen,
- Fragmented
- ))
- {
- return EFI_INVALID_PARAMETER;
- }
- HeadLen = sizeof (EFI_IP6_HEADER) + *UnFragmentLen;
- if (*Fragmented) {
- //
- // Get the fragment offset from the Fragment header
- //
- FragmentHead = (IP6_FRAGMENT_HEADER *)NetbufGetByte (*Packet, HeadLen, NULL);
- if (FragmentHead == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- FragmentOffset = NTOHS (FragmentHead->FragmentOffset);
- if ((FragmentOffset & 0x1) == 0) {
- Info->LastFrag = TRUE;
- }
- FragmentOffset &= (~0x1);
- //
- // This is the first fragment of the packet
- //
- if (FragmentOffset == 0) {
- Info->NextHeader = FragmentHead->NextHeader;
- }
- Info->HeadLen = (UINT16)HeadLen;
- HeadLen += sizeof (IP6_FRAGMENT_HEADER);
- Info->Start = FragmentOffset;
- Info->Length = TotalLen - (UINT16)HeadLen;
- Info->End = Info->Start + Info->Length;
- Info->Id = FragmentHead->Identification;
- Info->FormerNextHeader = FormerHeadOffset;
- //
- // Fragments should in the unit of 8 octets long except the last one.
- //
- if ((Info->LastFrag == 0) && (Info->Length % 8 != 0)) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Reassemble the packet.
- //
- *Packet = Ip6Reassemble (&IpSb->Assemble, *Packet);
- if (*Packet == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Re-check the assembled packet to get the right values.
- //
- *Head = (*Packet)->Ip.Ip6;
- PayloadLen = (*Head)->PayloadLength;
- if (PayloadLen != 0) {
- if (*Payload != NULL) {
- FreePool (*Payload);
- }
- *Payload = AllocatePool ((UINTN)PayloadLen);
- if (*Payload == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- NetbufCopy (*Packet, sizeof (EFI_IP6_HEADER), PayloadLen, *Payload);
- }
- if (!Ip6IsExtsValid (
- IpSb,
- *Packet,
- &(*Head)->NextHeader,
- *Payload,
- (UINT32)PayloadLen,
- TRUE,
- NULL,
- LastHead,
- ExtHdrsLen,
- UnFragmentLen,
- Fragmented
- ))
- {
- return EFI_INVALID_PARAMETER;
- }
- }
- //
- // Trim the head off, after this point, the packet is headless.
- // and Packet->TotalLen == Info->Length.
- //
- NetbufTrim (*Packet, sizeof (EFI_IP6_HEADER) + *ExtHdrsLen, TRUE);
- return EFI_SUCCESS;
- }
- /**
- The IP6 input routine. It is called by the IP6_INTERFACE when an
- IP6 fragment is received from MNP.
- @param[in] Packet The IP6 packet received.
- @param[in] IoStatus The return status of receive request.
- @param[in] Flag The link layer flag for the packet received, such
- as multicast.
- @param[in] Context The IP6 service instance that owns the MNP.
- **/
- VOID
- Ip6AcceptFrame (
- IN NET_BUF *Packet,
- IN EFI_STATUS IoStatus,
- IN UINT32 Flag,
- IN VOID *Context
- )
- {
- IP6_SERVICE *IpSb;
- EFI_IP6_HEADER *Head;
- UINT8 *Payload;
- UINT8 *LastHead;
- UINT32 UnFragmentLen;
- UINT32 ExtHdrsLen;
- BOOLEAN Fragmented;
- EFI_STATUS Status;
- EFI_IP6_HEADER ZeroHead;
- IpSb = (IP6_SERVICE *)Context;
- NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
- Payload = NULL;
- LastHead = NULL;
- //
- // Check input parameters
- //
- if (EFI_ERROR (IoStatus) || (IpSb->State == IP6_SERVICE_DESTROY)) {
- goto Drop;
- }
- //
- // Pre-Process the Ipv6 Packet and then reassemble if it is necessary.
- //
- Status = Ip6PreProcessPacket (
- IpSb,
- &Packet,
- Flag,
- &Payload,
- &LastHead,
- &ExtHdrsLen,
- &UnFragmentLen,
- &Fragmented,
- &Head
- );
- if (EFI_ERROR (Status)) {
- goto Restart;
- }
- //
- // After trim off, the packet is a esp/ah/udp/tcp/icmp6 net buffer,
- // and no need consider any other ahead ext headers.
- //
- Status = Ip6IpSecProcessPacket (
- IpSb,
- &Head,
- LastHead, // need get the lasthead value for input
- &Packet,
- &Payload,
- &ExtHdrsLen,
- EfiIPsecInBound,
- NULL
- );
- if (EFI_ERROR (Status)) {
- goto Restart;
- }
- //
- // If the packet is protected by IPsec Tunnel Mode, Check the Inner Ip Packet.
- //
- ZeroMem (&ZeroHead, sizeof (EFI_IP6_HEADER));
- if (0 == CompareMem (Head, &ZeroHead, sizeof (EFI_IP6_HEADER))) {
- Status = Ip6PreProcessPacket (
- IpSb,
- &Packet,
- Flag,
- &Payload,
- &LastHead,
- &ExtHdrsLen,
- &UnFragmentLen,
- &Fragmented,
- &Head
- );
- if (EFI_ERROR (Status)) {
- goto Restart;
- }
- }
- //
- // Check the Packet again.
- //
- if (Packet == NULL) {
- goto Restart;
- }
- //
- // Packet may have been changed. The ownership of the packet
- // is transferred to the packet process logic.
- //
- Head = Packet->Ip.Ip6;
- IP6_GET_CLIP_INFO (Packet)->Status = EFI_SUCCESS;
- switch (*LastHead) {
- case IP6_ICMP:
- Ip6IcmpHandle (IpSb, Head, Packet);
- break;
- default:
- Ip6Demultiplex (IpSb, Head, Packet);
- }
- Packet = NULL;
- //
- // Dispatch the DPCs queued by the NotifyFunction of the rx token's events
- // which are signaled with received data.
- //
- DispatchDpc ();
- Restart:
- if (Payload != NULL) {
- FreePool (Payload);
- }
- Ip6ReceiveFrame (Ip6AcceptFrame, IpSb);
- Drop:
- if (Packet != NULL) {
- NetbufFree (Packet);
- }
- return;
- }
- /**
- Initialize an already allocated assemble table. This is generally
- the assemble table embedded in the IP6 service instance.
- @param[in, out] Table The assemble table to initialize.
- **/
- VOID
- Ip6CreateAssembleTable (
- IN OUT IP6_ASSEMBLE_TABLE *Table
- )
- {
- UINT32 Index;
- for (Index = 0; Index < IP6_ASSEMLE_HASH_SIZE; Index++) {
- InitializeListHead (&Table->Bucket[Index]);
- }
- }
- /**
- Clean up the assemble table by removing all of the fragments
- and assemble entries.
- @param[in, out] Table The assemble table to clean up.
- **/
- VOID
- Ip6CleanAssembleTable (
- IN OUT IP6_ASSEMBLE_TABLE *Table
- )
- {
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- IP6_ASSEMBLE_ENTRY *Assemble;
- UINT32 Index;
- for (Index = 0; Index < IP6_ASSEMLE_HASH_SIZE; Index++) {
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &Table->Bucket[Index]) {
- Assemble = NET_LIST_USER_STRUCT (Entry, IP6_ASSEMBLE_ENTRY, Link);
- RemoveEntryList (Entry);
- Ip6FreeAssembleEntry (Assemble);
- }
- }
- }
- /**
- The signal handle of IP6's recycle event. It is called back
- when the upper layer releases the packet.
- @param[in] Event The IP6's recycle event.
- @param[in] Context The context of the handle, which is a IP6_RXDATA_WRAP.
- **/
- VOID
- EFIAPI
- Ip6OnRecyclePacket (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- IP6_RXDATA_WRAP *Wrap;
- Wrap = (IP6_RXDATA_WRAP *)Context;
- EfiAcquireLockOrFail (&Wrap->IpInstance->RecycleLock);
- RemoveEntryList (&Wrap->Link);
- EfiReleaseLock (&Wrap->IpInstance->RecycleLock);
- ASSERT (!NET_BUF_SHARED (Wrap->Packet));
- NetbufFree (Wrap->Packet);
- gBS->CloseEvent (Wrap->RxData.RecycleSignal);
- FreePool (Wrap);
- }
- /**
- Wrap the received packet to a IP6_RXDATA_WRAP, which will be
- delivered to the upper layer. Each IP6 child that accepts the
- packet will get a not-shared copy of the packet which is wrapped
- in the IP6_RXDATA_WRAP. The IP6_RXDATA_WRAP->RxData is passed
- to the upper layer. The upper layer will signal the recycle event in
- it when it is done with the packet.
- @param[in] IpInstance The IP6 child to receive the packet.
- @param[in] Packet The packet to deliver up.
- @return NULL if it failed to wrap the packet; otherwise, the wrapper.
- **/
- IP6_RXDATA_WRAP *
- Ip6WrapRxData (
- IN IP6_PROTOCOL *IpInstance,
- IN NET_BUF *Packet
- )
- {
- IP6_RXDATA_WRAP *Wrap;
- EFI_IP6_RECEIVE_DATA *RxData;
- EFI_STATUS Status;
- Wrap = AllocatePool (IP6_RXDATA_WRAP_SIZE (Packet->BlockOpNum));
- if (Wrap == NULL) {
- return NULL;
- }
- InitializeListHead (&Wrap->Link);
- Wrap->IpInstance = IpInstance;
- Wrap->Packet = Packet;
- RxData = &Wrap->RxData;
- ZeroMem (&RxData->TimeStamp, sizeof (EFI_TIME));
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- Ip6OnRecyclePacket,
- Wrap,
- &RxData->RecycleSignal
- );
- if (EFI_ERROR (Status)) {
- FreePool (Wrap);
- return NULL;
- }
- ASSERT (Packet->Ip.Ip6 != NULL);
- //
- // The application expects a network byte order header.
- //
- RxData->HeaderLength = sizeof (EFI_IP6_HEADER);
- RxData->Header = (EFI_IP6_HEADER *)Ip6NtohHead (Packet->Ip.Ip6);
- RxData->DataLength = Packet->TotalSize;
- //
- // Build the fragment table to be delivered up.
- //
- RxData->FragmentCount = Packet->BlockOpNum;
- NetbufBuildExt (Packet, (NET_FRAGMENT *)RxData->FragmentTable, &RxData->FragmentCount);
- return Wrap;
- }
- /**
- Check whether this IP child accepts the packet.
- @param[in] IpInstance The IP child to check.
- @param[in] Head The IP header of the packet.
- @param[in] Packet The data of the packet.
- @retval TRUE The child wants to receive the packet.
- @retval FALSE The child does not want to receive the packet.
- **/
- BOOLEAN
- Ip6InstanceFrameAcceptable (
- IN IP6_PROTOCOL *IpInstance,
- IN EFI_IP6_HEADER *Head,
- IN NET_BUF *Packet
- )
- {
- IP6_ICMP_ERROR_HEAD Icmp;
- EFI_IP6_CONFIG_DATA *Config;
- IP6_CLIP_INFO *Info;
- UINT8 *Proto;
- UINT32 Index;
- UINT8 *ExtHdrs;
- UINT16 ErrMsgPayloadLen;
- UINT8 *ErrMsgPayload;
- Config = &IpInstance->ConfigData;
- Proto = NULL;
- //
- // Dirty trick for the Tiano UEFI network stack implementation. If
- // ReceiveTimeout == -1, the receive of the packet for this instance
- // is disabled. The UEFI spec don't have such captibility. We add
- // this to improve the performance because IP will make a copy of
- // the received packet for each accepting instance. Some IP instances
- // used by UDP/TCP only send packets, they don't wants to receive.
- //
- if (Config->ReceiveTimeout == (UINT32)(-1)) {
- return FALSE;
- }
- if (Config->AcceptPromiscuous) {
- return TRUE;
- }
- //
- // Check whether the protocol is acceptable.
- //
- ExtHdrs = NetbufGetByte (Packet, 0, NULL);
- if (!Ip6IsExtsValid (
- IpInstance->Service,
- Packet,
- &Head->NextHeader,
- ExtHdrs,
- (UINT32)Head->PayloadLength,
- TRUE,
- NULL,
- &Proto,
- NULL,
- NULL,
- NULL
- ))
- {
- return FALSE;
- }
- //
- // The upper layer driver may want to receive the ICMPv6 error packet
- // invoked by its packet, like UDP.
- //
- if ((*Proto == IP6_ICMP) && (!Config->AcceptAnyProtocol) && (*Proto != Config->DefaultProtocol)) {
- NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *)&Icmp);
- if (Icmp.Head.Type <= ICMP_V6_ERROR_MAX) {
- if (!Config->AcceptIcmpErrors) {
- return FALSE;
- }
- //
- // Get the protocol of the invoking packet of ICMPv6 error packet.
- //
- ErrMsgPayloadLen = NTOHS (Icmp.IpHead.PayloadLength);
- ErrMsgPayload = NetbufGetByte (Packet, sizeof (Icmp), NULL);
- if (!Ip6IsExtsValid (
- NULL,
- NULL,
- &Icmp.IpHead.NextHeader,
- ErrMsgPayload,
- ErrMsgPayloadLen,
- TRUE,
- NULL,
- &Proto,
- NULL,
- NULL,
- NULL
- ))
- {
- return FALSE;
- }
- }
- }
- //
- // Match the protocol
- //
- if (!Config->AcceptAnyProtocol && (*Proto != Config->DefaultProtocol)) {
- return FALSE;
- }
- //
- // Check for broadcast, the caller has computed the packet's
- // cast type for this child's interface.
- //
- Info = IP6_GET_CLIP_INFO (Packet);
- //
- // If it is a multicast packet, check whether we are in the group.
- //
- if (Info->CastType == Ip6Multicast) {
- //
- // Receive the multicast if the instance wants to receive all packets.
- //
- if (NetIp6IsUnspecifiedAddr (&IpInstance->ConfigData.StationAddress)) {
- return TRUE;
- }
- for (Index = 0; Index < IpInstance->GroupCount; Index++) {
- if (EFI_IP6_EQUAL (IpInstance->GroupList + Index, &Head->DestinationAddress)) {
- break;
- }
- }
- return (BOOLEAN)(Index < IpInstance->GroupCount);
- }
- return TRUE;
- }
- /**
- Enqueue a shared copy of the packet to the IP6 child if the
- packet is acceptable to it. Here the data of the packet is
- shared, but the net buffer isn't.
- @param IpInstance The IP6 child to enqueue the packet to.
- @param Head The IP header of the received packet.
- @param Packet The data of the received packet.
- @retval EFI_NOT_STARTED The IP child hasn't been configured.
- @retval EFI_INVALID_PARAMETER The child doesn't want to receive the packet.
- @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources
- @retval EFI_SUCCESS A shared copy the packet is enqueued to the child.
- **/
- EFI_STATUS
- Ip6InstanceEnquePacket (
- IN IP6_PROTOCOL *IpInstance,
- IN EFI_IP6_HEADER *Head,
- IN NET_BUF *Packet
- )
- {
- IP6_CLIP_INFO *Info;
- NET_BUF *Clone;
- //
- // Check whether the packet is acceptable to this instance.
- //
- if (IpInstance->State != IP6_STATE_CONFIGED) {
- return EFI_NOT_STARTED;
- }
- if (!Ip6InstanceFrameAcceptable (IpInstance, Head, Packet)) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Enqueue a shared copy of the packet.
- //
- Clone = NetbufClone (Packet);
- if (Clone == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Set the receive time out for the assembled packet. If it expires,
- // packet will be removed from the queue.
- //
- Info = IP6_GET_CLIP_INFO (Clone);
- Info->Life = IP6_US_TO_SEC (IpInstance->ConfigData.ReceiveTimeout);
- InsertTailList (&IpInstance->Received, &Clone->List);
- return EFI_SUCCESS;
- }
- /**
- Deliver the received packets to the upper layer if there are both received
- requests and enqueued packets. If the enqueued packet is shared, it will
- duplicate it to a non-shared packet, release the shared packet, then
- deliver the non-shared packet up.
- @param[in] IpInstance The IP child to deliver the packet up.
- @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to deliver the
- packets.
- @retval EFI_SUCCESS All the enqueued packets that can be delivered
- are delivered up.
- **/
- EFI_STATUS
- Ip6InstanceDeliverPacket (
- IN IP6_PROTOCOL *IpInstance
- )
- {
- EFI_IP6_COMPLETION_TOKEN *Token;
- IP6_RXDATA_WRAP *Wrap;
- NET_BUF *Packet;
- NET_BUF *Dup;
- UINT8 *Head;
- //
- // Deliver a packet if there are both a packet and a receive token.
- //
- while (!IsListEmpty (&IpInstance->Received) && !NetMapIsEmpty (&IpInstance->RxTokens)) {
- Packet = NET_LIST_HEAD (&IpInstance->Received, NET_BUF, List);
- if (!NET_BUF_SHARED (Packet)) {
- //
- // If this is the only instance that wants the packet, wrap it up.
- //
- Wrap = Ip6WrapRxData (IpInstance, Packet);
- if (Wrap == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- RemoveEntryList (&Packet->List);
- } else {
- //
- // Create a duplicated packet if this packet is shared
- //
- Dup = NetbufDuplicate (Packet, NULL, sizeof (EFI_IP6_HEADER));
- if (Dup == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Copy the IP head over. The packet to deliver up is
- // headless. Trim the head off after copy. The IP head
- // may be not continuous before the data.
- //
- Head = NetbufAllocSpace (Dup, sizeof (EFI_IP6_HEADER), NET_BUF_HEAD);
- ASSERT (Head != NULL);
- Dup->Ip.Ip6 = (EFI_IP6_HEADER *)Head;
- CopyMem (Head, Packet->Ip.Ip6, sizeof (EFI_IP6_HEADER));
- NetbufTrim (Dup, sizeof (EFI_IP6_HEADER), TRUE);
- Wrap = Ip6WrapRxData (IpInstance, Dup);
- if (Wrap == NULL) {
- NetbufFree (Dup);
- return EFI_OUT_OF_RESOURCES;
- }
- RemoveEntryList (&Packet->List);
- NetbufFree (Packet);
- Packet = Dup;
- }
- //
- // Insert it into the delivered packet, then get a user's
- // receive token, pass the wrapped packet up.
- //
- EfiAcquireLockOrFail (&IpInstance->RecycleLock);
- InsertHeadList (&IpInstance->Delivered, &Wrap->Link);
- EfiReleaseLock (&IpInstance->RecycleLock);
- Token = NetMapRemoveHead (&IpInstance->RxTokens, NULL);
- Token->Status = IP6_GET_CLIP_INFO (Packet)->Status;
- Token->Packet.RxData = &Wrap->RxData;
- gBS->SignalEvent (Token->Event);
- }
- return EFI_SUCCESS;
- }
- /**
- Enqueue a received packet to all the IP children that share
- the same interface.
- @param[in] IpSb The IP6 service instance that receive the packet.
- @param[in] Head The header of the received packet.
- @param[in] Packet The data of the received packet.
- @param[in] IpIf The interface to enqueue the packet to.
- @return The number of the IP6 children that accepts the packet.
- **/
- INTN
- Ip6InterfaceEnquePacket (
- IN IP6_SERVICE *IpSb,
- IN EFI_IP6_HEADER *Head,
- IN NET_BUF *Packet,
- IN IP6_INTERFACE *IpIf
- )
- {
- IP6_PROTOCOL *IpInstance;
- IP6_CLIP_INFO *Info;
- LIST_ENTRY *Entry;
- INTN Enqueued;
- INTN LocalType;
- INTN SavedType;
- //
- // First, check that the packet is acceptable to this interface
- // and find the local cast type for the interface.
- //
- LocalType = 0;
- Info = IP6_GET_CLIP_INFO (Packet);
- if (IpIf->PromiscRecv) {
- LocalType = Ip6Promiscuous;
- } else {
- LocalType = Info->CastType;
- }
- //
- // Iterate through the ip instances on the interface, enqueue
- // the packet if filter passed. Save the original cast type,
- // and pass the local cast type to the IP children on the
- // interface. The global cast type will be restored later.
- //
- SavedType = Info->CastType;
- Info->CastType = (UINT32)LocalType;
- Enqueued = 0;
- NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
- IpInstance = NET_LIST_USER_STRUCT (Entry, IP6_PROTOCOL, AddrLink);
- NET_CHECK_SIGNATURE (IpInstance, IP6_PROTOCOL_SIGNATURE);
- if (Ip6InstanceEnquePacket (IpInstance, Head, Packet) == EFI_SUCCESS) {
- Enqueued++;
- }
- }
- Info->CastType = (UINT32)SavedType;
- return Enqueued;
- }
- /**
- Deliver the packet for each IP6 child on the interface.
- @param[in] IpSb The IP6 service instance that received the packet.
- @param[in] IpIf The IP6 interface to deliver the packet.
- **/
- VOID
- Ip6InterfaceDeliverPacket (
- IN IP6_SERVICE *IpSb,
- IN IP6_INTERFACE *IpIf
- )
- {
- IP6_PROTOCOL *IpInstance;
- LIST_ENTRY *Entry;
- NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
- IpInstance = NET_LIST_USER_STRUCT (Entry, IP6_PROTOCOL, AddrLink);
- Ip6InstanceDeliverPacket (IpInstance);
- }
- }
- /**
- De-multiplex the packet. the packet delivery is processed in two
- passes. The first pass will enqueue a shared copy of the packet
- to each IP6 child that accepts the packet. The second pass will
- deliver a non-shared copy of the packet to each IP6 child that
- has pending receive requests. Data is copied if more than one
- child wants to consume the packet, because each IP child needs
- its own copy of the packet to make changes.
- @param[in] IpSb The IP6 service instance that received the packet.
- @param[in] Head The header of the received packet.
- @param[in] Packet The data of the received packet.
- @retval EFI_NOT_FOUND No IP child accepts the packet.
- @retval EFI_SUCCESS The packet is enqueued or delivered to some IP
- children.
- **/
- EFI_STATUS
- Ip6Demultiplex (
- IN IP6_SERVICE *IpSb,
- IN EFI_IP6_HEADER *Head,
- IN NET_BUF *Packet
- )
- {
- LIST_ENTRY *Entry;
- IP6_INTERFACE *IpIf;
- INTN Enqueued;
- //
- // Two pass delivery: first, enqueue a shared copy of the packet
- // to each instance that accept the packet.
- //
- Enqueued = 0;
- NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
- IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
- if (IpIf->Configured) {
- Enqueued += Ip6InterfaceEnquePacket (IpSb, Head, Packet, IpIf);
- }
- }
- //
- // Second: deliver a duplicate of the packet to each instance.
- // Release the local reference first, so that the last instance
- // getting the packet will not copy the data.
- //
- NetbufFree (Packet);
- Packet = NULL;
- if (Enqueued == 0) {
- return EFI_NOT_FOUND;
- }
- NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
- IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
- if (IpIf->Configured) {
- Ip6InterfaceDeliverPacket (IpSb, IpIf);
- }
- }
- return EFI_SUCCESS;
- }
- /**
- Decrease the life of the transmitted packets. If it is
- decreased to zero, cancel the packet. This function is
- called by Ip6packetTimerTicking that provides timeout for both the
- received-but-not-delivered and transmitted-but-not-recycle
- packets.
- @param[in] Map The IP6 child's transmit map.
- @param[in] Item Current transmitted packet.
- @param[in] Context Not used.
- @retval EFI_SUCCESS Always returns EFI_SUCCESS.
- **/
- EFI_STATUS
- EFIAPI
- Ip6SentPacketTicking (
- IN NET_MAP *Map,
- IN NET_MAP_ITEM *Item,
- IN VOID *Context
- )
- {
- IP6_TXTOKEN_WRAP *Wrap;
- Wrap = (IP6_TXTOKEN_WRAP *)Item->Value;
- ASSERT (Wrap != NULL);
- if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {
- Ip6CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);
- }
- return EFI_SUCCESS;
- }
- /**
- Timeout the fragments, and the enqueued, and transmitted packets.
- @param[in] IpSb The IP6 service instance to timeout.
- **/
- VOID
- Ip6PacketTimerTicking (
- IN IP6_SERVICE *IpSb
- )
- {
- LIST_ENTRY *InstanceEntry;
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- IP6_PROTOCOL *IpInstance;
- IP6_ASSEMBLE_ENTRY *Assemble;
- NET_BUF *Packet;
- IP6_CLIP_INFO *Info;
- UINT32 Index;
- //
- // First, time out the fragments. The packet's life is counting down
- // once the first-arriving fragment of that packet was received.
- //
- for (Index = 0; Index < IP6_ASSEMLE_HASH_SIZE; Index++) {
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &(IpSb->Assemble.Bucket[Index])) {
- Assemble = NET_LIST_USER_STRUCT (Entry, IP6_ASSEMBLE_ENTRY, Link);
- if ((Assemble->Life > 0) && (--Assemble->Life == 0)) {
- //
- // If the first fragment (the one with a Fragment Offset of zero)
- // has been received, an ICMP Time Exceeded - Fragment Reassembly
- // Time Exceeded message should be sent to the source of that fragment.
- //
- if ((Assemble->Packet != NULL) &&
- !IP6_IS_MULTICAST (&Assemble->Head->DestinationAddress))
- {
- Ip6SendIcmpError (
- IpSb,
- Assemble->Packet,
- NULL,
- &Assemble->Head->SourceAddress,
- ICMP_V6_TIME_EXCEEDED,
- ICMP_V6_TIMEOUT_REASSEMBLE,
- NULL
- );
- }
- //
- // If reassembly of a packet is not completed within 60 seconds of
- // the reception of the first-arriving fragment of that packet, the
- // reassembly must be abandoned and all the fragments that have been
- // received for that packet must be discarded.
- //
- RemoveEntryList (Entry);
- Ip6FreeAssembleEntry (Assemble);
- }
- }
- }
- NET_LIST_FOR_EACH (InstanceEntry, &IpSb->Children) {
- IpInstance = NET_LIST_USER_STRUCT (InstanceEntry, IP6_PROTOCOL, Link);
- //
- // Second, time out the assembled packets enqueued on each IP child.
- //
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpInstance->Received) {
- Packet = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
- Info = IP6_GET_CLIP_INFO (Packet);
- if ((Info->Life > 0) && (--Info->Life == 0)) {
- RemoveEntryList (Entry);
- NetbufFree (Packet);
- }
- }
- //
- // Third: time out the transmitted packets.
- //
- NetMapIterate (&IpInstance->TxTokens, Ip6SentPacketTicking, NULL);
- }
- }
|