【UEFI基础】EDK网络框架(UDP4)

这篇具有很好参考价值的文章主要介绍了【UEFI基础】EDK网络框架(UDP4)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

UDP4

UDP4协议说明

UDP的全称是User Datagram Protocol,它不提供复杂的控制机制,仅利用IP提供面向无连接的通信服务。它将上层应用程序发来的数据在收到的那一刻,立即按照原样发送到网络。

UDP报文格式:

【UEFI基础】EDK网络框架(UDP4),UEFI开发基础,网络,uefi

各个参数说明如下:

字段 长度(字节) 描述
Source Port 2 发送端口,标识哪个应用程序发送(发送进程)。
Destination Port 2 目标端口,标识哪个应用程序接收(接收进程)。
Length 2 UDP首部加上UDP数据的字节数,最小为8。
Checksum 2 覆盖UDP首部和UDP数据,是可选的。
data octets 变长 UDP负载,可选的。

前面的四个参数对应到UEFI代码中就是UDP头部:

//
// UDP header definition
//
typedef struct {
  UINT16    SrcPort;
  UINT16    DstPort;
  UINT16    Length;
  UINT16    Checksum;
} EFI_UDP_HEADER;

UDP4代码综述

UDP4也是一个通用的网络协议,其实现在NetworkPkg\Udp4Dxe\Udp4Dxe.inf,这里首先需要看下它的入口:

EFI_STATUS
EFIAPI
Udp4DriverEntryPoint (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  //
  // Install the Udp4DriverBinding and Udp4ComponentName protocols.
  //
  Status = EfiLibInstallDriverBindingComponentName2 (
             ImageHandle,
             SystemTable,
             &gUdp4DriverBinding,
             ImageHandle,
             &gUdp4ComponentName,
             &gUdp4ComponentName2
             );
  if (!EFI_ERROR (Status)) {
    //
    // Initialize the UDP random port.
    //
    mUdp4RandomPort = (UINT16)(((UINT16)NetRandomInitSeed ()) % UDP4_PORT_KNOWN + UDP4_PORT_KNOWN); // 宏的值是1024
  }
}

因为UDP4也是一个UEFI Driver Model,所以第一步是安装gUdp4DriverBinding,其实现:

EFI_DRIVER_BINDING_PROTOCOL  gUdp4DriverBinding = {
  Udp4DriverBindingSupported,
  Udp4DriverBindingStart,
  Udp4DriverBindingStop,
  0xa,
  NULL,
  NULL
};

而第二步是初始化一个随机的UDP端口,根据通用网络协议的做法,UDP的端口占两个字节(即16位),只要不是0-1023里面的公认端口都可以,且跟TCP端口的一致也没有关系。

UDP4在UEFI网络协议栈中的关系图:

Udp4DriverBindingSupported

UDP4依赖于IP4:

EFI_STATUS
EFIAPI
Udp4DriverBindingSupported (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   ControllerHandle,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath  OPTIONAL
  )
{
  //
  // Test for the Ip4 Protocol
  //
  Status = gBS->OpenProtocol (
                  ControllerHandle,
                  &gEfiIp4ServiceBindingProtocolGuid,
                  NULL,
                  This->DriverBindingHandle,
                  ControllerHandle,
                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
                  );
}

Udp4DriverBindingStart

Start函数的流程大致如下:

  1. 初始化UDP4_SERVICE_DATA
  2. 安装gEfiUdp4ServiceBindingProtocolGuid

同其它驱动一样,重点也是结构体,这里就是UDP4_SERVICE_DATA

UDP4_SERVICE_DATA

UDP4_SERVICE_DATA在Start函数中创建:

EFI_STATUS
EFIAPI
Udp4DriverBindingStart (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   ControllerHandle,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath  OPTIONAL
  )
{
  Status = Udp4CreateService (Udp4Service, This->DriverBindingHandle, ControllerHandle);
}

其结构体定义如下:

