arpimpl.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,698 行 · 第 1/3 页
C
1,698 行
/*++
Copyright (c) 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:
ArpImpl.c
Abstract:
--*/
#include "ArpImpl.h"
#include "ArpDebug.h"
EFI_ARP_PROTOCOL mEfiArpProtocolTemplate = {
ArpConfigure,
ArpAdd,
ArpFind,
ArpDelete,
ArpFlush,
ArpRequest,
ArpCancel
};
VOID
ArpInitInstance (
IN ARP_SERVICE_DATA *ArpService,
IN ARP_INSTANCE_DATA *Instance
)
/*++
Routine Description:
Initialize the instance context data.
Arguments:
ArpService - Pointer to the arp service context data this instance belongs to.
Instance - Pointer to the instance context data.
Returns:
None.
--*/
{
NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);
Instance->Signature = ARP_INSTANCE_DATA_SIGNATURE;
Instance->ArpService = ArpService;
Instance->ArpProto = mEfiArpProtocolTemplate;
Instance->Configured = FALSE;
Instance->Destroyed = FALSE;
NetListInit (&Instance->List);
}
VOID
EFIAPI
ArpOnFrameRcvd (
IN EFI_EVENT Event,
IN VOID *Context
)
/*++
Routine Description:
Process the Arp packets received from Mnp, the procedure conforms to RFC826.
Arguments:
Event - The Event this notify function registered to.
Context - Pointer to the context data registerd to the Event.
Returns:
None.
--*/
{
EFI_STATUS Status;
ARP_SERVICE_DATA *ArpService;
EFI_MANAGED_NETWORK_COMPLETION_TOKEN *RxToken;
EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData;
ARP_HEAD *Head;
ARP_ADDRESS ArpAddress;
ARP_CACHE_ENTRY *CacheEntry;
NET_LIST_ENTRY *Entry;
ARP_INSTANCE_DATA *Instance;
EFI_ARP_CONFIG_DATA *ConfigData;
NET_ARP_ADDRESS SenderAddress[2];
BOOLEAN ProtoMatched;
BOOLEAN IsTarget;
BOOLEAN MergeFlag;
ArpService = (ARP_SERVICE_DATA *)Context;
NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);
RxToken = &ArpService->RxToken;
if (RxToken->Status == EFI_ABORTED) {
//
// The Token is aborted, possibly by arp itself, just return and the receiving
// process is stopped.
//
return;
}
if (EFI_ERROR (RxToken->Status)) {
//
// Restart the receiving if any other error Status occurs.
//
goto RESTART_RECEIVE;
}
//
// Status is EFI_SUCCESS, process the received frame.
//
RxData = RxToken->Packet.RxData;
Head = (ARP_HEAD *) RxData->PacketData;
//
// Convert the byte order of the multi-byte fields.
//
Head->HwType = NTOHS (Head->HwType);
Head->ProtoType = NTOHS (Head->ProtoType);
Head->OpCode = NTOHS (Head->OpCode);
if ((Head->HwType != ArpService->SnpMode.IfType) ||
(Head->HwAddrLen != ArpService->SnpMode.HwAddressSize) ||
(RxData->ProtocolType != ARP_ETHER_PROTO_TYPE)) {
//
// The hardware type or the hardware address length doesn't match.
// There is a sanity check for the protocol type too.
//
goto RECYCLE_RXDATA;
}
//
// Set the pointers to the addresses contained in the arp packet.
//
ArpAddress.SenderHwAddr = (UINT8 *)(Head + 1);
ArpAddress.SenderProtoAddr = ArpAddress.SenderHwAddr + Head->HwAddrLen;
ArpAddress.TargetHwAddr = ArpAddress.SenderProtoAddr + Head->ProtoAddrLen;
ArpAddress.TargetProtoAddr = ArpAddress.TargetHwAddr + Head->HwAddrLen;
if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {
ARP_DEBUG_ERROR (("ArpOnFrameRcvd: Faild to acquire the CacheTableLock.\n"));
goto RECYCLE_RXDATA;
}
SenderAddress[Hardware].Type = Head->HwType;
SenderAddress[Hardware].Length = Head->HwAddrLen;
SenderAddress[Hardware].AddressPtr = ArpAddress.SenderHwAddr;
SenderAddress[Protocol].Type = Head->ProtoType;
SenderAddress[Protocol].Length = Head->ProtoAddrLen;
SenderAddress[Protocol].AddressPtr = ArpAddress.SenderProtoAddr;
//
// First, check the denied cache table.
//
CacheEntry = ArpFindDeniedCacheEntry (
ArpService,
&SenderAddress[Protocol],
&SenderAddress[Hardware]
);
if (CacheEntry != NULL) {
//
// This address (either hardware or protocol address, or both) is configured to
// be a deny entry, silently skip the normal process.
//
goto UNLOCK_EXIT;
}
ProtoMatched = FALSE;
IsTarget = FALSE;
Instance = NULL;
NET_LIST_FOR_EACH (Entry, &ArpService->ChildrenList) {
//
// Iterate all the children.
//
Instance = NET_LIST_USER_STRUCT (Entry, ARP_INSTANCE_DATA, List);
NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);
ConfigData = &Instance->ConfigData;
if ((Instance->Configured) &&
(Head->ProtoType == ConfigData->SwAddressType) &&
(Head->ProtoAddrLen == ConfigData->SwAddressLength)) {
//
// The protocol type is matched for the received arp packet.
//
ProtoMatched = TRUE;
if (0 == NetCompareMem (
(VOID *)ArpAddress.TargetProtoAddr,
ConfigData->StationAddress,
ConfigData->SwAddressLength
)) {
//
// The arp driver has the target address required by the received arp packet.
//
IsTarget = TRUE;
break;
}
}
}
if (!ProtoMatched) {
//
// Protocol type unmatchable, skip.
//
goto UNLOCK_EXIT;
}
//
// Check whether the sender's address information is already in the cache.
//
MergeFlag = FALSE;
CacheEntry = ArpFindNextCacheEntryInTable (
&ArpService->ResolvedCacheTable,
NULL,
ByProtoAddress,
&SenderAddress[Protocol],
NULL
);
if (CacheEntry != NULL) {
//
// Update the entry with the new information.
//
ArpFillAddressInCacheEntry (CacheEntry, &SenderAddress[Hardware], NULL);
CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;
MergeFlag = TRUE;
}
if (!IsTarget) {
//
// This arp packet isn't targeted to us, skip now.
//
goto UNLOCK_EXIT;
}
if (!MergeFlag) {
//
// Add the triplet <protocol type, sender protocol address, sender hardware address>
// to the translation table.
//
CacheEntry = ArpFindNextCacheEntryInTable (
&ArpService->PendingRequestTable,
NULL,
ByProtoAddress,
&SenderAddress[Protocol],
NULL
);
if (CacheEntry == NULL) {
//
// Allocate a new CacheEntry.
//
CacheEntry = ArpAllocCacheEntry (NULL);
if (CacheEntry == NULL) {
goto UNLOCK_EXIT;
}
}
NetListRemoveEntry (&CacheEntry->List);
//
// Fill the addresses into the CacheEntry.
//
ArpFillAddressInCacheEntry (
CacheEntry,
&SenderAddress[Hardware],
&SenderAddress[Protocol]
);
//
// Inform the user.
//
ArpAddressResolved (CacheEntry, NULL, NULL);
//
// Add this entry into the ResolvedCacheTable
//
NetListInsertHead (&ArpService->ResolvedCacheTable, &CacheEntry->List);
}
if (Head->OpCode == ARP_OPCODE_REQUEST) {
//
// Send back the ARP Reply. If we reach here, Instance is not NULL and CacheEntry
// is not NULL.
//
ArpSendFrame (Instance, CacheEntry, ARP_OPCODE_REPLY);
}
UNLOCK_EXIT:
NET_UNLOCK (&ArpService->Lock);
RECYCLE_RXDATA:
//
// Signal Mnp to recycle the RxData.
//
gBS->SignalEvent (RxData->RecycleEvent);
RESTART_RECEIVE:
//
// Continue to receive packets from Mnp.
//
Status = ArpService->Mnp->Receive (ArpService->Mnp, RxToken);
DEBUG_CODE (
if (EFI_ERROR (Status)) {
ARP_DEBUG_ERROR (("ArpOnFrameRcvd: ArpService->Mnp->Receive "
"failed, %r\n.", Status));
}
);
}
VOID
EFIAPI
ArpOnFrameSent (
IN EFI_EVENT Event,
IN VOID *Context
)
/*++
Routine Description:
Process the already sent arp packets.
Arguments:
Event - The Event this notify function registered to.
Context - Pointer to the context data registerd to the Event.
Returns:
None.
--*/
{
EFI_MANAGED_NETWORK_COMPLETION_TOKEN *TxToken;
EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;
ASSERT (Context != NULL);
TxToken = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *)Context;
TxData = TxToken->Packet.TxData;
DEBUG_CODE (
if (EFI_ERROR (TxToken->Status)) {
ARP_DEBUG_ERROR (("ArpOnFrameSent: TxToken->Status, %r.\n", TxToken->Status));
}
);
//
// Free the allocated memory and close the event.
//
NetFreePool (TxData->FragmentTable[0].FragmentBuffer);
NetFreePool (TxData);
gBS->CloseEvent (TxToken->Event);
NetFreePool (TxToken);
}
VOID
EFIAPI
ArpTimerHandler (
IN EFI_EVENT Event,
IN VOID *Context
)
/*++
Routine Description:
Process the arp cache olding and drive the retrying arp requests.
Arguments:
Event - The Event this notify function registered to.
Context - Pointer to the context data registerd to the Event.
Returns:
None.
--*/
{
ARP_SERVICE_DATA *ArpService;
NET_LIST_ENTRY *Entry;
NET_LIST_ENTRY *NextEntry;
NET_LIST_ENTRY *ContextEntry;
ARP_CACHE_ENTRY *CacheEntry;
USER_REQUEST_CONTEXT *RequestContext;
ASSERT (Context != NULL);
ArpService = (ARP_SERVICE_DATA *)Context;
if (EFI_ERROR (NET_TRYLOCK (&ArpService->Lock))) {
return;
}
//
// Iterate all the pending requests to see whether a retry is needed to send out
// or the request finally fails because the retry time reaches the limitation.
//
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->PendingRequestTable) {
CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
if (CacheEntry->NextRetryTime <= ARP_PERIODIC_TIMER_INTERVAL) {
//
// Timeout, if we can retry more, send out the request again, otherwise abort
// this request.
//
if (CacheEntry->RetryCount == 0) {
//
// Abort this request.
//
ArpAddressResolved (CacheEntry, NULL, NULL);
ASSERT (NetListIsEmpty (&CacheEntry->UserRequestList));
NetListRemoveEntry (&CacheEntry->List);
NetFreePool (CacheEntry);
} else {
//
// resend the ARP request.
//
ASSERT (!NetListIsEmpty(&CacheEntry->UserRequestList));
ContextEntry = CacheEntry->UserRequestList.ForwardLink;
RequestContext = NET_LIST_USER_STRUCT (ContextEntry, USER_REQUEST_CONTEXT, List);
ArpSendFrame (RequestContext->Instance, CacheEntry, ARP_OPCODE_REQUEST);
CacheEntry->RetryCount--;
CacheEntry->NextRetryTime = RequestContext->Instance->ConfigData.RetryTimeOut;
}
} else {
//
// Update the NextRetryTime.
//
CacheEntry->NextRetryTime -= ARP_PERIODIC_TIMER_INTERVAL;
}
}
//
// Check the timeouts for the DeniedCacheTable.
//
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->DeniedCacheTable) {
CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
ASSERT (NetListIsEmpty (&CacheEntry->UserRequestList));
if (CacheEntry->DefaultDecayTime == 0) {
//
// It's a static entry, skip it.
//
continue;
}
if (CacheEntry->DecayTime <= ARP_PERIODIC_TIMER_INTERVAL) {
//
// Time out, remove it.
//
NetListRemoveEntry (&CacheEntry->List);
NetFreePool (CacheEntry);
} else {
//
// Update the DecayTime.
//
CacheEntry->DecayTime -= ARP_PERIODIC_TIMER_INTERVAL;
}
}
//
// Check the timeouts for the ResolvedCacheTable.
//
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->ResolvedCacheTable) {
CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
ASSERT (NetListIsEmpty (&CacheEntry->UserRequestList));
if (CacheEntry->DefaultDecayTime == 0) {
//
// It's a static entry, skip it.
//
continue;
}
if (CacheEntry->DecayTime <= ARP_PERIODIC_TIMER_INTERVAL) {
//
// Time out, remove it.
//
NetListRemoveEntry (&CacheEntry->List);
NetFreePool (CacheEntry);
} else {
//
// Update the DecayTime.
//
CacheEntry->DecayTime -= ARP_PERIODIC_TIMER_INTERVAL;
}
}
NET_UNLOCK (&ArpService->Lock);
}
STATIC
BOOLEAN
ArpMatchAddress (
IN NET_ARP_ADDRESS *AddressOne,
IN NET_ARP_ADDRESS *AddressTwo
)
/*++
Routine Description:
Match the two NET_ARP_ADDRESSes.
Arguments:
AddressOne - Pointer to the first address to match.
AddressTwo - Pointer to the second address to match.
Returns:
The two addresses match or not.
--*/
{
if ((AddressOne->Type != AddressTwo->Type) ||
(AddressOne->Length != AddressTwo->Length)) {
//
// Either Type or Length doesn't match.
//
return FALSE;
}
if ((AddressOne->AddressPtr != NULL) &&
(NetCompareMem (
AddressOne->AddressPtr,
AddressTwo->AddressPtr,
AddressOne->Length
) != 0)) {
//
// The address is not the same.
//
return FALSE;
}
return TRUE;
}
ARP_CACHE_ENTRY *
ArpFindNextCacheEntryInTable (
IN NET_LIST_ENTRY *CacheTable,
IN NET_LIST_ENTRY *StartEntry,
IN FIND_OPTYPE FindOpType,
IN NET_ARP_ADDRESS *ProtocolAddress OPTIONAL,
IN NET_ARP_ADDRESS *HardwareAddress OPTIONAL
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?