说明
之前讲的MNP和SNP,以及UNDI并不是我们常见的网络协议,它们应该是UEFI下特有的,链接如下:
而接下去讲的内容,就是普通的网络协议了。
首先是ARP。
ARP
ARP全称Address Resolution Protocol。
ARP的作用是以目标IP地址为线索,用来定位下一个应该接受数据分包的网络设备对应的MAC地址。如果目标主机不在同一个链路上时,可以通过ARP查找下一跳路由器的MAC地址。
注意ARP只适用于IPv4,不能用于IPv6。
ARP的初始化也比较简单,它主要做了以下的事情:
1. 通过ArpCreateService()函数初始化ARP_SERVICE_DATA结构体;
2. 安装gEfiArpServiceBindingProtocolGuid对应的Protocol;
3. 执行该ARP对应的MNP中的Receive()函数;
这里需要说明几点:
1. 同MNP一样(事实上就是因为ARP需要对应到MNP的缘故),ARP也有对应的EFI_SERVICE_BINDING_PROTOCOL;这里的对应关系是,一个Vlan对应一个MNP_SERVICE_DATA结构体对应一个ARP_SERVICE_DATA结构体;
2. ARP初始化的时候调用了MNP的Receive()函数:
Status = ArpService->Mnp->Receive (ArpService->Mnp, &ArpService->RxToken);
对于这个Receive()函数,代码中有如下的声明:
/**
Places an asynchronous receiving request into the receiving queue.
The Receive() function places a completion token into the receive packet
queue. This function is always asynchronous.
The caller must fill in the Token.Event field in the completion token, and
this field cannot be NULL. When the receive operation completes, the MNP
updates the Token.Status and Token.RxData fields and the Token.Event is
signaled.
**/
注意这里的非同步。Receive()的主要代码如下:
//
// Check whether this token(event) is already in the rx token queue.
//
Status = NetMapIterate (&Instance->RxTokenMap, MnpTokenExist, (VOID *) Token);
if (EFI_ERROR (Status)) {
goto ON_EXIT;
}
//
// Insert the Token into the RxTokenMap.
//
Status = NetMapInsertTail (&Instance->RxTokenMap, (VOID *) Token, NULL);
if (!EFI_ERROR (Status)) {
//
// Try to deliver any buffered packets.
//
Status = MnpInstanceDeliverPacket (Instance);
//
// Dispatch the DPC queued by the NotifyFunction of Token->Event.
//
DispatchDpc ();
}
实际上就是ARP注册了一个回调函数到MNP中,MNP接受数据后会回调这个注册的函数。
这里虽然说是回调函数,其实还是要复杂一些的,具体的结构体如下:
typedef struct {
///
/// This Event will be signaled after the Status field is updated
/// by the MNP. The type of Event must be
/// EFI_NOTIFY_SIGNAL. The Task Priority Level (TPL) of
/// Event must be lower than or equal to TPL_CALLBACK.
///
EFI_EVENT Event;
///
/// The status that is returned to the caller at the end of the operation
/// to indicate whether this operation completed successfully.
///
EFI_STATUS Status;
union {
///
/// When this token is used for receiving, RxData is a pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.
///
EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData;
///
/// When this token is used for transmitting, TxData is a pointer to the EFI_MANAGED_NETWORK_TRANSMIT_DATA.
///
EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;
} Packet;
} EFI_MANAGED_NETWORK_COMPLETION_TOKEN;
它包含了回调的函数,状态和数据等内容。
ARP_SERVICE_DATA结构体中有这个结构体,并会在ArpCreateService()中初始化(主要是初始化回调事件)。
下面就是介绍ARP_SERVICE_DATA这个结构体。
ARP_SERVICE_DATA Structure
ARP_SERVICE_DATA定义在ArpImpl.h文件中,如下所示:
struct _ARP_SERVICE_DATA {
UINT32 Signature;
EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
EFI_HANDLE MnpChildHandle;
EFI_HANDLE ImageHandle;
EFI_HANDLE ControllerHandle;
EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
EFI_MANAGED_NETWORK_CONFIG_DATA MnpConfigData;
EFI_MANAGED_NETWORK_COMPLETION_TOKEN RxToken;
EFI_SIMPLE_NETWORK_MODE SnpMode;
UINTN ChildrenNumber;
LIST_ENTRY ChildrenList;
LIST_ENTRY PendingRequestTable;
LIST_ENTRY DeniedCacheTable;
LIST_ENTRY ResolvedCacheTable;
EFI_EVENT PeriodicTimer;
};
这些成员介绍如下:
1. Signature:它的值是SIGNATURE_32('A', 'R', 'P', 'S');
2. ServiceBinding:就是ARP对应的Service Binding Protocol;
3. MnpChildHandle:通过ManagedNetworkServiceBindingProtocol->CreateChild()创建的子Handle;
4. ImageHandle、ControllerHandle:就是Driver Binding Protocol对应的两个Handle;
5. Mnp:对应的MNP;
6. MnpConfigData:调用MNP的Configure()函数时需要使用的参数,具体的值如下:
//
// Set the Mnp config parameters.
//
ArpService->MnpConfigData.ReceivedQueueTimeoutValue = 0;
ArpService->MnpConfigData.TransmitQueueTimeoutValue = 0;
ArpService->MnpConfigData.ProtocolTypeFilter = ARP_ETHER_PROTO_TYPE;
ArpService->MnpConfigData.EnableUnicastReceive = TRUE;
ArpService->MnpConfigData.EnableMulticastReceive = FALSE;
ArpService->MnpConfigData.EnableBroadcastReceive = TRUE;
ArpService->MnpConfigData.EnablePromiscuousReceive = FALSE;
ArpService->MnpConfigData.FlushQueuesOnReset = TRUE;
ArpService->MnpConfigData.EnableReceiveTimestamps = FALSE;
ArpService->MnpConfigData.DisableBackgroundPolling = FALSE;
7. RxToken:这个就是之前提到的用于回调的结构体;
8. SnpMode:通过Mnp->GetModeData()获取到的参数,就是初始化SNP时使用的EFI_SIMPLE_NETWORK_MODE结构体;
9. ChildrenNumber、ChildrenList:用来管理ArpServiceBindingProtocol创建的子项,同MNP类似,也会有一个ARP_INSTANCE_DATA与之对应;
10. PendingRequestTable:参考代码中的说明:
//
// 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.
//
11. DeniedCacheTable、ResolvedCacheTable:存放IP-MAC对,并管理其它相关的参数;
12. PeriodicTimer:ARP初始化好后会周期的运行,一个是检查IP-MAC对是否超时,一个是检查发送的ARP是否还需要再次发送;
关于PeriodicTimer可以参考函数ArpTimerHandler(),它其实就是在处理上述的11/12中的成员。
因为ARP与MNP结构体类似,也有一个ServiceBindingProtocol,所以也会有CreateChild()和DestroyChild()这两个函数,且在CreateChild()中会初始化ARP_INSTANCE_DATA和安装gEfiArpProtocolGuid对应的Protocol。这里不再详细说明了。
ARP Interface
ARP提供的接口如下:
struct _EFI_ARP_PROTOCOL {
EFI_ARP_CONFIGURE Configure;
EFI_ARP_ADD Add;
EFI_ARP_FIND Find;
EFI_ARP_DELETE Delete;
EFI_ARP_FLUSH Flush;
EFI_ARP_REQUEST Request;
EFI_ARP_CANCEL Cancel;
};
ARP提供的接口还是比较简单的,主要就是IP-MAC对的一个管理。
最后的说明,在ARP被初始化之后,就有定时器开始跑起来了,就是前面提到的ArpTimerHandler()函数会周期运行:
//
// Create the Arp heartbeat timer.
//
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL | EVT_TIMER,
TPL_CALLBACK,
ArpTimerHandler,
ArpService,
&ArpService->PeriodicTimer
);
if (EFI_ERROR (Status)) {
goto ERROR_EXIT;
}
//
// Start the heartbeat timer.
//
Status = gBS->SetTimer (
ArpService->PeriodicTimer,
TimerPeriodic,
ARP_PERIODIC_TIMER_INTERVAL
);
但是另外一个重要的回调函数:ArpService->RxToken.Event,它是用来对接受到的数据进行处理,并相应的做出反应。
比如接受到了一个ARP请求,则会发送ARP的回复,并更新之前提到的11/12成员的值。
这个回调函数要到MNP周期性接收数据后才会回调执行,这个过程是这样的:
1. 首先在ArpCreateService()函数中会调用ArpService->Mnp->Configure();
2. 在Configure()的实现中,会调用MnpConfigureInstance();
3. MnpConfigureInstance()中,当配置完成后,会调用MnpStart():
if (Instance->Configured) {
//
// The instance is configured, start the Mnp.
//
Status = MnpStart (
MnpServiceData,
IsConfigUpdate,
(BOOLEAN) !NewConfigData->DisableBackgroundPolling
);
4. 而在MnpStart()中开启了定时事件:
if (MnpDeviceData->EnableSystemPoll ^ EnableSystemPoll) {
//
// The EnableSystemPoll differs with the current state, disable or enable
// the system poll.
//
TimerOpType = EnableSystemPoll ? TimerPeriodic : TimerCancel;
Status = gBS->SetTimer (MnpDeviceData->PollTimer, TimerOpType, MNP_SYS_POLL_INTERVAL);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "MnpStart: gBS->SetTimer for PollTimer failed, %r.\n", Status));
goto ErrorExit;
}
MnpDeviceData->EnableSystemPoll = EnableSystemPoll;
}
5. 这里的MnpDeviceData->PollTimer对应的函数是MnpSystemPoll():
/**
Poll to receive the packets from Snp. This function is either called by upperlayer
protocols/applications or the system poll timer notify mechanism.
@param[in] Event The event this notify function registered to.
@param[in] Context Pointer to the context data registered to the event.
**/
VOID
EFIAPI
MnpSystemPoll (
IN EFI_EVENT Event,
IN VOID *Context
)
{
MNP_DEVICE_DATA *MnpDeviceData;
MnpDeviceData = (MNP_DEVICE_DATA *) Context;
NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);
//
// Try to receive packets from Snp.
//
MnpReceivePacket (MnpDeviceData);
//
// Dispatch the DPC queued by the NotifyFunction of rx token's events.
//
DispatchDpc ();
}
数据从这里开始接收。
接收了数据之后,ARP对应的回调结构体RxToken中的事件也就会执行了。
根据上面的说法,ARP初始化之后,就可以来接收数据,并处理ARP请求,大致的流程如下(具体怎么处理ARP略):