1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606 |
- /** @file
- IP4 input process.
- Copyright (c) 2005 - 2020, Intel Corporation. All rights reserved.<BR>
- (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "Ip4Impl.h"
- /**
- Create an empty assemble entry for the packet identified by
- (Dst, Src, Id, Protocol). The default life for the packet is
- 120 seconds.
- @param[in] Dst The destination address
- @param[in] Src The source address
- @param[in] Id The ID field in IP header
- @param[in] Protocol The protocol field in IP header
- @return NULL if failed to allocate memory for the entry, otherwise
- the point to just created reassemble entry.
- **/
- IP4_ASSEMBLE_ENTRY *
- Ip4CreateAssembleEntry (
- IN IP4_ADDR Dst,
- IN IP4_ADDR Src,
- IN UINT16 Id,
- IN UINT8 Protocol
- )
- {
- IP4_ASSEMBLE_ENTRY *Assemble;
- Assemble = AllocatePool (sizeof (IP4_ASSEMBLE_ENTRY));
- if (Assemble == NULL) {
- return NULL;
- }
- InitializeListHead (&Assemble->Link);
- InitializeListHead (&Assemble->Fragments);
- Assemble->Dst = Dst;
- Assemble->Src = Src;
- Assemble->Id = Id;
- Assemble->Protocol = Protocol;
- Assemble->TotalLen = 0;
- Assemble->CurLen = 0;
- Assemble->Head = NULL;
- Assemble->Info = NULL;
- Assemble->Life = IP4_FRAGMENT_LIFE;
- return Assemble;
- }
- /**
- Release all the fragments of a packet, then free the assemble entry.
- @param[in] Assemble The assemble entry to free
- **/
- VOID
- Ip4FreeAssembleEntry (
- IN IP4_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);
- }
- FreePool (Assemble);
- }
- /**
- Initialize an already allocated assemble table. This is generally
- the assemble table embedded in the IP4 service instance.
- @param[in, out] Table The assemble table to initialize.
- **/
- VOID
- Ip4InitAssembleTable (
- IN OUT IP4_ASSEMBLE_TABLE *Table
- )
- {
- UINT32 Index;
- for (Index = 0; Index < IP4_ASSEMLE_HASH_SIZE; Index++) {
- InitializeListHead (&Table->Bucket[Index]);
- }
- }
- /**
- Clean up the assemble table: remove all the fragments
- and assemble entries.
- @param[in] Table The assemble table to clean up
- **/
- VOID
- Ip4CleanAssembleTable (
- IN IP4_ASSEMBLE_TABLE *Table
- )
- {
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- IP4_ASSEMBLE_ENTRY *Assemble;
- UINT32 Index;
- for (Index = 0; Index < IP4_ASSEMLE_HASH_SIZE; Index++) {
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &Table->Bucket[Index]) {
- Assemble = NET_LIST_USER_STRUCT (Entry, IP4_ASSEMBLE_ENTRY, Link);
- RemoveEntryList (Entry);
- Ip4FreeAssembleEntry (Assemble);
- }
- }
- }
- /**
- Trim the packet to fit in [Start, End), and update the per
- packet information.
- @param Packet Packet to trim
- @param Start The sequence of the first byte to fit in
- @param End One beyond the sequence of last byte to fit in.
- **/
- VOID
- Ip4TrimPacket (
- IN OUT NET_BUF *Packet,
- IN INTN Start,
- IN INTN End
- )
- {
- IP4_CLIP_INFO *Info;
- INTN Len;
- Info = IP4_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 = Start;
- Info->Length -= Len;
- }
- if (End < Info->End) {
- Len = End - Info->End;
- NetbufTrim (Packet, (UINT32)Len, NET_BUF_TAIL);
- Info->End = End;
- Info->Length -= Len;
- }
- }
- /**
- 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 will free all the fragments of the packet.
- @param[in] Arg The assemble entry to free
- **/
- VOID
- EFIAPI
- Ip4OnFreeFragments (
- IN VOID *Arg
- )
- {
- Ip4FreeAssembleEntry ((IP4_ASSEMBLE_ENTRY *)Arg);
- }
- /**
- 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
- return.
- @param Table The assemble table used. New assemble entry will be created
- if the Packet is from a new chain of fragments.
- @param 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 reassemble. The point to just assembled
- packet if all the fragments of the packet have arrived.
- **/
- NET_BUF *
- Ip4Reassemble (
- IN OUT IP4_ASSEMBLE_TABLE *Table,
- IN OUT NET_BUF *Packet
- )
- {
- IP4_HEAD *IpHead;
- IP4_CLIP_INFO *This;
- IP4_CLIP_INFO *Node;
- IP4_ASSEMBLE_ENTRY *Assemble;
- LIST_ENTRY *Head;
- LIST_ENTRY *Prev;
- LIST_ENTRY *Cur;
- NET_BUF *Fragment;
- NET_BUF *NewPacket;
- INTN Index;
- IpHead = Packet->Ip.Ip4;
- This = IP4_GET_CLIP_INFO (Packet);
- ASSERT (IpHead != NULL);
- //
- // First: find the related assemble entry
- //
- Assemble = NULL;
- Index = IP4_ASSEMBLE_HASH (IpHead->Dst, IpHead->Src, IpHead->Id, IpHead->Protocol);
- NET_LIST_FOR_EACH (Cur, &Table->Bucket[Index]) {
- Assemble = NET_LIST_USER_STRUCT (Cur, IP4_ASSEMBLE_ENTRY, Link);
- if ((Assemble->Dst == IpHead->Dst) && (Assemble->Src == IpHead->Src) &&
- (Assemble->Id == IpHead->Id) && (Assemble->Protocol == IpHead->Protocol))
- {
- break;
- }
- }
- //
- // Create a new assemble entry if no assemble entry is related to this packet
- //
- if (Cur == &Table->Bucket[Index]) {
- Assemble = Ip4CreateAssembleEntry (
- IpHead->Dst,
- IpHead->Src,
- IpHead->Id,
- IpHead->Protocol
- );
- if (Assemble == NULL) {
- goto DROP;
- }
- InsertHeadList (&Table->Bucket[Index], &Assemble->Link);
- }
- //
- // Assemble shouldn't be NULL here
- //
- ASSERT (Assemble != NULL);
- //
- // 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.
- //
- Head = &Assemble->Fragments;
- NET_LIST_FOR_EACH (Cur, Head) {
- Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
- if (This->Start < IP4_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) != Head) {
- Fragment = NET_LIST_USER_STRUCT (Prev, NET_BUF, List);
- Node = IP4_GET_CLIP_INFO (Fragment);
- if (This->Start < Node->End) {
- if (This->End <= Node->End) {
- NetbufFree (Packet);
- return NULL;
- }
- Ip4TrimPacket (Packet, Node->End, This->End);
- }
- }
- //
- // 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 != Head) {
- Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
- Node = IP4_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 DROP;
- }
- Ip4TrimPacket (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.
- //
- ASSERT (Assemble->Head == NULL);
- Assemble->Head = IpHead;
- Assemble->Info = IP4_GET_CLIP_INFO (Packet);
- }
- //
- // Don't update the length more than once.
- //
- if (IP4_LAST_FRAGMENT (IpHead->Fragment) && (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 know
- // 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 (Head->BackLink, NET_BUF, List);
- if (IP4_GET_CLIP_INFO (Fragment)->End != Assemble->TotalLen) {
- Ip4FreeAssembleEntry (Assemble);
- return NULL;
- }
- //
- // Wrap the packet in a net buffer then deliver it up
- //
- NewPacket = NetbufFromBufList (
- &Assemble->Fragments,
- 0,
- 0,
- Ip4OnFreeFragments,
- Assemble
- );
- if (NewPacket == NULL) {
- Ip4FreeAssembleEntry (Assemble);
- return NULL;
- }
- NewPacket->Ip.Ip4 = Assemble->Head;
- ASSERT (Assemble->Info != NULL);
- CopyMem (
- IP4_GET_CLIP_INFO (NewPacket),
- Assemble->Info,
- sizeof (*IP4_GET_CLIP_INFO (NewPacket))
- );
- return NewPacket;
- }
- return NULL;
- DROP:
- NetbufFree (Packet);
- return NULL;
- }
- /**
- The callback function for the net buffer which 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
- Ip4IpSecFree (
- IN VOID *Arg
- )
- {
- IP4_IPSEC_WRAP *Wrap;
- Wrap = (IP4_IPSEC_WRAP *)Arg;
- if (Wrap->IpSecRecycleSignal != NULL) {
- gBS->SignalEvent (Wrap->IpSecRecycleSignal);
- }
- NetbufFree (Wrap->Packet);
- FreePool (Wrap);
- return;
- }
- /**
- The work function to locate IPsec protocol to process the inbound or
- outbound IP packets. The process routine handls the packet with following
- actions: bypass the packet, discard the packet, or protect the packet.
- @param[in] IpSb The IP4 service instance.
- @param[in, out] Head The caller supplied IP4 header.
- @param[in, out] Netbuf The IP4 packet to be processed by IPsec.
- @param[in, out] Options The caller supplied options.
- @param[in, out] OptionsLen 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 is no sufficient resource to complete the operation.
- @retval EFI_BUFFER_TOO_SMALL The number of non-empty block is bigger than the
- number of input data blocks when build a fragment table.
- **/
- EFI_STATUS
- Ip4IpSecProcessPacket (
- IN IP4_SERVICE *IpSb,
- IN OUT IP4_HEAD **Head,
- IN OUT NET_BUF **Netbuf,
- IN OUT UINT8 **Options,
- IN OUT UINT32 *OptionsLen,
- 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;
- IP4_TXTOKEN_WRAP *TxWrap;
- IP4_IPSEC_WRAP *IpSecWrap;
- EFI_STATUS Status;
- IP4_HEAD ZeroHead;
- Status = EFI_SUCCESS;
- if (!mIpSec2Installed) {
- goto ON_EXIT;
- }
- ASSERT (mIpSec != NULL);
- Packet = *Netbuf;
- RecycleEvent = NULL;
- IpSecWrap = NULL;
- FragmentTable = NULL;
- TxWrap = (IP4_TXTOKEN_WRAP *)Context;
- FragmentCount = Packet->BlockOpNum;
- ZeroMem (&ZeroHead, sizeof (IP4_HEAD));
- //
- // 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 - IP4_MAX_IPSEC_HEADLEN;
- }
- //
- // 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);
- //
- // Record the original FragmentTable and count.
- //
- OriginalFragmentTable = FragmentTable;
- OriginalFragmentCount = FragmentCount;
- if (EFI_ERROR (Status)) {
- FreePool (FragmentTable);
- goto ON_EXIT;
- }
- //
- // Convert host byte order to network byte order
- //
- Ip4NtohHead (*Head);
- Status = mIpSec->ProcessExt (
- mIpSec,
- IpSb->Controller,
- IP_VERSION_4,
- (VOID *)(*Head),
- &(*Head)->Protocol,
- (VOID **)Options,
- OptionsLen,
- (EFI_IPSEC_FRAGMENT_DATA **)(&FragmentTable),
- &FragmentCount,
- Direction,
- &RecycleEvent
- );
- //
- // Convert back to host byte order
- //
- Ip4NtohHead (*Head);
- if (EFI_ERROR (Status)) {
- FreePool (OriginalFragmentTable);
- goto ON_EXIT;
- }
- if ((OriginalFragmentTable == FragmentTable) && (OriginalFragmentCount == FragmentCount)) {
- //
- // 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,
- IP4_MAX_HEADLEN,
- 0,
- Ip4FreeTxToken,
- TxWrap
- );
- if (TxWrap->Packet == NULL) {
- //
- // Recover the TxWrap->Packet, if meet a error, and the caller will free
- // the TxWrap.
- //
- TxWrap->Packet = *Netbuf;
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_EXIT;
- }
- //
- // Free original Netbuf.
- //
- NetIpSecNetbufFree (*Netbuf);
- *Netbuf = TxWrap->Packet;
- } else {
- IpSecWrap = AllocateZeroPool (sizeof (IP4_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,
- IP4_MAX_HEADLEN,
- 0,
- Ip4IpSecFree,
- 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 (*Head, &ZeroHead, sizeof (IP4_HEAD)))) {
- Ip4PrependHead (Packet, *Head, *Options, *OptionsLen);
- Ip4NtohHead (Packet->Ip.Ip4);
- NetbufTrim (Packet, ((*Head)->HeadLen << 2), TRUE);
- CopyMem (
- IP4_GET_CLIP_INFO (Packet),
- IP4_GET_CLIP_INFO (IpSecWrap->Packet),
- sizeof (IP4_CLIP_INFO)
- );
- }
- *Netbuf = Packet;
- }
- ON_EXIT:
- return Status;
- }
- /**
- Pre-process the IPv4 packet. First validates the IPv4 packet, and
- then reassembles packet if it is necessary.
- @param[in] IpSb Pointer to IP4_SERVICE.
- @param[in, out] Packet Pointer to the Packet to be processed.
- @param[in] Head Pointer to the IP4_HEAD.
- @param[in] Option Pointer to a buffer which contains the IPv4 option.
- @param[in] OptionLen The length of Option in bytes.
- @param[in] Flag The link layer flag for the packet received, such
- as multicast.
- @retval EFI_SUCCESS The received packet is in well form.
- @retval EFI_INVALID_PARAMETER The received packet is malformed.
- **/
- EFI_STATUS
- Ip4PreProcessPacket (
- IN IP4_SERVICE *IpSb,
- IN OUT NET_BUF **Packet,
- IN IP4_HEAD *Head,
- IN UINT8 *Option,
- IN UINT32 OptionLen,
- IN UINT32 Flag
- )
- {
- IP4_CLIP_INFO *Info;
- UINT32 HeadLen;
- UINT32 TotalLen;
- UINT16 Checksum;
- //
- // Check if the IP4 header is correctly formatted.
- //
- HeadLen = (Head->HeadLen << 2);
- TotalLen = NTOHS (Head->TotalLen);
- //
- // Mnp may deliver frame trailer sequence up, trim it off.
- //
- if (TotalLen < (*Packet)->TotalSize) {
- NetbufTrim (*Packet, (*Packet)->TotalSize - TotalLen, FALSE);
- }
- if ((Head->Ver != 4) || (HeadLen < IP4_MIN_HEADLEN) ||
- (TotalLen < HeadLen) || (TotalLen != (*Packet)->TotalSize))
- {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Some OS may send IP packets without checksum.
- //
- Checksum = (UINT16)(~NetblockChecksum ((UINT8 *)Head, HeadLen));
- if ((Head->Checksum != 0) && (Checksum != 0)) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Convert the IP header to host byte order, then get the per packet info.
- //
- (*Packet)->Ip.Ip4 = Ip4NtohHead (Head);
- Info = IP4_GET_CLIP_INFO (*Packet);
- Info->LinkFlag = Flag;
- Info->CastType = Ip4GetHostCast (IpSb, Head->Dst, Head->Src);
- Info->Start = (Head->Fragment & IP4_HEAD_OFFSET_MASK) << 3;
- Info->Length = Head->TotalLen - HeadLen;
- Info->End = Info->Start + Info->Length;
- Info->Status = EFI_SUCCESS;
- //
- // The packet is destinated to us if the CastType is non-zero.
- //
- if ((Info->CastType == 0) || (Info->End > IP4_MAX_PACKET_SIZE)) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Validate the options. Don't call the Ip4OptionIsValid if
- // there is no option to save some CPU process.
- //
- if ((OptionLen > 0) && !Ip4OptionIsValid (Option, OptionLen, TRUE)) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Trim the head off, after this point, the packet is headless,
- // and Packet->TotalLen == Info->Length.
- //
- NetbufTrim (*Packet, HeadLen, TRUE);
- //
- // Reassemble the packet if this is a fragment. The packet is a
- // fragment if its head has MF (more fragment) set, or it starts
- // at non-zero byte.
- //
- if (((Head->Fragment & IP4_HEAD_MF_MASK) != 0) || (Info->Start != 0)) {
- //
- // Drop the fragment if DF is set but it is fragmented. Gateway
- // need to send a type 4 destination unreache ICMP message here.
- //
- if ((Head->Fragment & IP4_HEAD_DF_MASK) != 0) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // The length of all but the last fragments is in the unit of 8 bytes.
- //
- if (((Head->Fragment & IP4_HEAD_MF_MASK) != 0) && (Info->Length % 8 != 0)) {
- return EFI_INVALID_PARAMETER;
- }
- *Packet = Ip4Reassemble (&IpSb->Assemble, *Packet);
- //
- // Packet assembly isn't complete, start receive more packet.
- //
- if (*Packet == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- }
- return EFI_SUCCESS;
- }
- /**
- This function checks the IPv4 packet length.
- @param[in] Packet Pointer to the IPv4 Packet to be checked.
- @retval TRUE The input IPv4 packet length is valid.
- @retval FALSE The input IPv4 packet length is invalid.
- **/
- BOOLEAN
- Ip4IsValidPacketLength (
- IN NET_BUF *Packet
- )
- {
- //
- // Check the IP4 packet length.
- //
- if (Packet->TotalSize < IP4_MIN_HEADLEN) {
- return FALSE;
- }
- return TRUE;
- }
- /**
- The IP4 input routine. It is called by the IP4_INTERFACE when a
- IP4 fragment is received from MNP.
- @param[in] Ip4Instance The IP4 child that request the receive, most like
- it is NULL.
- @param[in] Packet The IP4 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 IP4 service instance that own the MNP.
- **/
- VOID
- Ip4AccpetFrame (
- IN IP4_PROTOCOL *Ip4Instance,
- IN NET_BUF *Packet,
- IN EFI_STATUS IoStatus,
- IN UINT32 Flag,
- IN VOID *Context
- )
- {
- IP4_SERVICE *IpSb;
- IP4_HEAD *Head;
- EFI_STATUS Status;
- IP4_HEAD ZeroHead;
- UINT8 *Option;
- UINT32 OptionLen;
- IpSb = (IP4_SERVICE *)Context;
- Option = NULL;
- if (EFI_ERROR (IoStatus) || (IpSb->State == IP4_SERVICE_DESTROY)) {
- goto DROP;
- }
- if (!Ip4IsValidPacketLength (Packet)) {
- goto RESTART;
- }
- Head = (IP4_HEAD *)NetbufGetByte (Packet, 0, NULL);
- ASSERT (Head != NULL);
- OptionLen = (Head->HeadLen << 2) - IP4_MIN_HEADLEN;
- if (OptionLen > 0) {
- Option = (UINT8 *)(Head + 1);
- }
- //
- // Validate packet format and reassemble packet if it is necessary.
- //
- Status = Ip4PreProcessPacket (
- IpSb,
- &Packet,
- Head,
- Option,
- OptionLen,
- Flag
- );
- 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 = Ip4IpSecProcessPacket (
- IpSb,
- &Head,
- &Packet,
- &Option,
- &OptionLen,
- EfiIPsecInBound,
- NULL
- );
- if (EFI_ERROR (Status)) {
- goto RESTART;
- }
- //
- // If the packet is protected by tunnel mode, parse the inner Ip Packet.
- //
- ZeroMem (&ZeroHead, sizeof (IP4_HEAD));
- if (0 == CompareMem (Head, &ZeroHead, sizeof (IP4_HEAD))) {
- // Packet may have been changed. Head, HeadLen, TotalLen, and
- // info must be reloaded before use. The ownership of the packet
- // is transferred to the packet process logic.
- //
- if (!Ip4IsValidPacketLength (Packet)) {
- goto RESTART;
- }
- Head = (IP4_HEAD *)NetbufGetByte (Packet, 0, NULL);
- ASSERT (Head != NULL);
- Status = Ip4PreProcessPacket (
- IpSb,
- &Packet,
- Head,
- Option,
- OptionLen,
- Flag
- );
- if (EFI_ERROR (Status)) {
- goto RESTART;
- }
- }
- ASSERT (Packet != NULL);
- Head = Packet->Ip.Ip4;
- IP4_GET_CLIP_INFO (Packet)->Status = EFI_SUCCESS;
- switch (Head->Protocol) {
- case EFI_IP_PROTO_ICMP:
- Ip4IcmpHandle (IpSb, Head, Packet);
- break;
- case IP4_PROTO_IGMP:
- Ip4IgmpHandle (IpSb, Head, Packet);
- break;
- default:
- Ip4Demultiplex (IpSb, Head, Packet, Option, OptionLen);
- }
- Packet = NULL;
- //
- // Dispatch the DPCs queued by the NotifyFunction of the rx token's events
- // which are signaled with received data.
- //
- DispatchDpc ();
- RESTART:
- Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);
- DROP:
- if (Packet != NULL) {
- NetbufFree (Packet);
- }
- return;
- }
- /**
- 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 If the child wants to receive the packet.
- @retval FALSE Otherwise.
- **/
- BOOLEAN
- Ip4InstanceFrameAcceptable (
- IN IP4_PROTOCOL *IpInstance,
- IN IP4_HEAD *Head,
- IN NET_BUF *Packet
- )
- {
- IP4_ICMP_ERROR_HEAD Icmp;
- EFI_IP4_CONFIG_DATA *Config;
- IP4_CLIP_INFO *Info;
- UINT16 Proto;
- UINT32 Index;
- Config = &IpInstance->ConfigData;
- //
- // 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 capability. 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;
- }
- //
- // Use protocol from the IP header embedded in the ICMP error
- // message to filter, instead of ICMP itself. ICMP handle will
- // call Ip4Demultiplex to deliver ICMP errors.
- //
- Proto = Head->Protocol;
- if ((Proto == EFI_IP_PROTO_ICMP) && (!Config->AcceptAnyProtocol) && (Proto != Config->DefaultProtocol)) {
- NetbufCopy (Packet, 0, sizeof (Icmp.Head), (UINT8 *)&Icmp.Head);
- if (mIcmpClass[Icmp.Head.Type].IcmpClass == ICMP_ERROR_MESSAGE) {
- if (!Config->AcceptIcmpErrors) {
- return FALSE;
- }
- NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *)&Icmp);
- Proto = Icmp.IpHead.Protocol;
- }
- }
- //
- // 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 = IP4_GET_CLIP_INFO (Packet);
- if (IP4_IS_BROADCAST (Info->CastType)) {
- return Config->AcceptBroadcast;
- }
- //
- // If it is a multicast packet, check whether we are in the group.
- //
- if (Info->CastType == IP4_MULTICAST) {
- //
- // Receive the multicast if the instance wants to receive all packets.
- //
- if (!IpInstance->ConfigData.UseDefaultAddress && (IpInstance->Interface->Ip == 0)) {
- return TRUE;
- }
- for (Index = 0; Index < IpInstance->GroupCount; Index++) {
- if (IpInstance->Groups[Index] == HTONL (Head->Dst)) {
- break;
- }
- }
- return (BOOLEAN)(Index < IpInstance->GroupCount);
- }
- return TRUE;
- }
- /**
- Enqueue a shared copy of the packet to the IP4 child if the
- packet is acceptable to it. Here the data of the packet is
- shared, but the net buffer isn't.
- @param[in] IpInstance The IP4 child to enqueue the packet to
- @param[in] Head The IP header of the received packet
- @param[in] 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 resource
- @retval EFI_SUCCESS A shared copy the packet is enqueued to the child.
- **/
- EFI_STATUS
- Ip4InstanceEnquePacket (
- IN IP4_PROTOCOL *IpInstance,
- IN IP4_HEAD *Head,
- IN NET_BUF *Packet
- )
- {
- IP4_CLIP_INFO *Info;
- NET_BUF *Clone;
- //
- // Check whether the packet is acceptable to this instance.
- //
- if (IpInstance->State != IP4_STATE_CONFIGED) {
- return EFI_NOT_STARTED;
- }
- if (!Ip4InstanceFrameAcceptable (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 = IP4_GET_CLIP_INFO (Clone);
- Info->Life = IP4_US_TO_SEC (IpInstance->ConfigData.ReceiveTimeout);
- InsertTailList (&IpInstance->Received, &Clone->List);
- return EFI_SUCCESS;
- }
- /**
- The signal handle of IP4's recycle event. It is called back
- when the upper layer release the packet.
- @param Event The IP4's recycle event.
- @param Context The context of the handle, which is a
- IP4_RXDATA_WRAP
- **/
- VOID
- EFIAPI
- Ip4OnRecyclePacket (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- IP4_RXDATA_WRAP *Wrap;
- Wrap = (IP4_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 IP4_RXDATA_WRAP, which will be
- delivered to the upper layer. Each IP4 child that accepts the
- packet will get a not-shared copy of the packet which is wrapped
- in the IP4_RXDATA_WRAP. The IP4_RXDATA_WRAP->RxData is passed
- to the upper layer. Upper layer will signal the recycle event in
- it when it is done with the packet.
- @param[in] IpInstance The IP4 child to receive the packet.
- @param[in] Packet The packet to deliver up.
- @retval Wrap if warp the packet succeed.
- @retval NULL failed to wrap the packet .
- **/
- IP4_RXDATA_WRAP *
- Ip4WrapRxData (
- IN IP4_PROTOCOL *IpInstance,
- IN NET_BUF *Packet
- )
- {
- IP4_RXDATA_WRAP *Wrap;
- EFI_IP4_RECEIVE_DATA *RxData;
- EFI_STATUS Status;
- BOOLEAN RawData;
- Wrap = AllocatePool (IP4_RXDATA_WRAP_SIZE (Packet->BlockOpNum));
- if (Wrap == NULL) {
- return NULL;
- }
- InitializeListHead (&Wrap->Link);
- Wrap->IpInstance = IpInstance;
- Wrap->Packet = Packet;
- RxData = &Wrap->RxData;
- ZeroMem (RxData, sizeof (EFI_IP4_RECEIVE_DATA));
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- Ip4OnRecyclePacket,
- Wrap,
- &RxData->RecycleSignal
- );
- if (EFI_ERROR (Status)) {
- FreePool (Wrap);
- return NULL;
- }
- ASSERT (Packet->Ip.Ip4 != NULL);
- ASSERT (IpInstance != NULL);
- RawData = IpInstance->ConfigData.RawData;
- //
- // The application expects a network byte order header.
- //
- if (!RawData) {
- RxData->HeaderLength = (Packet->Ip.Ip4->HeadLen << 2);
- RxData->Header = (EFI_IP4_HEADER *)Ip4NtohHead (Packet->Ip.Ip4);
- RxData->OptionsLength = RxData->HeaderLength - IP4_MIN_HEADLEN;
- RxData->Options = NULL;
- if (RxData->OptionsLength != 0) {
- RxData->Options = (VOID *)(RxData->Header + 1);
- }
- }
- 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;
- }
- /**
- Deliver the received packets to 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
- Ip4InstanceDeliverPacket (
- IN IP4_PROTOCOL *IpInstance
- )
- {
- EFI_IP4_COMPLETION_TOKEN *Token;
- IP4_RXDATA_WRAP *Wrap;
- NET_BUF *Packet;
- NET_BUF *Dup;
- UINT8 *Head;
- UINT32 HeadLen;
- //
- // 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 = Ip4WrapRxData (IpInstance, Packet);
- if (Wrap == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- RemoveEntryList (&Packet->List);
- } else {
- //
- // Create a duplicated packet if this packet is shared
- //
- if (IpInstance->ConfigData.RawData) {
- HeadLen = 0;
- } else {
- HeadLen = IP4_MAX_HEADLEN;
- }
- Dup = NetbufDuplicate (Packet, NULL, HeadLen);
- if (Dup == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- if (!IpInstance->ConfigData.RawData) {
- //
- // 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, IP4_MAX_HEADLEN, NET_BUF_HEAD);
- ASSERT (Head != NULL);
- Dup->Ip.Ip4 = (IP4_HEAD *)Head;
- CopyMem (Head, Packet->Ip.Ip4, Packet->Ip.Ip4->HeadLen << 2);
- NetbufTrim (Dup, IP4_MAX_HEADLEN, TRUE);
- }
- Wrap = Ip4WrapRxData (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 = IP4_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 IP4 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] Option Point to the IP4 packet header options.
- @param[in] OptionLen Length of the IP4 packet header options.
- @param[in] IpIf The interface to enqueue the packet to.
- @return The number of the IP4 children that accepts the packet
- **/
- INTN
- Ip4InterfaceEnquePacket (
- IN IP4_SERVICE *IpSb,
- IN IP4_HEAD *Head,
- IN NET_BUF *Packet,
- IN UINT8 *Option,
- IN UINT32 OptionLen,
- IN IP4_INTERFACE *IpIf
- )
- {
- IP4_PROTOCOL *IpInstance;
- IP4_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. A packet sent
- // to say 192.168.1.1 should NOT be deliver to 10.0.0.1 unless
- // promiscuous receiving.
- //
- LocalType = 0;
- Info = IP4_GET_CLIP_INFO (Packet);
- if ((Info->CastType == IP4_MULTICAST) || (Info->CastType == IP4_LOCAL_BROADCAST)) {
- //
- // If the CastType is multicast, don't need to filter against
- // the group address here, Ip4InstanceFrameAcceptable will do
- // that later.
- //
- LocalType = Info->CastType;
- } else {
- //
- // Check the destination against local IP. If the station
- // address is 0.0.0.0, it means receiving all the IP destined
- // to local non-zero IP. Otherwise, it is necessary to compare
- // the destination to the interface's IP address.
- //
- if (IpIf->Ip == IP4_ALLZERO_ADDRESS) {
- LocalType = IP4_LOCAL_HOST;
- } else {
- LocalType = Ip4GetNetCast (Head->Dst, IpIf);
- if ((LocalType == 0) && IpIf->PromiscRecv) {
- LocalType = IP4_PROMISCUOUS;
- }
- }
- }
- if (LocalType == 0) {
- return 0;
- }
- //
- // 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 = LocalType;
- Enqueued = 0;
- NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
- IpInstance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);
- NET_CHECK_SIGNATURE (IpInstance, IP4_PROTOCOL_SIGNATURE);
- //
- // In RawData mode, add IPv4 headers and options back to packet.
- //
- if ((IpInstance->ConfigData.RawData) && (Option != NULL) && (OptionLen != 0)) {
- Ip4PrependHead (Packet, Head, Option, OptionLen);
- }
- if (Ip4InstanceEnquePacket (IpInstance, Head, Packet) == EFI_SUCCESS) {
- Enqueued++;
- }
- }
- Info->CastType = SavedType;
- return Enqueued;
- }
- /**
- Deliver the packet for each IP4 child on the interface.
- @param[in] IpSb The IP4 service instance that received the packet
- @param[in] IpIf The IP4 interface to deliver the packet.
- @retval EFI_SUCCESS It always returns EFI_SUCCESS now
- **/
- EFI_STATUS
- Ip4InterfaceDeliverPacket (
- IN IP4_SERVICE *IpSb,
- IN IP4_INTERFACE *IpIf
- )
- {
- IP4_PROTOCOL *Ip4Instance;
- LIST_ENTRY *Entry;
- NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
- Ip4Instance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);
- Ip4InstanceDeliverPacket (Ip4Instance);
- }
- return EFI_SUCCESS;
- }
- /**
- Demultiple the packet. the packet delivery is processed in two
- passes. The first pass will enqueue a shared copy of the packet
- to each IP4 child that accepts the packet. The second pass will
- deliver a non-shared copy of the packet to each IP4 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 IP4 service instance that received the packet.
- @param[in] Head The header of the received packet.
- @param[in] Packet The data of the received packet.
- @param[in] Option Point to the IP4 packet header options.
- @param[in] OptionLen Length of the IP4 packet header options.
- @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
- Ip4Demultiplex (
- IN IP4_SERVICE *IpSb,
- IN IP4_HEAD *Head,
- IN NET_BUF *Packet,
- IN UINT8 *Option,
- IN UINT32 OptionLen
- )
- {
- LIST_ENTRY *Entry;
- IP4_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, IP4_INTERFACE, Link);
- if (IpIf->Configured) {
- Enqueued += Ip4InterfaceEnquePacket (
- IpSb,
- Head,
- Packet,
- Option,
- OptionLen,
- 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);
- if (Enqueued == 0) {
- return EFI_NOT_FOUND;
- }
- NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
- IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
- if (IpIf->Configured) {
- Ip4InterfaceDeliverPacket (IpSb, IpIf);
- }
- }
- return EFI_SUCCESS;
- }
- /**
- Timeout the fragment and enqueued packets.
- @param[in] IpSb The IP4 service instance to timeout
- **/
- VOID
- Ip4PacketTimerTicking (
- IN IP4_SERVICE *IpSb
- )
- {
- LIST_ENTRY *InstanceEntry;
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- IP4_PROTOCOL *IpInstance;
- IP4_ASSEMBLE_ENTRY *Assemble;
- NET_BUF *Packet;
- IP4_CLIP_INFO *Info;
- UINT32 Index;
- //
- // First, time out the fragments. The packet's life is counting down
- // once the first-arrived fragment was received.
- //
- for (Index = 0; Index < IP4_ASSEMLE_HASH_SIZE; Index++) {
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->Assemble.Bucket[Index]) {
- Assemble = NET_LIST_USER_STRUCT (Entry, IP4_ASSEMBLE_ENTRY, Link);
- if ((Assemble->Life > 0) && (--Assemble->Life == 0)) {
- RemoveEntryList (Entry);
- Ip4FreeAssembleEntry (Assemble);
- }
- }
- }
- NET_LIST_FOR_EACH (InstanceEntry, &IpSb->Children) {
- IpInstance = NET_LIST_USER_STRUCT (InstanceEntry, IP4_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 = IP4_GET_CLIP_INFO (Packet);
- if ((Info->Life > 0) && (--Info->Life == 0)) {
- RemoveEntryList (Entry);
- NetbufFree (Packet);
- }
- }
- //
- // Third: time out the transmitted packets.
- //
- NetMapIterate (&IpInstance->TxTokens, Ip4SentPacketTicking, NULL);
- }
- }
|