[UEFI] EDK2代码中记录网络发送报文从IP层到UNDI层代码调用大概流程

EDK2整个网络层次:

在这里插入图片描述

把IP层待发送的包放到发送队列

/**
Places outgoing data packets into the transmit queue.

The Transmit() function places a sending request in the transmit queue of this
EFI IPv4 Protocol instance. Whenever the packet in the token is sent out or some
errors occur, the event in the token will be signaled and the status is updated.*/

**EFI_STATUS
EFIAPI
EfiIp4Transmit (
IN EFI_IP4_PROTOCOL This,
IN EFI_IP4_COMPLETION_TOKEN Token
)

省略若干代码
//
// Mark the packet sent before output it. Mark it not sent again if the
// returned status is not EFI_SUCCESS;
//
Wrap->Sent = TRUE;

调用接口发送:

Status = Ip4Output (
IpSb,
IpInstance,
Wrap->Packet,
&Head,
OptionsBuffer,
OptionsLength,
GateWay,
Ip4OnPacketSent,
Wrap
);

发送IPV4包

/**
Transmit an IP4 packet. The packet comes either from the IP4
child’s consumer (IpInstance != NULL) or the IP4 driver itself
(IpInstance == NULL). It will route the packet, fragment it,
then transmit all the fragments through some interface.
*/

**EFI_STATUS
Ip4Output (
IN IP4_SERVICE *IpSb,
IN IP4_PROTOCOL *IpInstance OPTIONAL,
IN NET_BUF *Packet,
IN IP4_HEAD *Head,
IN UINT8 Option,
IN UINT32 OptLen,
IN IP4_ADDR GateWay,
IN IP4_FRAME_CALLBACK Callback,
IN VOID Context
)

如果报文长度太长,需要分片发送:

if (Packet->TotalSize + HeadLen > Mtu) {
//
// Fragmentation is disabled for RawData mode.
//
for (Index = 0; Index < Num - 1; Index++, Offset -= Mtu)
{
Fragment = NetbufGetFragment (Packet, Offset, PacketLen, IP4_MAX_HEADLEN);

  if (Fragment == NULL) 
  {
    Status = EFI_OUT_OF_RESOURCES;
    goto ON_ERROR;
  }

  //
  // Update the header's fragment. The caller fills the IP4 header
  // fields that are required by Ip4PrependHead except the fragment.
  //
  Head->Fragment = IP4_HEAD_FRAGMENT_FIELD (FALSE, (Index != 0), Offset);
  Ip4PrependHead (Fragment, Head, Option, OptLen);

  //
  // Transmit the fragments, pass the Packet address as the context.
  // So, we can find all the fragments spawned from the Packet by
  // compare the NetBuf and Context to the Packet.
  //

Status = Ip4SendFrame (
IpIf,
IpInstance,
Fragment,
GateWay,
Ip4SysPacketSent,
Packet,
IpSb
);

  if (EFI_ERROR (Status)) {
    goto ON_ERROR;
  }

  PacketLen = Mtu;
}

//
// Trim the already sent data, then adjust the head's fragment field.
//
NetbufTrim (Packet, Packet->TotalSize - Mtu, FALSE);
Head->Fragment = IP4_HEAD_FRAGMENT_FIELD (FALSE, TRUE, 0);

}

通过接口发送报文:

/*
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.
*/
**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,
IN IP4_SERVICE IpSb
)

检查本地ARP缓存:

// First check whether this binding is in the ARP cache.
//
NextHop = HTONL (NextHop);
Status = Arp->Request (Arp, &NextHop, NULL, &Token->DstMac);

通过调用MNP层发送接口发送报文:

//
// Insert the tx token into the SentFrames list before calling Mnp->Transmit.
// Remove it if the returned status is not EFI_SUCCESS.
//
InsertTailList (&Interface->SentFrames, &Token->Link);
Status = Interface->Mnp->Transmit (Interface->Mnp, &Token->MnpToken);
if (EFI_ERROR (Status)) {
RemoveEntryList (&Token->Link);
goto ON_ERROR;
}

调用MNP层Transmit接口:

///
/// The MNP is used by network applications (and drivers) to
/// perform raw (unformatted) asynchronous network packet I/O.
///
struct _EFI_MANAGED_NETWORK_PROTOCOL {
EFI_MANAGED_NETWORK_GET_MODE_DATA GetModeData;
EFI_MANAGED_NETWORK_CONFIGURE Configure;
EFI_MANAGED_NETWORK_MCAST_IP_TO_MAC McastIpToMac;
EFI_MANAGED_NETWORK_GROUPS Groups;
EFI_MANAGED_NETWORK_TRANSMIT Transmit;
EFI_MANAGED_NETWORK_RECEIVE Receive;
EFI_MANAGED_NETWORK_CANCEL Cancel;
EFI_MANAGED_NETWORK_POLL Poll;
};

