ip4input.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,332 行 · 第 1/3 页
C
1,332 行
//
if ((Assemble->TotalLen != 0) && (Assemble->CurLen >= Assemble->TotalLen)) {
NetListRemoveEntry (&Assemble->Link);
//
// If the packet is properly formated, 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 = Assemble->Head;
*IP4_GET_CLIP_INFO (NewPacket) = *Assemble->Info;
return NewPacket;
}
return NULL;
DROP:
NetbufFree (Packet);
return NULL;
}
VOID
Ip4AccpetFrame (
IN IP4_PROTOCOL *Ip4Instance,
IN NET_BUF *Packet,
IN EFI_STATUS IoStatus,
IN UINT32 Flag,
IN VOID *Context
)
/*++
Routine Description:
The IP4 input routine. It is called by the IP4_INTERFACE when a
IP4 fragment is received from MNP.
Arguments:
Ip4Instance - The IP4 child that request the receive, most like it is NULL.
Packet - The IP4 packet received.
IoStatus - The return status of receive request.
Flag - The link layer flag for the packet received, such as multicast.
Context - The IP4 service instance that own the MNP.
Returns:
None
--*/
{
IP4_SERVICE *IpSb;
IP4_CLIP_INFO *Info;
IP4_HEAD *Head;
UINT32 HeadLen;
UINT32 OptionLen;
UINT32 TotalLen;
UINT16 Checksum;
IpSb = (IP4_SERVICE *) Context;
if (EFI_ERROR (IoStatus) || (IpSb->State == IP4_SERVICE_DESTORY)) {
goto DROP;
}
//
// Check that the IP4 header is correctly formated
//
if (Packet->TotalSize < IP4_MIN_HEADLEN) {
goto RESTART;
}
Head = (IP4_HEAD *) NetbufGetByte (Packet, 0, NULL);
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)) {
goto RESTART;
}
//
// Some OS may send IP packets without checksum.
//
Checksum = ~NetblockChecksum ((UINT8 *) Head, HeadLen);
if ((Head->Checksum != 0) && (Checksum != 0)) {
goto RESTART;
}
//
// Convert the IP header to host byte order, then get the per packet info.
//
Packet->Ip = 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)) {
goto RESTART;
}
//
// Validate the options. Don't call the Ip4OptionIsValid if
// there is no option to save some CPU process.
//
OptionLen = HeadLen - IP4_MIN_HEADLEN;
if ((OptionLen > 0) && !Ip4OptionIsValid ((UINT8 *) (Head + 1), OptionLen, TRUE)) {
goto RESTART;
}
//
// 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) || (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) {
goto RESTART;
}
//
// The length of all but the last fragments is in the unit of 8 bytes.
//
if ((Head->Fragment & IP4_HEAD_MF_MASK) && (Info->Length % 8 != 0)) {
goto RESTART;
}
Packet = Ip4Reassemble (&IpSb->Assemble, Packet);
//
// Packet assembly isn't complete, start receive more packet.
//
if (Packet == NULL) {
goto RESTART;
}
}
//
// Packet may have been changed. Head, HeadLen, TotalLen, and
// info must be reloaded bofore use. The ownership of the packet
// is transfered to the packet process logic.
//
Head = Packet->Ip;
IP4_GET_CLIP_INFO (Packet)->Status = EFI_SUCCESS;
switch (Head->Protocol) {
case IP4_PROTO_ICMP:
Ip4IcmpHandle (IpSb, Head, Packet);
break;
case IP4_PROTO_IGMP:
Ip4IgmpHandle (IpSb, Head, Packet);
break;
default:
Ip4Demultiplex (IpSb, Head, Packet);
}
Packet = NULL;
RESTART:
Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);
DROP:
if (Packet != NULL) {
NetbufFree (Packet);
}
return ;
}
BOOLEAN
Ip4InstanceFrameAcceptable (
IN IP4_PROTOCOL *IpInstance,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
)
/*++
Routine Description:
Check whether this IP child accepts the packet.
Arguments:
IpInstance - The IP child to check
Head - The IP header of the packet
Packet - The data of the packet
Returns:
TRUE if the child wants to receive the packet, otherwise return FALSE.
--*/
{
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 implmentation. If
// ReceiveTimeout == -1, the receive of the packet for this instance
// is disabled. The UEFI spec don't have such captibility. We add
// this to improve the performance because IP will make a copy of
// the received packet for each accepting instance. Some IP instances
// used by UDP/TCP only send packets, they don't wants to receive.
//
if (Config->ReceiveTimeout == (UINT32)(-1)) {
return FALSE;
}
if (Config->AcceptPromiscuous) {
return TRUE;
}
//
// Use protocol from the IP header embedded in the ICMP error
// message to filter, instead of ICMP itself. ICMP handle will
// can Ip4Demultiplex to deliver ICMP errors.
//
Proto = Head->Protocol;
if (Proto == IP4_PROTO_ICMP) {
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;
}
EFI_STATUS
Ip4InstanceEnquePacket (
IN IP4_PROTOCOL *IpInstance,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
)
/*++
Routine Description:
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.
Arguments:
IpInstance - The IP4 child to enqueue the packet to
Head - The IP header of the received packet
Packet - The data of the received packet
Returns:
EFI_NOT_STARTED - The IP child hasn't been configured.
EFI_INVALID_PARAMETER - The child doesn't want to receive the packet
EFI_OUT_OF_RESOURCES - Failed to allocate some resource
EFI_SUCCESS - A shared copy the packet is enqueued to the child.
--*/
{
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;
}
//
// Enque 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);
NetListInsertTail (&IpInstance->Received, &Clone->List);
return EFI_SUCCESS;
}
STATIC
VOID
EFIAPI
Ip4OnRecyclePacket (
IN EFI_EVENT Event,
IN VOID *Context
)
/*++
Routine Description:
The signal handle of IP4's recycle event. It is called back
when the upper layer release the packet.
Arguments:
Event - The IP4's recycle event.
Context - The context of the handle, which is a IP4_RXDATA_WRAP
Returns:
None
--*/
{
IP4_RXDATA_WRAP *Wrap;
Wrap = (IP4_RXDATA_WRAP *) Context;
NET_TRYLOCK (&Wrap->IpInstance->RecycleLock);
NetListRemoveEntry (&Wrap->Link);
NET_UNLOCK (&Wrap->IpInstance->RecycleLock);
ASSERT (!NET_BUF_SHARED (Wrap->Packet));
NetbufFree (Wrap->Packet);
gBS->CloseEvent (Wrap->RxData.RecycleSignal);
NetFreePool (Wrap);
}
IP4_RXDATA_WRAP *
Ip4WrapRxData (
IN IP4_PROTOCOL *IpInstance,
IN NET_BUF *Packet
)
/*++
Routine Description:
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
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?