typedef struct _UDP4_SERVICE_DATA_ {
  UINT32                          Signature;
  EFI_SERVICE_BINDING_PROTOCOL    ServiceBinding;
  EFI_HANDLE                      ImageHandle;
  EFI_HANDLE                      ControllerHandle;
  LIST_ENTRY                      ChildrenList;
  UINTN                           ChildrenNumber;
  IP_IO                           *IpIo;

  EFI_EVENT                       TimeoutEvent;
} UDP4_SERVICE_DATA;

相比之前的服务数据,这个结构体相当得简单,其中比较重要的成员有:

  • ServiceBinding:对应mUdp4ServiceBinding
EFI_SERVICE_BINDING_PROTOCOL  mUdp4ServiceBinding = {
  Udp4ServiceBindingCreateChild,
  Udp4ServiceBindingDestroyChild
};

用于创建UDP4子项。

  • ChildrenListChildrenNumber:对应UDP4_INSTANCE_DATA结构体,由Udp4ServiceBindingCreateChild()创建,是表示子项的结构体,在UDP4_INSTANCE_DATA会进一步介绍。
  • IpIo:它是对IP4实例的一个包装,UDP4通过它来进行通信,在IP_IO已经介绍过。在UDP4以及TCP4中会进场看到类似IP_IO这样的结构体,它们仅仅是对IP层的保证,之所以要有这样的包装,是因为存在IPv4和IPv6两个版本,而这里只关注IPv4。
  • TimeoutEvent:一个定时事件,创建的位置是在Udp4CreateService()函数中:
EFI_STATUS
Udp4CreateService (
  IN OUT UDP4_SERVICE_DATA  *Udp4Service,
  IN     EFI_HANDLE         ImageHandle,
  IN     EFI_HANDLE         ControllerHandle
  )
{
  //
  // Create the event for Udp timeout checking.
  //
  Status = gBS->CreateEvent (
                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
                  TPL_CALLBACK,
                  Udp4CheckTimeout,
                  Udp4Service,
                  &Udp4Service->TimeoutEvent
                  );
  //
  // Start the timeout timer event.
  //
  Status = gBS->SetTimer (
                  Udp4Service->TimeoutEvent,
                  TimerPeriodic,
                  UDP4_TIMEOUT_INTERVAL // 50 milliseconds
                  );

对应的回调函数Udp4CheckTimeout(),它用来检测接收到的报文是否过期,其主体代码:

VOID
EFIAPI
Udp4CheckTimeout (
  IN EFI_EVENT  Event,
  IN VOID       *Context
  )
{
  NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {
    //
    // Iterate all the instances belonging to this service context.
    //
    Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);
    NET_CHECK_SIGNATURE (Instance, UDP4_INSTANCE_DATA_SIGNATURE);

    if (!Instance->Configured || (Instance->ConfigData.ReceiveTimeout == 0)) {
      //
      // Skip this instance if it's not configured or no receive timeout.
      //
      continue;
    }

    NET_LIST_FOR_EACH_SAFE (WrapEntry, NextEntry, &Instance->RcvdDgramQue) {
      //
      // Iterate all the rxdatas belonging to this udp instance.
      //
      Wrap = NET_LIST_USER_STRUCT (WrapEntry, UDP4_RXDATA_WRAP, Link);

      //
      // TimeoutTick unit is microsecond, MNP_TIMEOUT_CHECK_INTERVAL unit is 100ns.
      //
      if (Wrap->TimeoutTick < (UDP4_TIMEOUT_INTERVAL / 10)) {
        //
        // Remove this RxData if it timeouts.
        //
        Udp4RecycleRxDataWrap (NULL, (VOID *)Wrap);
      } else {
        Wrap->TimeoutTick -= (UDP4_TIMEOUT_INTERVAL / 10);
      }
    }
  }
}

这里的Wrap对应结构体UDP4_RXDATA_WRAP

