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 + -
显示快捷键?