ipio.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,364 行 · 第 1/2 页
C
1,364 行
/*++
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:
IpIo.c
Abstract:
The implementation of the IpIo layer.
--*/
#include "IpIo.h"
#define NET_PROTO_HDR(Buf, Type) ((Type *) ((Buf)->BlockOp[0].Head))
#define ICMP_ERRLEN(IpHdr) \
(sizeof(IP4_ICMP_HEAD) + EFI_IP4_HEADER_LEN(IpHdr) + 8)
NET_LIST_ENTRY mActiveIpIoList = {
&mActiveIpIoList,
&mActiveIpIoList
};
EFI_IP4_CONFIG_DATA mIpIoDefaultIpConfigData = {
EFI_IP_PROTO_UDP,
FALSE,
TRUE,
FALSE,
FALSE,
FALSE,
{0, 0, 0, 0},
{0, 0, 0, 0},
0,
255,
FALSE,
FALSE,
0,
0
};
ICMP_ERROR_INFO mIcmpErrMap[] = {
{ EFI_NETWORK_UNREACHABLE, FALSE, TRUE }, // ICMP_ERR_UNREACH_NET
{ EFI_HOST_UNREACHABLE, FALSE, TRUE }, // ICMP_ERR_UNREACH_HOST
{ EFI_PROTOCOL_UNREACHABLE, TRUE, TRUE }, // ICMP_ERR_UNREACH_PROTOCOL
{ EFI_PORT_UNREACHABLE, TRUE, TRUE }, // ICMP_ERR_UNREACH_PORT
{ EFI_ICMP_ERROR, TRUE, TRUE }, // ICMP_ERR_MSGSIZE
{ EFI_ICMP_ERROR, FALSE, TRUE }, // ICMP_ERR_UNREACH_SRCFAIL
{ EFI_HOST_UNREACHABLE, FALSE, TRUE }, // ICMP_ERR_TIMXCEED_INTRANS
{ EFI_HOST_UNREACHABLE, FALSE, TRUE }, // ICMP_ERR_TIMEXCEED_REASS
{ EFI_ICMP_ERROR, FALSE, FALSE }, // ICMP_ERR_QUENCH
{ EFI_ICMP_ERROR, FALSE, TRUE } // ICMP_ERR_PARAMPROB
};
STATIC
VOID
EFIAPI
IpIoTransmitHandler (
IN EFI_EVENT Event,
IN VOID *Context
);
STATIC
EFI_STATUS
IpIoCreateIpChildOpenProtocol (
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ImageHandle,
IN EFI_HANDLE *ChildHandle,
OUT VOID **Interface
)
/*++
Routine Description:
This function create an ip child ,open the IP protocol, return the opened
Ip protocol to Interface.
Arguments:
ControllerHandle - The controller handle.
ImageHandle - The image handle.
ChildHandle - Pointer to the buffer to save the ip child handle.
Interface - Pointer used to get the ip protocol interface.
Returns:
EFI_SUCCESS - The ip child is created and the ip protocol interface is retrieved.
other - The required operation failed.
--*/
{
EFI_STATUS Status;
//
// Create an ip child.
//
Status = NetLibCreateServiceChild (
ControllerHandle,
ImageHandle,
&gEfiIp4ServiceBindingProtocolGuid,
ChildHandle
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Open the ip protocol installed on the *ChildHandle.
//
Status = gBS->OpenProtocol (
*ChildHandle,
&gEfiIp4ProtocolGuid,
Interface,
ImageHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
//
// On failure, destroy the ip child.
//
NetLibDestroyServiceChild (
ControllerHandle,
ImageHandle,
&gEfiIp4ServiceBindingProtocolGuid,
*ChildHandle
);
}
return Status;
}
STATIC
EFI_STATUS
IpIoCloseProtocolDestroyIpChild (
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ImageHandle,
IN EFI_HANDLE ChildHandle
)
/*++
Routine Description:
This function close the previously openned ip protocol and destroy the ip child.
Arguments:
ControllerHandle - The controller handle.
ImageHandle - the image handle.
ChildHandle - The child handle of the ip child.
Returns:
EFI_SUCCESS - The ip protocol is closed and the relevant ip child is destroyed.
other - The required operation failed.
--*/
{
EFI_STATUS Status;
//
// Close the previously openned ip protocol.
//
gBS->CloseProtocol (
ChildHandle,
&gEfiIp4ProtocolGuid,
ImageHandle,
ControllerHandle
);
//
// Destroy the ip child.
//
Status = NetLibDestroyServiceChild (
ControllerHandle,
ImageHandle,
&gEfiIp4ServiceBindingProtocolGuid,
ChildHandle
);
return Status;
}
STATIC
EFI_STATUS
IpIoIcmpHandler (
IN IP_IO *IpIo,
IN NET_BUF *Pkt,
IN EFI_NET_SESSION_DATA *Session
)
/*++
Routine Description:
Handle ICMP packets.
Arguments:
IpIo - Pointer to the IP_IO instance.
Pkt - Pointer to the ICMP packet.
Session - Pointer to the net session of this ICMP packet.
Returns:
EFI_SUCCESS - The ICMP packet is handled successfully.
EFI_ABORTED - This type of ICMP packet is not supported.
--*/
{
IP4_ICMP_ERROR_HEAD *IcmpHdr;
EFI_IP4_HEADER *IpHdr;
ICMP_ERROR IcmpErr;
UINT8 *PayLoadHdr;
UINT8 Type;
UINT8 Code;
UINT32 TrimBytes;
IcmpHdr = NET_PROTO_HDR (Pkt, IP4_ICMP_ERROR_HEAD);
IpHdr = (EFI_IP4_HEADER *) (&IcmpHdr->IpHead);
//
// Check the ICMP packet length.
//
if (Pkt->TotalSize < ICMP_ERRLEN (IpHdr)) {
return EFI_ABORTED;
}
Type = IcmpHdr->Head.Type;
Code = IcmpHdr->Head.Code;
//
// Analyze the ICMP Error in this ICMP pkt
//
switch (Type) {
case ICMP_TYPE_UNREACH:
switch (Code) {
case ICMP_CODE_UNREACH_NET:
case ICMP_CODE_UNREACH_HOST:
case ICMP_CODE_UNREACH_PROTOCOL:
case ICMP_CODE_UNREACH_PORT:
case ICMP_CODE_UNREACH_SRCFAIL:
IcmpErr = ICMP_ERR_UNREACH_NET + Code;
break;
case ICMP_CODE_UNREACH_NEEDFRAG:
IcmpErr = ICMP_ERR_MSGSIZE;
break;
case ICMP_CODE_UNREACH_NET_UNKNOWN:
case ICMP_CODE_UNREACH_NET_PROHIB:
case ICMP_CODE_UNREACH_TOSNET:
IcmpErr = ICMP_ERR_UNREACH_NET;
break;
case ICMP_CODE_UNREACH_HOST_UNKNOWN:
case ICMP_CODE_UNREACH_ISOLATED:
case ICMP_CODE_UNREACH_HOST_PROHIB:
case ICMP_CODE_UNREACH_TOSHOST:
IcmpErr = ICMP_ERR_UNREACH_HOST;
break;
default:
return EFI_ABORTED;
break;
}
break;
case ICMP_TYPE_TIMXCEED:
if (Code > 1) {
return EFI_ABORTED;
}
IcmpErr = Code + ICMP_ERR_TIMXCEED_INTRANS;
break;
case ICMP_TYPE_PARAMPROB:
if (Code > 1) {
return EFI_ABORTED;
}
IcmpErr = ICMP_ERR_PARAMPROB;
break;
case ICMP_TYPE_SOURCEQUENCH:
if (Code != 0) {
return EFI_ABORTED;
}
IcmpErr = ICMP_ERR_QUENCH;
break;
default:
return EFI_ABORTED;
break;
}
//
// Notify user the ICMP pkt only containing payload except
// IP and ICMP header
//
PayLoadHdr = (UINT8 *) ((UINT8 *) IpHdr + EFI_IP4_HEADER_LEN (IpHdr));
TrimBytes = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr);
NetbufTrim (Pkt, TrimBytes, TRUE);
IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);
return EFI_SUCCESS;
}
STATIC
VOID
IpIoExtFree (
IN VOID *Event
)
/*++
Routine Description:
Ext free function for net buffer. This function is
called when the net buffer is freed. It is used to
signal the recycle event to notify IP to recycle the
data buffer.
Arguments:
Event - The event to be signaled.
Returns:
None.
--*/
{
gBS->SignalEvent ((EFI_EVENT) Event);
}
STATIC
IP_IO_SEND_ENTRY *
IpIoCreateSndEntry (
IN IP_IO *IpIo,
IN NET_BUF *Pkt,
IN EFI_IP4_PROTOCOL *Sender,
IN VOID *Context OPTIONAL,
IN VOID *NotifyData OPTIONAL,
IN IP4_ADDR Dest,
IN IP_IO_OVERRIDE *Override
)
/*++
Routine Description:
Create a send entry to wrap a packet before sending
out it through IP.
Arguments:
IpIo - Pointer to the IP_IO instance.
Pkt - Pointer to the packet.
Sender - Pointer to the IP sender.
NotifyData - Pointer to the notify data.
Dest - Pointer to the destination IP address.
Override - Pointer to the overriden IP_IO data.
Returns:
Pointer to the data structure created to wrap the packet. If NULL,
resource limit occurred.
--*/
{
IP_IO_SEND_ENTRY *SndEntry;
EFI_IP4_COMPLETION_TOKEN *SndToken;
EFI_IP4_TRANSMIT_DATA *TxData;
EFI_STATUS Status;
EFI_IP4_OVERRIDE_DATA *OverrideData;
UINT32 Index;
//
// Allocate resource for SndEntry
//
SndEntry = NetAllocatePool (sizeof (IP_IO_SEND_ENTRY));
if (NULL == SndEntry) {
return NULL;
}
//
// Allocate resource for SndToken
//
SndToken = NetAllocatePool (sizeof (EFI_IP4_COMPLETION_TOKEN));
if (NULL == SndToken) {
goto ReleaseSndEntry;
}
Status = gBS->CreateEvent (
EFI_EVENT_NOTIFY_SIGNAL,
NET_TPL_EVENT,
IpIoTransmitHandler,
SndEntry,
&(SndToken->Event)
);
if (EFI_ERROR (Status)) {
goto ReleaseSndToken;
}
//
// Allocate resource for TxData
//
TxData = NetAllocatePool (
sizeof (EFI_IP4_TRANSMIT_DATA) +
sizeof (EFI_IP4_FRAGMENT_DATA) * (Pkt->BlockOpNum - 1)
);
if (NULL == TxData) {
goto ReleaseEvent;
}
//
// Allocate resource for OverrideData if needed
//
OverrideData = NULL;
if (NULL != Override) {
OverrideData = NetAllocatePool (sizeof (EFI_IP4_OVERRIDE_DATA));
if (NULL == OverrideData) {
goto ReleaseResource;
}
//
// Set the fields of OverrideData
//
*OverrideData = *Override;
}
//
// Set the fields of TxData
//
EFI_IP4 (TxData->DestinationAddress) = Dest;
TxData->OverrideData = OverrideData;
TxData->OptionsLength = 0;
TxData->OptionsBuffer = NULL;
TxData->TotalDataLength = Pkt->TotalSize;
TxData->FragmentCount = Pkt->BlockOpNum;
for (Index = 0; Index < Pkt->BlockOpNum; Index++) {
TxData->FragmentTable[Index].FragmentBuffer = Pkt->BlockOp[Index].Head;
TxData->FragmentTable[Index].FragmentLength = Pkt->BlockOp[Index].Size;
}
//
// Set the fields of SndToken
//
SndToken->Packet.TxData = TxData;
//
// Set the fields of SndEntry
//
SndEntry->IpIo = IpIo;
SndEntry->Ip = Sender;
SndEntry->Context = Context;
SndEntry->NotifyData = NotifyData;
SndEntry->Pkt = Pkt;
NET_GET_REF (Pkt);
SndEntry->SndToken = SndToken;
NetListInsertTail (&IpIo->PendingSndList, &SndEntry->Entry);
return SndEntry;
ReleaseResource:
NetFreePool (TxData);
ReleaseEvent:
gBS->CloseEvent (SndToken->Event);
ReleaseSndToken:
NetFreePool (SndToken);
ReleaseSndEntry:
NetFreePool (SndEntry);
return NULL;
}
STATIC
VOID
IpIoDestroySndEntry (
IN IP_IO_SEND_ENTRY *SndEntry
)
/*++
Routine Description:
Destroy the SndEntry.
Arguments:
SndEntry - Pointer to the send entry to be destroyed.
Returns:
None.
--*/
{
EFI_IP4_TRANSMIT_DATA *TxData;
TxData = SndEntry->SndToken->Packet.TxData;
if (NULL != TxData->OverrideData) {
NetFreePool (TxData->OverrideData);
}
NetFreePool (TxData);
NetbufFree (SndEntry->Pkt);
gBS->CloseEvent (SndEntry->SndToken->Event);
NetFreePool (SndEntry->SndToken);
NetListRemoveEntry (&SndEntry->Entry);
NetFreePool (SndEntry);
}
STATIC
VOID
EFIAPI
IpIoTransmitHandler (
IN EFI_EVENT Event,
IN VOID *Context
)
/*++
Routine Description:
Notify function for IP transmit token.
Arguments:
Event - The event signaled.
Context - The context passed in by the event notifier.
Returns:
None.
--*/
{
IP_IO *IpIo;
IP_IO_SEND_ENTRY *SndEntry;
SndEntry = (IP_IO_SEND_ENTRY *) Context;
IpIo = SndEntry->IpIo;
if (IpIo->PktSentNotify && SndEntry->NotifyData) {
IpIo->PktSentNotify (
SndEntry->SndToken->Status,
SndEntry->Context,
SndEntry->Ip,
SndEntry->NotifyData
);
}
IpIoDestroySndEntry (SndEntry);
}
STATIC
VOID
EFIAPI
IpIoDummyHandler (
IN EFI_EVENT Event,
IN VOID *Context
)
/*++
Routine Description:
The dummy handler for the dummy IP receive token.
Arguments:
Evt - The event signaled.
Context - The context passed in by the event notifier.
Returns:
None.
--*/
{
IP_IO_IP_INFO *IpInfo;
EFI_IP4_COMPLETION_TOKEN *DummyToken;
ASSERT (Event && Context);
IpInfo = (IP_IO_IP_INFO *) Context;
DummyToken = &(IpInfo->DummyRcvToken);
if (EFI_SUCCESS == DummyToken->Status) {
ASSERT (DummyToken->Packet.RxData);
gBS->SignalEvent (DummyToken->Packet.RxData->RecycleSignal);
}
IpInfo->Ip->Receive (IpInfo->Ip, DummyToken);
}
STATIC
VOID
EFIAPI
IpIoListenHandler (
IN EFI_EVENT Event,
IN VOID *Context
)
/*++
Routine Description:
Notify function for the IP receive token, used to process
the received IP packets.
Arguments:
Event - The event signaled.
Context - The context passed in by the event notifier.
Returns:
None.
--*/
{
IP_IO *IpIo;
EFI_STATUS Status;
EFI_IP4_RECEIVE_DATA *RxData;
EFI_IP4_PROTOCOL *Ip;
EFI_NET_SESSION_DATA Session;
NET_BUF *Pkt;
IpIo = (IP_IO *) Context;
Ip = IpIo->Ip;
Status = IpIo->RcvToken.Status;
RxData = IpIo->RcvToken.Packet.RxData;
if (((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) || (NULL == RxData)) {
//
// Only process the normal packets and the icmp error packets, if RxData is NULL
// with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although
// this should be a bug of the low layer (IP).
//
goto Resume;
}
if (NULL == IpIo->PktRcvdNotify) {
goto CleanUp;
}
if ((EFI_IP4 (RxData->Header->SourceAddress) != 0) &&
!Ip4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) {
//
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?