ip4input.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,332 行 · 第 1/3 页

C
1,332
字号
/*++

Copyright (c) 2005 - 2006, Intel Corporation                                                         
All rights reserved. This program and the accompanying materials                          
are licensed and made available under the terms and conditions of the BSD License         
which accompanies this distribution.  The full text of the license may be found at        
http://opensource.org/licenses/bsd-license.php                                            
                                                                                          
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

Module Name:

  Ip4Input.c

Abstract:

  IP4 input process.

--*/

#include "Ip4Impl.h"

STATIC
IP4_ASSEMBLE_ENTRY *
Ip4CreateAssembleEntry (
  IN IP4_ADDR               Dst,
  IN IP4_ADDR               Src,
  IN UINT16                 Id,
  IN UINT8                  Protocol
  )
/*++

Routine Description:

  Create a empty assemble entry for the packet identified by 
  (Dst, Src, Id, Protocol). The default life for the packet is
  120 seconds.

Arguments:

  Dst       - The destination address
  Src       - The source address
  Id        - The ID field in IP header
  Protocol  - The protocol field in IP header

Returns:

  NULL if failed to allocate memory for the entry, otherwise
  the point to just created reassemble entry.

--*/
{

  IP4_ASSEMBLE_ENTRY        *Assemble;

  Assemble = NetAllocatePool (sizeof (IP4_ASSEMBLE_ENTRY));

  if (Assemble == NULL) {
    return NULL;
  }

  NetListInit (&Assemble->Link);
  NetListInit (&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;
}

STATIC
VOID
Ip4FreeAssembleEntry (
  IN IP4_ASSEMBLE_ENTRY     *Assemble
  )
/*++

Routine Description:

  Release all the fragments of a packet, then free the assemble entry

Arguments:

  Assemble  - The assemble entry to free

Returns:

  None

--*/
{
  NET_LIST_ENTRY            *Entry;
  NET_LIST_ENTRY            *Next;
  NET_BUF                   *Fragment;

  NET_LIST_FOR_EACH_SAFE (Entry, Next, &Assemble->Fragments) {
    Fragment = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);

    NetListRemoveEntry (Entry);
    NetbufFree (Fragment);
  }

  NetFreePool (Assemble);
}

VOID
Ip4InitAssembleTable (
  IN IP4_ASSEMBLE_TABLE     *Table
  )
/*++

Routine Description:

  Initialize an already allocated assemble table. This is generally
  the assemble table embedded in the IP4 service instance.

Arguments:

  Table - The assemble table to initialize.

Returns:

  NONE

--*/
{
  UINT32                    Index;

  for (Index = 0; Index < IP4_ASSEMLE_HASH_SIZE; Index++) {
    NetListInit (&Table->Bucket[Index]);
  }
}

VOID
Ip4CleanAssembleTable (
  IN IP4_ASSEMBLE_TABLE     *Table
  )
/*++

Routine Description:

  Clean up the assemble table: remove all the fragments
  and assemble entries.

Arguments:

  Table - The assemble table to clean up

Returns:

  None

--*/
{
  NET_LIST_ENTRY            *Entry;
  NET_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);

      NetListRemoveEntry (Entry);
      Ip4FreeAssembleEntry (Assemble);
    }
  }
}

STATIC
VOID
Ip4TrimPacket (
  IN NET_BUF                *Packet,
  IN INTN                   Start,
  IN INTN                   End
  )
/*++

Routine Description:

  Trim the packet to fit in [Start, End), and update the per 
  packet information.

Arguments:

  Packet  - Packet to trim
  Start   - The sequence of the first byte to fit in
  End     - One beyond the sequence of last byte to fit in.

Returns:

  None

--*/
{
  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;
  }
}

STATIC
VOID
Ip4OnFreeFragments (
  IN VOID                   *Arg
  )
/*++

Routine Description:

  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.

Arguments:

  Arg - The assemble entry to free

Returns:

  None

--*/
{
  Ip4FreeAssembleEntry ((IP4_ASSEMBLE_ENTRY *) Arg);
}

STATIC
NET_BUF *
Ip4Reassemble (
  IN IP4_ASSEMBLE_TABLE     *Table,
  IN NET_BUF                *Packet
  )
/*++

Routine Description:

  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.

Arguments:

  Table   - The assemble table used.
  Packet  - The fragment to assemble

Returns:

  NULL if the packet can't be reassemble. The point to just assembled
  packet if all the fragments of the packet have arrived.

--*/
{
  IP4_HEAD                  *IpHead;
  IP4_CLIP_INFO             *This;
  IP4_CLIP_INFO             *Node;
  IP4_ASSEMBLE_ENTRY        *Assemble;
  NET_LIST_ENTRY            *Head;
  NET_LIST_ENTRY            *Prev;
  NET_LIST_ENTRY            *Cur;
  NET_BUF                   *Fragment;
  NET_BUF                   *NewPacket;
  INTN                      Index;

  IpHead  = Packet->Ip;
  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;
    }

    NetListInsertHead (&Table->Bucket[Index], &Assemble->Link);
  }

  //
  // Find the point to insert the packet: before the first
  // fragment with THIS.Start < CUR.Start. the previous one
  // has PREV.Start <= THIS.Start < CUR.Start.
  //
  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->ForwardLink) != 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;

      NetListRemoveEntry (&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) {
        NetListRemoveEntry (&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 totoal length is know
  //  2. received all the data. If the last fragment on the
  //     queue ends at the total length, all data is received.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?