typedef struct _UDP4_RXDATA_WRAP_ {
  LIST_ENTRY               Link;
  NET_BUF                  *Packet;
  UINT32                   TimeoutTick;
  EFI_UDP4_RECEIVE_DATA    RxData;
} UDP4_RXDATA_WRAP;

它通过Udp4WrapRxData()创建,然后放到一个队列中供UDP驱动处理,如果来不及处理就会过期,而过期时间也由这里的成员TimeoutTick指定,而该成员由另外的一个值指定:

Wrap->TimeoutTick = Instance->ConfigData.ReceiveTimeout;

Instance是后面会介绍的UDP4_INSTANCE_DATA中的配置参数ConfigDataConfigData.ReceiveTimeout的值在创建时是-1,表示不会过期:

  //
  // use the -1 magic number to disable the receiving process of the ip instance.
  //
  Ip4ConfigData->ReceiveTimeout = (UINT32)(-1);

不过在UDP4的配置中可以修改:

EFI_STATUS
EFIAPI
Udp4Configure (
  IN EFI_UDP4_PROTOCOL     *This,
  IN EFI_UDP4_CONFIG_DATA  *UdpConfigData OPTIONAL
  )
{
  if (UdpConfigData != NULL) {
    if (Instance->Configured) {
      //
      // Save the reconfigurable parameters.
      //
      Instance->ConfigData.TransmitTimeout = UdpConfigData->TransmitTimeout;
    }
  }
}

UDP4_INSTANCE_DATA

UDP4_INSTANCE_DATA表示一个UDP4子项,其它位于NetworkPkg\Udp4Dxe\Udp4Impl.h:

typedef struct _UDP4_INSTANCE_DATA_ {
  UINT32                  Signature;
  LIST_ENTRY              Link;

  UDP4_SERVICE_DATA       *Udp4Service;
  EFI_UDP4_PROTOCOL       Udp4Proto;
  EFI_UDP4_CONFIG_DATA    ConfigData;
  EFI_HANDLE              ChildHandle;
  BOOLEAN                 Configured;
  BOOLEAN                 IsNoMapping;

  NET_MAP                 TxTokens;
  NET_MAP                 RxTokens;

  NET_MAP                 McastIps;

  LIST_ENTRY              RcvdDgramQue;
  LIST_ENTRY              DeliveredDgramQue;

  UINT16                  HeadSum;

  EFI_STATUS              IcmpError;

  IP_IO_IP_INFO           *IpInfo;

  BOOLEAN                 InDestroy;
} UDP4_INSTANCE_DATA;

下面介绍其中比较重要的成员:

  • Udp4Service:指向UDP4服务的结构体。

  • Udp4Proto:对应EFI_UDP4_PROTOCOL,后面会进一步介绍。

  • ConfigData:UDP配置数据:

typedef struct {
  //
  // Receiving Filters
  //
  BOOLEAN             AcceptBroadcast;
  BOOLEAN             AcceptPromiscuous;
  BOOLEAN             AcceptAnyPort;
  BOOLEAN             AllowDuplicatePort;
  //
  // I/O parameters
  //
  UINT8               TypeOfService;
  UINT8               TimeToLive;
  BOOLEAN             DoNotFragment;
  UINT32              ReceiveTimeout;
  UINT32              TransmitTimeout;
  //
  // Access Point
  //
  BOOLEAN             UseDefaultAddress;
  EFI_IPv4_ADDRESS    StationAddress;
  EFI_IPv4_ADDRESS    SubnetMask;
  UINT16              StationPort;
  EFI_IPv4_ADDRESS    RemoteAddress;
  UINT16              RemotePort;
} EFI_UDP4_CONFIG_DATA;
  • TxTokensRxTokens:描述收发数据的映射:
typedef struct {
  LIST_ENTRY    Used;
  LIST_ENTRY    Recycled;
  UINTN         Count;
} NET_MAP;

真正的Token是EFI_UDP4_COMPLETION_TOKEN

