REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the NetworkPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Maciej Rabeda <maciej.rabeda@linux.intel.com>
		
			
				
	
	
		
			1607 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1607 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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);
 | 
						|
  }
 | 
						|
}
 |