【UEFI基础】UEFI网络框架之ARP

说明

之前讲的MNP和SNP,以及UNDI并不是我们常见的网络协议,它们应该是UEFI下特有的,链接如下:

【UEFI基础】UEFI网络框架之UNDI

【UEFI基础】UEFI网络框架之SNP

【UEFI基础】UEFI网络框架之MNP

而接下去讲的内容,就是普通的网络协议了。

首先是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. ImageHandleControllerHandle:就是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. ChildrenNumberChildrenList:用来管理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. DeniedCacheTableResolvedCacheTable:存放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略):

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值