typedef struct {
  EFI_EVENT     Event;
  EFI_STATUS    Status;
  union {
    EFI_UDP4_RECEIVE_DATA     *RxData;
    EFI_UDP4_TRANSMIT_DATA    *TxData;
  } Packet;
} EFI_UDP4_COMPLETION_TOKEN;
  • RcvdDgramQueDeliveredDgramQue:处理收发数据的队列。
  • IpInfo:底层IP4实例需要使用到的结构体:
///
/// The IP_IO_IP_INFO is used in IpIoSend() to override the default IP instance
/// in IP_IO.
///
typedef struct _IP_IO_IP_INFO {
  EFI_IP_ADDRESS               Addr;
  IP_IO_IP_MASK                PreMask;
  LIST_ENTRY                   Entry;
  EFI_HANDLE                   ChildHandle;
  IP_IO_IP_PROTOCOL            Ip;
  IP_IO_IP_COMPLETION_TOKEN    DummyRcvToken;
  INTN                         RefCnt;
  UINT8                        IpVersion;
} IP_IO_IP_INFO;

从注释中可以看到发送数据时会使用到。

EFI_UDP4_PROTOCOL

UDP4通信的接口,该Protocol的结构体如下:

///
/// The EFI_UDP4_PROTOCOL defines an EFI UDPv4 Protocol session that can be used
/// by any network drivers, applications, or daemons to transmit or receive UDP packets.
/// This protocol instance can either be bound to a specified port as a service or
/// connected to some remote peer as an active client. Each instance has its own settings,
/// such as the routing table and group table, which are independent from each other.
///
struct _EFI_UDP4_PROTOCOL {
  EFI_UDP4_GET_MODE_DATA    GetModeData;
  EFI_UDP4_CONFIGURE        Configure;
  EFI_UDP4_GROUPS           Groups;
  EFI_UDP4_ROUTES           Routes;
  EFI_UDP4_TRANSMIT         Transmit;
  EFI_UDP4_RECEIVE          Receive;
  EFI_UDP4_CANCEL           Cancel;
  EFI_UDP4_POLL             Poll;
};

对应的实现:

EFI_UDP4_PROTOCOL  mUdp4Protocol = {
  Udp4GetModeData,
  Udp4Configure,
  Udp4Groups,
  Udp4Routes,
  Udp4Transmit,
  Udp4Receive,
  Udp4Cancel,
  Udp4Poll
};

后面会介绍这些函数的实现。

Udp4.GetModeData

对应的实现是Udp4GetModeData(),其代码实现:

EFI_STATUS
EFIAPI
Udp4GetModeData (
  IN  EFI_UDP4_PROTOCOL                *This,
  OUT EFI_UDP4_CONFIG_DATA             *Udp4ConfigData OPTIONAL,
  OUT EFI_IP4_MODE_DATA                *Ip4ModeData    OPTIONAL,
  OUT EFI_MANAGED_NETWORK_CONFIG_DATA  *MnpConfigData  OPTIONAL,
  OUT EFI_SIMPLE_NETWORK_MODE          *SnpModeData    OPTIONAL
  )
{
  if (Udp4ConfigData != NULL) {
    //
    // Set the Udp4ConfigData.
    //
    CopyMem (Udp4ConfigData, &Instance->ConfigData, sizeof (*Udp4ConfigData));
  }

  Ip = Instance->IpInfo->Ip.Ip4;

  //
  // Get the underlying Ip4ModeData, MnpConfigData and SnpModeData.
  //
  Status = Ip->GetModeData (Ip, Ip4ModeData, MnpConfigData, SnpModeData);

}

从这里可以看出,上层的网络协议可以获取到下层所有的模式数据。

对于UDP4来说,数据在UDP4_INSTANCE_DATAConfigData成员中。

Udp4.Configure

对应的实现是Udp4Configure(),其代码实现:

