mnpio.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,165 行 · 第 1/2 页
C
1,165 行
Arguments:
Instance - Pointer to the mnp instance context data.
RxData - Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.
GroupAddress - Pointer to the GroupAddress, the GroupAddress is non-NULL and
it contains the destination multicast mac address of the
received packet if the packet destinated to a multicast mac address.
PktAttr - The received packets attribute.
Returns:
The received packet matches the instance's receive filters or not.
--*/
{
EFI_MANAGED_NETWORK_CONFIG_DATA *ConfigData;
NET_LIST_ENTRY *Entry;
MNP_GROUP_CONTROL_BLOCK *GroupCtrlBlk;
NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
ConfigData = &Instance->ConfigData;
if (ConfigData->EnablePromiscuousReceive) {
//
// Always match if this instance is configured to be promiscuous.
//
return TRUE;
}
//
// Check the protocol type.
//
if ((ConfigData->ProtocolTypeFilter != 0) && (ConfigData->ProtocolTypeFilter != RxData->ProtocolType)) {
return FALSE;
}
//
// The protocol type is matched, check receive filter, include unicast and broadcast.
//
if ((Instance->ReceiveFilter & PktAttr) != 0) {
return TRUE;
}
//
// Check multicast addresses.
//
if (ConfigData->EnableMulticastReceive && RxData->MulticastFlag) {
ASSERT (GroupAddress != NULL);
NET_LIST_FOR_EACH (Entry, &Instance->GroupCtrlBlkList) {
GroupCtrlBlk = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_CONTROL_BLOCK, CtrlBlkEntry);
if (GroupCtrlBlk->GroupAddress == GroupAddress) {
//
// The instance is configured to receiveing packets destinated to this
// multicast address.
//
return TRUE;
}
}
}
//
// No match.
//
return FALSE;
}
STATIC
VOID
MnpAnalysePacket (
IN MNP_SERVICE_DATA *MnpServiceData,
IN NET_BUF *Nbuf,
IN EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData,
OUT MNP_GROUP_ADDRESS **GroupAddress,
OUT UINT8 *PktAttr
)
/*++
Routine Description:
Analyse the received packets.
Arguments:
MnpServiceData - Pointer to the mnp service context data.
Nbuf - Pointer to the net buffer holding the received packet.
RxData - Pointer to the buffer used to save the analysed result
in EFI_MANAGED_NETWORK_RECEIVE_DATA.
GroupAddress - Pointer to pointer to a MNP_GROUP_ADDRESS used to pass out
the address of the multicast address the received packet
destinated to.
PktAttr - Pointer to the buffer used to save the analysed packet attribute.
Returns:
None.
--*/
{
EFI_SIMPLE_NETWORK_MODE *SnpMode;
UINT8 *BufPtr;
NET_LIST_ENTRY *Entry;
SnpMode = MnpServiceData->Snp->Mode;
//
// Get the packet buffer.
//
BufPtr = NetbufGetByte (Nbuf, 0, NULL);
ASSERT (BufPtr != NULL);
//
// Set the initial values.
//
RxData->BroadcastFlag = FALSE;
RxData->MulticastFlag = FALSE;
RxData->PromiscuousFlag = FALSE;
*PktAttr = UNICAST_PACKET;
if (!NET_MAC_EQUAL (&SnpMode->CurrentAddress, BufPtr, SnpMode->HwAddressSize)) {
//
// This packet isn't destinated to our current mac address, it't not unicast.
//
*PktAttr = 0;
if (NET_MAC_EQUAL (&SnpMode->BroadcastAddress, BufPtr, SnpMode->HwAddressSize)) {
//
// It's broadcast.
//
RxData->BroadcastFlag = TRUE;
*PktAttr = BROADCAST_PACKET;
} else if ((*BufPtr & 0x01) == 0x1) {
//
// It's multicast, try to match the multicast filters.
//
NET_LIST_FOR_EACH (Entry, &MnpServiceData->GroupAddressList) {
*GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);
if (NET_MAC_EQUAL (BufPtr, &((*GroupAddress)->Address), SnpMode->HwAddressSize)) {
RxData->MulticastFlag = TRUE;
break;
}
}
if (!RxData->MulticastFlag) {
//
// No match, set GroupAddress to NULL. This multicast packet must
// be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.
//
*GroupAddress = NULL;
RxData->PromiscuousFlag = TRUE;
if (MnpServiceData->PromiscuousCount == 0) {
//
// Skip the below code, there is no receiver of this packet.
//
return ;
}
}
} else {
RxData->PromiscuousFlag = TRUE;
}
}
NetZeroMem (&RxData->Timestamp, sizeof (EFI_TIME));
//
// Fill the common parts of RxData.
//
RxData->PacketLength = Nbuf->TotalSize;
RxData->HeaderLength = SnpMode->MediaHeaderSize;
RxData->AddressLength = SnpMode->HwAddressSize;
RxData->DataLength = RxData->PacketLength - RxData->HeaderLength;
RxData->ProtocolType = NTOHS (*(UINT16 *) (BufPtr + 2 * SnpMode->HwAddressSize));
}
STATIC
MNP_RXDATA_WRAP *
MnpWrapRxData (
IN MNP_INSTANCE_DATA *Instance,
IN EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData
)
/*++
Routine Description:
Wrap the RxData.
Arguments:
Instance - Pointer to the mnp instance context data.
RxData - Pointer to the receive data to wrap.
Returns:
Pointer to a MNP_RXDATA_WRAP which wraps the RxData.
--*/
{
EFI_STATUS Status;
MNP_RXDATA_WRAP *RxDataWrap;
//
// Allocate memory.
//
RxDataWrap = NetAllocatePool (sizeof (MNP_RXDATA_WRAP));
if (RxDataWrap == NULL) {
MNP_DEBUG_ERROR (("MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));
return NULL;
}
RxDataWrap->Instance = Instance;
//
// Fill the RxData in RxDataWrap,
//
RxDataWrap->RxData = *RxData;
//
// Create the recycle event.
//
Status = gBS->CreateEvent (
EFI_EVENT_NOTIFY_SIGNAL,
NET_TPL_FAST_RECYCLE,
MnpRecycleRxData,
RxDataWrap,
&RxDataWrap->RxData.RecycleEvent
);
if (EFI_ERROR (Status)) {
MNP_DEBUG_ERROR (("MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status));
NetFreePool (RxDataWrap);
return NULL;
}
return RxDataWrap;
}
STATIC
VOID
MnpEnqueuePacket (
IN MNP_SERVICE_DATA *MnpServiceData,
IN NET_BUF *Nbuf
)
/*++
Routine Description:
Enqueue the received the packets to the instances belonging to the
MnpServiceData.
Arguments:
MnpServiceData - Pointer to the mnp service context data.
Nbuf - Pointer to the net buffer representing the received packet.
Returns:
None.
--*/
{
NET_LIST_ENTRY *Entry;
MNP_INSTANCE_DATA *Instance;
EFI_MANAGED_NETWORK_RECEIVE_DATA RxData;
UINT8 PktAttr;
MNP_GROUP_ADDRESS *GroupAddress;
MNP_RXDATA_WRAP *RxDataWrap;
//
// First, analyse the packet header.
//
MnpAnalysePacket (MnpServiceData, Nbuf, &RxData, &GroupAddress, &PktAttr);
if (RxData.PromiscuousFlag && (MnpServiceData->PromiscuousCount == 0)) {
//
// No receivers, no more action need.
//
return ;
}
//
// Iterate the children to find match.
//
NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {
Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);
NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
if (!Instance->Configured) {
continue;
}
//
// Check the packet against the instance receive filters.
//
if (MnpMatchPacket (Instance, &RxData, GroupAddress, PktAttr)) {
//
// Wrap the RxData.
//
RxDataWrap = MnpWrapRxData (Instance, &RxData);
if (RxDataWrap == NULL) {
continue;
}
//
// Associate RxDataWrap with Nbuf and increase the RefCnt.
//
RxDataWrap->Nbuf = Nbuf;
NET_GET_REF (RxDataWrap->Nbuf);
//
// Queue the packet into the instance queue.
//
MnpQueueRcvdPacket (Instance, RxDataWrap);
}
}
}
EFI_STATUS
MnpReceivePacket (
IN MNP_SERVICE_DATA *MnpServiceData
)
/*++
Routine Description:
Try to receive a packet and deliver it.
Arguments:
MnpServiceData - Pointer to the mnp service context data.
Returns:
EFI_SUCCESS - add return value to function comment
EFI_NOT_STARTED - The simple network protocol is not started.
EFI_NOT_READY - No packet received.
EFI_DEVICE_ERROR - An unexpected error occurs.
--*/
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
NET_BUF *Nbuf;
UINT8 *BufPtr;
UINTN BufLen;
UINTN HeaderSize;
UINT32 Trimmed;
NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
Snp = MnpServiceData->Snp;
if (Snp->Mode->State != EfiSimpleNetworkInitialized) {
//
// The simple network protocol is not started.
//
return EFI_NOT_STARTED;
}
if (NetListIsEmpty (&MnpServiceData->ChildrenList)) {
//
// There is no child, no need to receive packets.
//
return EFI_SUCCESS;
}
if (MnpServiceData->RxNbufCache == NULL) {
//
// Try to get a new buffer as there may be buffers recycled.
//
MnpServiceData->RxNbufCache = MnpAllocNbuf (MnpServiceData);
if (MnpServiceData->RxNbufCache == NULL) {
//
// No availabe buffer in the buffer pool.
//
return EFI_DEVICE_ERROR;
}
NetbufAllocSpace (
MnpServiceData->RxNbufCache,
MnpServiceData->BufferLength,
NET_BUF_TAIL
);
}
Nbuf = MnpServiceData->RxNbufCache;
BufLen = Nbuf->TotalSize;
BufPtr = NetbufGetByte (Nbuf, 0, NULL);
ASSERT (BufPtr != NULL);
//
// Receive packet through Snp.
//
Status = Snp->Receive (Snp, &HeaderSize, &BufLen, BufPtr, NULL, NULL, NULL);
if (EFI_ERROR (Status)) {
DEBUG_CODE (
if (Status != EFI_NOT_READY) {
MNP_DEBUG_ERROR (("MnpReceivePacket: Snp->Receive() = %r.\n", Status));
}
);
return Status;
}
//
// Sanity check.
//
if ((HeaderSize != Snp->Mode->MediaHeaderSize) || (BufLen < HeaderSize)) {
MNP_DEBUG_WARN (
("MnpReceivePacket: Size error, HL:TL = %d:%d.\n",
HeaderSize,
BufLen)
);
return EFI_DEVICE_ERROR;
}
Trimmed = 0;
if (Nbuf->TotalSize != BufLen) {
//
// Trim the packet from tail.
//
Trimmed = NetbufTrim (Nbuf, Nbuf->TotalSize - (UINT32) BufLen, NET_BUF_TAIL);
ASSERT (Nbuf->TotalSize == BufLen);
}
//
// Enqueue the packet to the matched instances.
//
MnpEnqueuePacket (MnpServiceData, Nbuf);
if (Nbuf->RefCnt > 2) {
//
// RefCnt > 2 indicates there is at least one receiver of this packet.
// Free the current RxNbufCache and allocate a new one.
//
MnpFreeNbuf (MnpServiceData, Nbuf);
Nbuf = MnpAllocNbuf (MnpServiceData);
MnpServiceData->RxNbufCache = Nbuf;
if (Nbuf == NULL) {
MNP_DEBUG_ERROR (("MnpReceivePacket: Alloc packet for receiving cache failed.\n"));
return EFI_DEVICE_ERROR;
}
NetbufAllocSpace (Nbuf, MnpServiceData->BufferLength, NET_BUF_TAIL);
} else {
//
// No receiver for this packet.
//
NetbufAllocSpace (Nbuf, Trimmed, NET_BUF_TAIL);
goto EXIT;
}
//
// Deliver the queued packets.
//
MnpDeliverPacket (MnpServiceData);
EXIT:
ASSERT (Nbuf->TotalSize == MnpServiceData->BufferLength);
return Status;
}
VOID
EFIAPI
MnpCheckPacketTimeout (
IN EFI_EVENT Event,
IN VOID *Context
)
/*++
Routine Description:
Remove the received packets if timeout occurs.
Arguments:
Event - The event this notify function registered to.
Context - Pointer to the context data registered to the event.
Returns:
None.
--*/
{
MNP_SERVICE_DATA *MnpServiceData;
NET_LIST_ENTRY *Entry;
NET_LIST_ENTRY *RxEntry;
NET_LIST_ENTRY *NextEntry;
MNP_INSTANCE_DATA *Instance;
MNP_RXDATA_WRAP *RxDataWrap;
MnpServiceData = (MNP_SERVICE_DATA *) Context;
NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
//
// Try to acquire the lock.
//
if (EFI_ERROR (NET_TRYLOCK (&MnpServiceData->ChildrenListLock))) {
MNP_DEBUG_WARN (("MnpCheckPacketTimeout: Acquire MnpServiceData->""ChildrenListLock failed.\n"));
return ;
}
NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {
Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);
NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);
if (!Instance->Configured || (Instance->ConfigData.ReceivedQueueTimeoutValue == 0)) {
//
// This instance is not configured or there is no receive time out,
// just skip to the next instance.
//
continue;
}
NET_LIST_FOR_EACH_SAFE (RxEntry, NextEntry, &Instance->RcvdPacketQueue) {
RxDataWrap = NET_LIST_USER_STRUCT (RxEntry, MNP_RXDATA_WRAP, WrapEntry);
if (RxDataWrap->TimeoutTick >= MNP_TIMEOUT_CHECK_INTERVAL) {
RxDataWrap->TimeoutTick -= MNP_TIMEOUT_CHECK_INTERVAL;
} else {
//
// Drop the timeout packet.
//
MNP_DEBUG_WARN (("MnpCheckPacketTimeout: Received packet timeout.\n"));
MnpRecycleRxData (NULL, RxDataWrap);
Instance->RcvdPacketQueueSize--;
}
}
}
NET_UNLOCK (&MnpServiceData->ChildrenListLock);
}
VOID
EFIAPI
MnpSystemPoll (
IN EFI_EVENT Event,
IN VOID *Context
)
/*++
Routine Description:
Poll to receive the packets from Snp. This function is either called by upperlayer
protocols/applications or the system poll timer notify mechanism.
Arguments:
Event - The event this notify function registered to.
Context - Pointer to the context data registered to the event.
Returns:
None.
--*/
{
MNP_SERVICE_DATA *MnpServiceData;
MnpServiceData = (MNP_SERVICE_DATA *) Context;
NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);
//
// Try to receive packets from Snp.
//
MnpReceivePacket (MnpServiceData);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?