ip4if.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,274 行 · 第 1/3 页
C
1,274 行
IP4_INTERFACE *Interface;
IP4_LINK_TX_TOKEN *Token;
EFI_STATUS Status;
EFI_TPL OldTpl;
ArpQue = (IP4_ARP_QUE *) Context;
NET_CHECK_SIGNATURE (ArpQue, IP4_FRAME_ARP_SIGNATURE);
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
NetListRemoveEntry (&ArpQue->Link);
//
// ARP resolve failed for some reason. Release all the frame
// and ARP queue itself. Ip4FreeArpQue will call the frame's
// owner back.
//
if (NET_MAC_EQUAL (&ArpQue->Mac, &mZeroMacAddress, ArpQue->Interface->HwaddrLen)) {
Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);
NET_RESTORE_TPL (OldTpl);
return ;
}
//
// ARP resolve succeeded, Transmit all the frame. Release the ARP
// queue. It isn't necessary for us to cache the ARP binding because
// we always check the ARP cache first before transmit.
//
Interface = ArpQue->Interface;
NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
NetListRemoveEntry (Entry);
Token = NET_LIST_USER_STRUCT (Entry, IP4_LINK_TX_TOKEN, Link);
Token->DstMac = ArpQue->Mac;
Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
if (EFI_ERROR (Status)) {
Token->CallBack (Token->IpInstance, Token->Packet, Status, 0, Token->Context);
Ip4FreeLinkTxToken (Token);
continue;
}
NetListInsertTail (&Interface->SentFrames, &Token->Link);
}
Ip4FreeArpQue (ArpQue, EFI_SUCCESS);
NET_RESTORE_TPL (OldTpl);
}
STATIC
VOID
EFIAPI
Ip4OnFrameSent (
IN EFI_EVENT Event,
IN VOID *Context
)
/*++
Routine Description:
Callback funtion when frame transmission is finished. It will
call the frame owner's callback function to tell it the result.
Arguments:
Event - The transmit token's event
Context - Context which is point to the token.
Returns:
None.
--*/
{
IP4_LINK_TX_TOKEN *Token;
EFI_TPL OldTpl;
Token = (IP4_LINK_TX_TOKEN *) Context;
NET_CHECK_SIGNATURE (Token, IP4_FRAME_TX_SIGNATURE);
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
NetListRemoveEntry (&Token->Link);
Token->CallBack (
Token->IpInstance,
Token->Packet,
Token->MnpToken.Status,
0,
Token->Context
);
Ip4FreeLinkTxToken (Token);
NET_RESTORE_TPL (OldTpl);
}
EFI_STATUS
Ip4SendFrame (
IN IP4_INTERFACE *Interface,
IN IP4_PROTOCOL *IpInstance, OPTIONAL
IN NET_BUF *Packet,
IN IP4_ADDR NextHop,
IN IP4_FRAME_CALLBACK CallBack,
IN VOID *Context
)
/*++
Routine Description:
Send a frame from the interface. If the next hop is broadcast or
multicast address, it is transmitted immediately. If the next hop
is a unicast, it will consult ARP to resolve the NextHop's MAC.
If some error happened, the CallBack won't be called. So, the caller
must test the return value, and take action when there is an error.
Arguments:
Interface - The interface to send the frame from
IpInstance - The IP child that request the transmission.
NULL if it is the IP4 driver itself.
Packet - The packet to transmit.
NextHop - The immediate destination to transmit the packet to.
CallBack - Function to call back when transmit finished.
Context - Opaque parameter to the call back.
Returns:
EFI_OUT_OF_RESOURCES - Failed to allocate resource to send the frame
EFI_NO_MAPPING - Can't resolve the MAC for the nexthop
EFI_SUCCESS - The packet is successfully transmitted.
--*/
{
IP4_LINK_TX_TOKEN *Token;
NET_LIST_ENTRY *Entry;
IP4_ARP_QUE *ArpQue;
EFI_ARP_PROTOCOL *Arp;
EFI_STATUS Status;
ASSERT (Interface->Configured);
Token = Ip4WrapLinkTxToken (Interface, IpInstance, Packet, CallBack, Context);
if (Token == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Get the destination MAC address for multicast and broadcasts.
// Don't depend on ARP to solve the address since there maybe no
// ARP at all. Ip4Output has set NextHop to 255.255.255.255 for
// all the broadcasts.
//
if (NextHop == IP4_ALLONE_ADDRESS) {
Token->DstMac = Interface->BroadcastMac;
goto SEND_NOW;
} else if (IP4_IS_MULTICAST (NextHop)) {
Status = Ip4GetMulticastMac (Interface->Mnp, NextHop, &Token->DstMac);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
goto SEND_NOW;
}
//
// Can only send out multicast/broadcast if the IP address is zero
//
if ((Arp = Interface->Arp) == NULL) {
Status = EFI_NO_MAPPING;
goto ON_ERROR;
}
//
// First check whether this binding is in the ARP cache.
//
NextHop = HTONL (NextHop);
Status = Arp->Request (Arp, &NextHop, NULL, &Token->DstMac);
if (Status == EFI_SUCCESS) {
goto SEND_NOW;
} else if (Status != EFI_NOT_READY) {
goto ON_ERROR;
}
//
// Have to do asynchronous ARP resolution. First check
// whether there is already a pending request.
//
ArpQue = NULL;
NET_LIST_FOR_EACH (Entry, &Interface->ArpQues) {
ArpQue = NET_LIST_USER_STRUCT (Entry, IP4_ARP_QUE, Link);
if (ArpQue->Ip == NextHop) {
break;
}
}
//
// Found a pending ARP request, enqueue the frame then return
//
if (Entry != &Interface->ArpQues) {
NetListInsertTail (&ArpQue->Frames, &Token->Link);
return EFI_SUCCESS;
}
//
// First frame to NextHop, issue an asynchronous ARP requests
//
ArpQue = Ip4CreateArpQue (Interface, NextHop);
if (ArpQue == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_ERROR;
}
Status = Arp->Request (Arp, &ArpQue->Ip, ArpQue->OnResolved, ArpQue->Mac.Addr);
if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) {
Ip4FreeArpQue (ArpQue, EFI_NO_MAPPING);
goto ON_ERROR;
}
NetListInsertHead (&ArpQue->Frames, &Token->Link);
NetListInsertHead (&Interface->ArpQues, &ArpQue->Link);
return EFI_SUCCESS;
SEND_NOW:
Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
NetListInsertTail (&Interface->SentFrames, &Token->Link);
return EFI_SUCCESS;
ON_ERROR:
Ip4FreeLinkTxToken (Token);
return Status;
}
STATIC
VOID
Ip4RecycleFrame (
IN VOID *Context
)
/*++
Routine Description:
Call back function when the received packet is freed.
Check Ip4OnFrameReceived for information.
Arguments:
Context - Context, which is the IP4_LINK_RX_TOKEN.
Returns:
None.
--*/
{
IP4_LINK_RX_TOKEN *Frame;
Frame = (IP4_LINK_RX_TOKEN *) Context;
NET_CHECK_SIGNATURE (Frame, IP4_FRAME_RX_SIGNATURE);
gBS->SignalEvent (Frame->MnpToken.Packet.RxData->RecycleEvent);
Ip4FreeFrameRxToken (Frame);
}
STATIC
VOID
EFIAPI
Ip4OnFrameReceived (
IN EFI_EVENT Event,
IN VOID *Context
)
/*++
Routine Description:
Received a frame from MNP, wrap it in net buffer then deliver
it to IP's input function. The ownship of the packet also
transferred to IP. When Ip is finished with this packet, it
will call NetbufFree to release the packet, NetbufFree will
again call the Ip4RecycleFrame to signal MNP's event and free
the token used.
Arguments:
Event - The receive event delivered to MNP for receive.
Context - Context for the callback.
Returns:
None.
--*/
{
EFI_MANAGED_NETWORK_COMPLETION_TOKEN *MnpToken;
EFI_MANAGED_NETWORK_RECEIVE_DATA *MnpRxData;
IP4_LINK_RX_TOKEN *Token;
NET_FRAGMENT Netfrag;
NET_BUF *Packet;
EFI_TPL OldTpl;
UINT32 Flag;
Token = (IP4_LINK_RX_TOKEN *) Context;
NET_CHECK_SIGNATURE (Token, IP4_FRAME_RX_SIGNATURE);
OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
//
// First clear the interface's receive request in case the
// caller wants to call Ip4ReceiveFrame in the callback.
//
Token->Interface->RecvRequest = NULL;
MnpToken = &Token->MnpToken;
MnpRxData = MnpToken->Packet.RxData;
if (EFI_ERROR (MnpToken->Status) || (MnpRxData == NULL)) {
Token->CallBack (Token->IpInstance, NULL, MnpToken->Status, 0, Token->Context);
Ip4FreeFrameRxToken (Token);
NET_RESTORE_TPL (OldTpl);
return ;
}
//
// Wrap the frame in a net buffer then deliever it to IP input.
// IP will reassemble the packet, and deliver it to upper layer
//
Netfrag.Len = MnpRxData->DataLength;
Netfrag.Bulk = MnpRxData->PacketData;
Packet = NetbufFromExt (&Netfrag, 1, 0, IP4_MAX_HEADLEN, Ip4RecycleFrame, Token);
if (Packet == NULL) {
gBS->SignalEvent (MnpRxData->RecycleEvent);
Token->CallBack (Token->IpInstance, NULL, EFI_OUT_OF_RESOURCES, 0, Token->Context);
Ip4FreeFrameRxToken (Token);
NET_RESTORE_TPL (OldTpl);
return ;
}
Flag = (MnpRxData->BroadcastFlag ? IP4_LINK_BROADCAST : 0);
Flag |= (MnpRxData->MulticastFlag ? IP4_LINK_MULTICAST : 0);
Flag |= (MnpRxData->PromiscuousFlag ? IP4_LINK_PROMISC : 0);
Token->CallBack (Token->IpInstance, Packet, EFI_SUCCESS, Flag, Token->Context);
NET_RESTORE_TPL (OldTpl);
}
EFI_STATUS
Ip4ReceiveFrame (
IN IP4_INTERFACE *Interface,
IN IP4_PROTOCOL *IpInstance, OPTIONAL
IN IP4_FRAME_CALLBACK CallBack,
IN VOID *Context
)
/*++
Routine Description:
Request to receive the packet from the interface.
Arguments:
Interface - The interface to receive the frames from
IpInstance - The instance that requests the receive. NULL for the driver itself.
CallBack - Function to call when receive finished.
Context - Opaque parameter to the callback
Returns:
EFI_ALREADY_STARTED - There is already a pending receive request.
EFI_OUT_OF_RESOURCES - Failed to allocate resource to receive
EFI_SUCCESS - The recieve request has been started.
--*/
{
IP4_LINK_RX_TOKEN *Token;
EFI_STATUS Status;
NET_CHECK_SIGNATURE (Interface, IP4_INTERFACE_SIGNATURE);
if (Interface->RecvRequest != NULL) {
return EFI_ALREADY_STARTED;
}
Token = Ip4CreateLinkRxToken (Interface, IpInstance, CallBack, Context);
if (Token == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = Interface->Mnp->Receive (Interface->Mnp, &Token->MnpToken);
if (EFI_ERROR (Status)) {
Ip4FreeFrameRxToken (Token);
return Status;
}
Interface->RecvRequest = Token;
return EFI_SUCCESS;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?