EFI_STATUS
EFIAPI
Udp4Configure (
  IN EFI_UDP4_PROTOCOL     *This,
  IN EFI_UDP4_CONFIG_DATA  *UdpConfigData OPTIONAL
  )
{
  // 根据是否有配置存在两种情况,没有数据相当于重置
  if (UdpConfigData != NULL) {
    if (Instance->Configured) {
      //
      // The instance is already configured, try to do the re-configuration.
      //
      if (!Udp4IsReconfigurable (&Instance->ConfigData, UdpConfigData)) {
        //
        // If the new configuration data wants to change some unreconfigurable
        // settings, return EFI_ALREADY_STARTED.
        //
        Status = EFI_ALREADY_STARTED;
        goto ON_EXIT;
      }

      //
      // Save the reconfigurable parameters.
      //
      Instance->ConfigData.TypeOfService   = UdpConfigData->TypeOfService;
      Instance->ConfigData.TimeToLive      = UdpConfigData->TimeToLive;
      Instance->ConfigData.DoNotFragment   = UdpConfigData->DoNotFragment;
      Instance->ConfigData.ReceiveTimeout  = UdpConfigData->ReceiveTimeout;
      Instance->ConfigData.TransmitTimeout = UdpConfigData->TransmitTimeout;
    } else {
      //
      // Construct the Ip configuration data from the UdpConfigData.
      //
      Udp4BuildIp4ConfigData (UdpConfigData, &Ip4ConfigData);

      //
      // Configure the Ip instance wrapped in the IpInfo.
      //
      Status = IpIoConfigIp (Instance->IpInfo, &Ip4ConfigData);
      if (EFI_ERROR (Status)) {
        if (Status == EFI_NO_MAPPING) {
          Instance->IsNoMapping = TRUE;
        }

        goto ON_EXIT;
      }

      Instance->IsNoMapping = FALSE;

      //
      // Save the configuration data.
      //
      CopyMem (&Instance->ConfigData, UdpConfigData, sizeof (Instance->ConfigData));
      IP4_COPY_ADDRESS (&Instance->ConfigData.StationAddress, &Ip4ConfigData.StationAddress);
      IP4_COPY_ADDRESS (&Instance->ConfigData.SubnetMask, &Ip4ConfigData.SubnetMask);

      //
      // Try to allocate the required port resource.
      //
      Status = Udp4Bind (&Udp4Service->ChildrenList, &Instance->ConfigData);
      if (EFI_ERROR (Status)) {
        //
        // Reset the ip instance if bind fails.
        //
        IpIoConfigIp (Instance->IpInfo, NULL);
        goto ON_EXIT;
      }

      //
      // Pre calculate the checksum for the pseudo head, ignore the UDP length first.
      //
      CopyMem (&LocalAddr, &Instance->ConfigData.StationAddress, sizeof (IP4_ADDR));
      CopyMem (&RemoteAddr, &Instance->ConfigData.RemoteAddress, sizeof (IP4_ADDR));
      Instance->HeadSum = NetPseudoHeadChecksum (
                            LocalAddr,
                            RemoteAddr,
                            EFI_IP_PROTO_UDP,
                            0
                            );

      Instance->Configured = TRUE;
    }
  } else {
    //
    // UdpConfigData is NULL, reset the instance.
    //
    Instance->Configured  = FALSE;
    Instance->IsNoMapping = FALSE;

    //
    // Reset the Ip instance wrapped in the IpInfo.
    //
    IpIoConfigIp (Instance->IpInfo, NULL);

    //
    // Cancel all the user tokens.
    //
    Instance->Udp4Proto.Cancel (&Instance->Udp4Proto, NULL);

    //
    // Remove the buffered RxData for this instance.
    //
    Udp4FlushRcvdDgram (Instance);
  }
}

根据输入参数的不同,以及是否已经配置过,会走到不同的流程,此外,UDP4还会配置进一步调用IP4的接口进行配置。

Udp4.Transmit

对应的实现是Udp4Transmit(),其代码实现:

EFI_STATUS
EFIAPI
Udp4Transmit (
  IN EFI_UDP4_PROTOCOL          *This,
  IN EFI_UDP4_COMPLETION_TOKEN  *Token
  )
{
  //
  // Validate the Token, if the token is invalid return the error code.
  //
  Status = Udp4ValidateTxToken (Instance, Token);
  if (EFI_ERROR (Status)) {
    goto ON_EXIT;
  }

  if (EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp4TokenExist, Token)) ||
      EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp4TokenExist, Token)))
  {
    //
    // Try to find a duplicate token in the two token maps, if found, return
    // EFI_ACCESS_DENIED.
    //
    Status = EFI_ACCESS_DENIED;
    goto ON_EXIT;
  }

  TxData = Token->Packet.TxData;

  //
  // Create a net buffer to hold the user buffer and the udp header.
  //
  Packet = NetbufFromExt (
             (NET_FRAGMENT *)TxData->FragmentTable,
             TxData->FragmentCount,
             UDP4_HEADER_SIZE,
             0,
             Udp4NetVectorExtFree,
             NULL
             );
  if (Packet == NULL) {
    Status = EFI_OUT_OF_RESOURCES;
    goto ON_EXIT;
  }

  //
  // Store the IpIo in ProtoData.
  //
  Udp4Service                       = Instance->Udp4Service;
  *((UINTN *)&Packet->ProtoData[0]) = (UINTN)(Udp4Service->IpIo);

  Udp4Header = (EFI_UDP_HEADER *)NetbufAllocSpace (Packet, UDP4_HEADER_SIZE, TRUE);
  ASSERT (Udp4Header != NULL);

  ConfigData = &Instance->ConfigData;

  //
  // Fill the udp header.
  //
  Udp4Header->SrcPort  = HTONS (ConfigData->StationPort);
  Udp4Header->DstPort  = HTONS (ConfigData->RemotePort);
  Udp4Header->Length   = HTONS ((UINT16)Packet->TotalSize);
  Udp4Header->Checksum = 0;

  UdpSessionData = TxData->UdpSessionData;
  IP4_COPY_ADDRESS (&Override.Ip4OverrideData.SourceAddress, &ConfigData->StationAddress);

  if (UdpSessionData != NULL) {
    //
    // Set the SourceAddress, SrcPort and Destination according to the specified
    // UdpSessionData.
    //
    if (!EFI_IP4_EQUAL (&UdpSessionData->SourceAddress, &mZeroIp4Addr)) {
      IP4_COPY_ADDRESS (&Override.Ip4OverrideData.SourceAddress, &UdpSessionData->SourceAddress);
    }

    if (UdpSessionData->SourcePort != 0) {
      Udp4Header->SrcPort = HTONS (UdpSessionData->SourcePort);
    }

    if (UdpSessionData->DestinationPort != 0) {
      Udp4Header->DstPort = HTONS (UdpSessionData->DestinationPort);
    }

    CopyMem (&Source, &Override.Ip4OverrideData.SourceAddress, sizeof (IP4_ADDR));
    CopyMem (&Destination, &UdpSessionData->DestinationAddress, sizeof (IP4_ADDR));

    //
    // calculate the pseudo head checksum using the overridden parameters.
    //
    HeadSum = NetPseudoHeadChecksum (
                Source,
                Destination,
                EFI_IP_PROTO_UDP,
                0
                );
  } else {
    //
    // UdpSessionData is NULL, use the address and port information previously configured.
    //
    CopyMem (&Destination, &ConfigData->RemoteAddress, sizeof (IP4_ADDR));

    HeadSum = Instance->HeadSum;
  }

  //
  // calculate the checksum.
  //
  Udp4Header->Checksum = Udp4Checksum (Packet, HeadSum);
  if (Udp4Header->Checksum == 0) {
    //
    // If the calculated checksum is 0, fill the Checksum field with all ones.
    //
    Udp4Header->Checksum = 0xffff;
  }

  //
  // Fill the IpIo Override data.
  //
  if (TxData->GatewayAddress != NULL) {
    IP4_COPY_ADDRESS (&Override.Ip4OverrideData.GatewayAddress, TxData->GatewayAddress);
  } else {
    ZeroMem (&Override.Ip4OverrideData.GatewayAddress, sizeof (EFI_IPv4_ADDRESS));
  }

  Override.Ip4OverrideData.Protocol      = EFI_IP_PROTO_UDP;
  Override.Ip4OverrideData.TypeOfService = ConfigData->TypeOfService;
  Override.Ip4OverrideData.TimeToLive    = ConfigData->TimeToLive;
  Override.Ip4OverrideData.DoNotFragment = ConfigData->DoNotFragment;

  //
  // Save the token into the TxToken map.
  //
  Status = NetMapInsertTail (&Instance->TxTokens, Token, Packet);

  //
  // Send out this datagram through IpIo.
  //
  IpDestAddr.Addr[0] = Destination;
  Status             = IpIoSend (
                         Udp4Service->IpIo,
                         Packet,
                         Instance->IpInfo,
                         Instance,
                         Token,
                         &IpDestAddr,
                         &Override
                         );
}