这里参数应该是两个:
typedef
EFI_STATUS
(EFIAPI *EFI_MANAGED_NETWORK_TRANSMIT)(
IN EFI_MANAGED_NETWORK_PROTOCOL *This,
IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token
);

实现的原型是这个:
EFI_STATUS
EFIAPI
MnpTransmit (
IN EFI_MANAGED_NETWORK_PROTOCOL *This,
IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token
)
{
省略若干代码:
//
// OK, send the packet synchronously.
//
Status = MnpSyncSendPacket (MnpServiceData, PktBuf, PktLen, Token);
}

/**
Synchronously send out the packet.

This function places the packet buffer to SNP driver’s tansmit queue. The packet
can be considered successfully sent out once SNP accept the packet, while the
packet buffer recycle is deferred for better performance.
省略参数部分
**/
EFI_STATUS
MnpSyncSendPacket (
IN MNP_SERVICE_DATA *MnpServiceData,
IN UINT8 *Packet,
IN UINT32 Length,
IN OUT EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token
)
{
省略若干代码
//
// Transmit the packet through SNP.
//
Status = Snp->Transmit (
Snp,
HeaderSize,
Length,
Packet,
TxData->SourceAddress,
TxData->DestinationAddress,
&ProtocolType
);

}

接下来实现部分是如下代码:
/**
Places a packet in the transmit queue of a network interface.

This function places the packet specified by Header and Buffer on the transmit
queue. If HeaderSize is nonzero and HeaderSize is not equal to
This->Mode->MediaHeaderSize, then EFI_INVALID_PARAMETER will be returned. If
BufferSize is less than This->Mode->MediaHeaderSize, then EFI_BUFFER_TOO_SMALL
will be returned. If Buffer is NULL, then EFI_INVALID_PARAMETER will be
returned. If HeaderSize is nonzero and DestAddr or Protocol is NULL, then
EFI_INVALID_PARAMETER will be returned. If the transmit engine of the network
interface is busy, then EFI_NOT_READY will be returned. If this packet can be
accepted by the transmit engine of the network interface, the packet contents
specified by Buffer will be placed on the transmit queue of the network
interface, and EFI_SUCCESS will be returned. GetStatus() can be used to
determine when the packet has actually been transmitted. The contents of the
Buffer must not be modified until the packet has actually been transmitted.
The Transmit() function performs nonblocking I/O. A caller who wants to perform
blocking I/O, should call Transmit(), and then GetStatus() until the
transmitted buffer shows up in the recycled transmit buffer.
If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
*/
实际执行的源码是:
**EFI_STATUS
EFIAPI
SnpUndi32Transmit (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN UINTN HeaderSize,
IN UINTN BufferSize,
IN VOID *Buffer,
IN EFI_MAC_ADDRESS *SrcAddr, OPTIONAL
IN EFI_MAC_ADDRESS DestAddr, OPTIONAL
IN UINT16 Protocol OPTIONAL
)

{
省略若干源码:
Status = PxeTransmit (Snp, Buffer, BufferSize);
}

代码已经到UNDI层:
/**
This routine calls undi to transmit the given data buffer
*/
EFI_STATUS
PxeTransmit (
SNP_DRIVER *Snp,
VOID *Buffer,
UINTN BufferSize
)
{
省略若干代码:
(*Snp->IssueUndi32Command) ((UINT64) (UINTN) &Snp->Cdb);
}

//
// Local instance data needed by SNP driver
// 上边这是访问UNDI提供的API接口
// Pointer to S/W UNDI API entry point
// This will be NULL for H/W UNDI
//
ISSUE_UNDI32_COMMAND IssueUndi32Command;

/**
Send command to UNDI. It does nothing currently.

@param Cdb command to be sent to UNDI.

@retval EFI_INVALID_PARAMETER The command is 0.
@retval EFI_UNSUPPORTED Default return status because it’s not
supported currently.

**/
EFI_STATUS
EFIAPI
IssueHwUndiCommand (
UINT64 Cdb
)

{
DEBUG ((EFI_D_ERROR, “\nIssueHwUndiCommand() - This should not be called!”));

if (Cdb == 0) {
return EFI_INVALID_PARAMETER;

}
//
// %%TBD - For now, nothing is done.
//
return EFI_UNSUPPORTED;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值