Udp4.Receive

对应的实现是Udp4Receive(),其代码实现:

EFI_STATUS
EFIAPI
Udp4Receive (
  IN EFI_UDP4_PROTOCOL          *This,
  IN EFI_UDP4_COMPLETION_TOKEN  *Token
  )
{
  if (EFI_ERROR (NetMapIterate (&Instance->RxTokens, Udp4TokenExist, Token)) ||
      EFI_ERROR (NetMapIterate (&Instance->TxTokens, Udp4TokenExist, Token)))
  {
    //
    // Return EFI_ACCESS_DENIED if the specified token is already in the TxTokens or
    // RxTokens map.
    //
    Status = EFI_ACCESS_DENIED;
    goto ON_EXIT;
  }

  Token->Packet.RxData = NULL;

  //
  // Save the token into the RxTokens map.
  //
  Status = NetMapInsertTail (&Instance->RxTokens, Token, NULL);
  if (EFI_ERROR (Status)) {
    Status = EFI_NOT_READY;
    goto ON_EXIT;
  }

  //
  // If there is an icmp error, report it.
  //
  Udp4ReportIcmpError (Instance);

  //
  // Try to deliver the received datagrams.
  //
  Udp4InstanceDeliverDgram (Instance);

  //
  // Dispatch the DPC queued by the NotifyFunction of Token->Event.
  //
  DispatchDpc ();
}

同其它的网络协议中的Receive一样,重点是注册Token。

Udp4.Poll

对应的实现是Udp4Poll(),其代码实现就是调用下一层的Poll:

EFI_STATUS
EFIAPI
Udp4Poll (
  IN EFI_UDP4_PROTOCOL  *This
  )
{
  Ip       = Instance->IpInfo->Ip.Ip4;
  //
  // Invode the Ip instance consumed by the udp instance to do the poll operation.
  //
  return Ip->Poll (Ip);
}

代码示例

DHCP和DNS等都是使用UDP的,后面会进一步说明。文章来源地址https://www.toymoban.com/news/detail-815569.html

到了这里,关于【UEFI基础】EDK网络框架(UDP4)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • UEFI基础——测试用例Hello Word

    硬件环境:龙芯ls3a6000平台 软件环境:龙芯uefi固件 GUID获取网址:https://guidgen.com mkdir TextPkg/ 三个文件 Hello.c 、 Hello.inf 、HelloPkg.dsc 1.1 Hello.c

    2024年02月07日
    浏览(33)
  • 【UEFI/BIOS】UEFI Shell Command (UEFI Shell 命令)篇目一

    命令 作用 alias 在UEFI Shell环境中显示、创建、删除别名 attrib 显示或更改文件或目录的属性 bcfg 操作Boot或者驱动程序顺序 cd 显示或更改当前目录 comp 以字节为单位比价两个文件的内容 connet 将驱动程序绑定到特定的设备并启动该驱动程序 cp 将一个或多个源文件或目录复制到目

    2024年02月07日
    浏览(32)
  • 【UEFI实战】UEFI图形显示(字符输出)

    接下来介绍 EFI_HII_FONT_PROTOCOL ,它在UEFI代码中完成了字符到像素的转换,本节主要介绍这个转换关系,它的实现代码在edk2MdeModulePkgUniversalHiiDatabaseDxeHiiDatabaseDxe.inf中,除了 EFI_HII_FONT_PROTOCOL ,这个模块还实现了很多其它的Protocol,后面用到的时候也会介绍,所以HiiDatabaseDx

    2024年02月13日
    浏览(28)
  • 《UEFI内核导读》UEFI Firmware Storage简介

     ============================== 敬请关注:“固件C字营     ==============================           UEFI固件一般存储在被称之为“固件仓库”的非易失性存储器中,简称为FD(固件设备),当前主流的存储介质是NorFlash它拥有非易失性、XIP以及可二次编程的特性。         固件设

    2023年04月08日
    浏览(27)
  • UEFI Shell命令详解,自写一个UEFI Shell命令

    命令 功能 命令 功能 acpiview 显示ACPI表相关信息 ifconfig 配置IP地址 alias 显示,创建,删除别名 load 加载UEFI驱动 attrib 显示,更改文件或目录属性 loadpcirom 加载PCI ROM bcfg 管理启动项 ls 列出目录内容或文件信息 cd 更改当前目录 map 显示Mapping cls 清空标准输出 memmap 显示目录映射

    2023年04月17日
    浏览(45)
  • uefi安全启动

    参考博客:UEFI安全启动 - 知乎 (zhihu.com) UEFI安全引导(Secure Boot)的核心职能就是利用数字签名来确认EFI驱动程序或者应用程序是否是受信任的。在简要地介绍了数字签名的概念(这是安全引导的基础)之后,我们重点介绍UEFI 安全引导是如何利用数字签名以及其他的加密方式

    2024年02月12日
    浏览(25)
  • 高通 UEFI:ABL(一)

    高通平台下的UEFI由XBL+ABL组成,主要完成各种客制化的需求实现,例如通过拉特定的gpio进入fastboot/recovery模式,读取ufs寿命,LCD兼容框架的实现等,想要实现客制化首先要搞明白源码种的框架组成,这篇文章先剖析一下abl阶段主要做了什么事情。 要分析abl框架,首先我们需要

    2024年02月09日
    浏览(33)
  • legacy启动和UEFI启动

    legacy启动是指传统的BIOS启动,和MBR分区模式相互依存,可以进行MBR分区系统的安装,支持所有Windows系统的安装,兼容性较强。Legacy作为传统的引导模式,Legacy模式支持磁盘分区为MBR结构,它能够引导32位系统也可以引导64位系统。 legacy启动意思是传统的BIOS启动,和MBR分区模

    2024年02月07日
    浏览(34)
  • UEFI统一可扩展固件接口

    统一可扩展固件接口(英语:Unified Extensible Firmware Interface,缩写UEFI)是一种个人电脑系统规格,用来定义操作系统与系统固件之间的软件界面,作为BIOS的替代方案。可扩展固件接口负责加电自检(POST)、联系操作系统以及提供连接操作系统与硬件的接口。 UEFI的前身是Int

    2024年02月04日
    浏览(26)
  • VM虚拟机 运行UEFI程序

    需要自行安装一个VM虚拟机,准备一个FAT32的U盘(U盘转格式时,最好用空U盘),U盘里面放你自己编译后生成的.efi文件。 1.新建虚拟机,点击“文件-》新建虚拟机” 大部分地方直接默认就行,这里只关注两个地方: 操作系统选Win10: 固件类型选择UEFI: 2.选中新建好的虚拟机

    2023年04月08日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包