mirror of https://github.com/acidanthera/audk.git
1909 lines
53 KiB
C
1909 lines
53 KiB
C
/** @file
|
|
The implementation of the Udp4 protocol.
|
|
|
|
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
|
|
#include "Udp4Impl.h"
|
|
|
|
UINT16 mUdp4RandomPort;
|
|
|
|
/**
|
|
This function checks and timeouts the I/O datagrams holding by the corresponding
|
|
service context.
|
|
|
|
@param[in] Event The event this function registered to.
|
|
@param[in] Context The context data registered during the creation of
|
|
the Event.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
Udp4CheckTimeout (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
);
|
|
|
|
/**
|
|
This function finds the udp instance by the specified <Address, Port> pair.
|
|
|
|
@param[in] InstanceList Pointer to the head of the list linking the udp
|
|
instances.
|
|
@param[in] Address Pointer to the specified IPv4 address.
|
|
@param[in] Port The udp port number.
|
|
|
|
@retval TRUE The specified <Address, Port> pair is found.
|
|
@retval FALSE Otherwise.
|
|
|
|
**/
|
|
BOOLEAN
|
|
Udp4FindInstanceByPort (
|
|
IN LIST_ENTRY *InstanceList,
|
|
IN EFI_IPv4_ADDRESS *Address,
|
|
IN UINT16 Port
|
|
);
|
|
|
|
/**
|
|
This function is the packet transmitting notify function registered to the IpIo
|
|
interface. It's called to signal the udp TxToken when IpIo layer completes the
|
|
transmitting of the udp datagram.
|
|
|
|
@param[in] Status The completion status of the output udp datagram.
|
|
@param[in] Context Pointer to the context data.
|
|
@param[in] Sender Specify a pointer of EFI_IP4_PROTOCOL for sending.
|
|
@param[in] NotifyData Pointer to the notify data.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
Udp4DgramSent (
|
|
IN EFI_STATUS Status,
|
|
IN VOID *Context,
|
|
IN IP_IO_IP_PROTOCOL Sender,
|
|
IN VOID *NotifyData
|
|
);
|
|
|
|
/**
|
|
This function processes the received datagram passed up by the IpIo layer.
|
|
|
|
@param[in] Status The status of this udp datagram.
|
|
@param[in] IcmpError The IcmpError code, only available when Status is
|
|
EFI_ICMP_ERROR.
|
|
@param[in] NetSession Pointer to the EFI_NET_SESSION_DATA.
|
|
@param[in] Packet Pointer to the NET_BUF containing the received udp
|
|
datagram.
|
|
@param[in] Context Pointer to the context data.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
Udp4DgramRcvd (
|
|
IN EFI_STATUS Status,
|
|
IN UINT8 IcmpError,
|
|
IN EFI_NET_SESSION_DATA *NetSession,
|
|
IN NET_BUF *Packet,
|
|
IN VOID *Context
|
|
);
|
|
|
|
/**
|
|
This function cancels the token specified by Arg in the Map. This is a callback
|
|
used by Udp4InstanceCancelToken().
|
|
|
|
@param[in] Map Pointer to the NET_MAP.
|
|
@param[in] Item Pointer to the NET_MAP_ITEM.
|
|
@param[in] Arg Pointer to the token to be cancelled, if NULL,
|
|
the token specified by Item is cancelled.
|
|
|
|
@retval EFI_SUCCESS The token is cancelled if Arg is NULL or the token
|
|
is not the same as that in the Item if Arg is not
|
|
NULL.
|
|
@retval EFI_ABORTED Arg is not NULL, and the token specified by Arg is
|
|
cancelled.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Udp4CancelTokens (
|
|
IN NET_MAP *Map,
|
|
IN NET_MAP_ITEM *Item,
|
|
IN VOID *Arg OPTIONAL
|
|
);
|
|
|
|
/**
|
|
This function matches the received udp datagram with the Instance.
|
|
|
|
@param[in] Instance Pointer to the udp instance context data.
|
|
@param[in] Udp4Session Pointer to the EFI_UDP4_SESSION_DATA abstracted
|
|
from the received udp datagram.
|
|
|
|
@retval TRUE The udp datagram matches the receiving requirements of the
|
|
udp Instance.
|
|
@retval FALSE Otherwise.
|
|
|
|
**/
|
|
BOOLEAN
|
|
Udp4MatchDgram (
|
|
IN UDP4_INSTANCE_DATA *Instance,
|
|
IN EFI_UDP4_SESSION_DATA *Udp4Session
|
|
);
|
|
|
|
/**
|
|
This function removes the Wrap specified by Context and release relevant resources.
|
|
|
|
@param[in] Event The Event this notify function registered to.
|
|
@param[in] Context Pointer to the context data.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
Udp4RecycleRxDataWrap (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
);
|
|
|
|
/**
|
|
This function wraps the Packet and the RxData.
|
|
|
|
@param[in] Instance Pointer to the instance context data.
|
|
@param[in] Packet Pointer to the buffer containing the received
|
|
datagram.
|
|
@param[in] RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this
|
|
datagram.
|
|
|
|
@return Pointer to the structure wrapping the RxData and the Packet.
|
|
|
|
**/
|
|
UDP4_RXDATA_WRAP *
|
|
Udp4WrapRxData (
|
|
IN UDP4_INSTANCE_DATA *Instance,
|
|
IN NET_BUF *Packet,
|
|
IN EFI_UDP4_RECEIVE_DATA *RxData
|
|
);
|
|
|
|
/**
|
|
This function enqueues the received datagram into the instances' receiving queues.
|
|
|
|
@param[in] Udp4Service Pointer to the udp service context data.
|
|
@param[in] Packet Pointer to the buffer containing the received
|
|
datagram.
|
|
@param[in] RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this
|
|
datagram.
|
|
|
|
@return The times this datagram is enqueued.
|
|
|
|
**/
|
|
UINTN
|
|
Udp4EnqueueDgram (
|
|
IN UDP4_SERVICE_DATA *Udp4Service,
|
|
IN NET_BUF *Packet,
|
|
IN EFI_UDP4_RECEIVE_DATA *RxData
|
|
);
|
|
|
|
/**
|
|
This function delivers the datagrams enqueued in the instances.
|
|
|
|
@param[in] Udp4Service Pointer to the udp service context data.
|
|
|
|
**/
|
|
VOID
|
|
Udp4DeliverDgram (
|
|
IN UDP4_SERVICE_DATA *Udp4Service
|
|
);
|
|
|
|
/**
|
|
This function demultiplexes the received udp datagram to the appropriate instances.
|
|
|
|
@param[in] Udp4Service Pointer to the udp service context data.
|
|
@param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstracted from
|
|
the received datagram.
|
|
@param[in] Packet Pointer to the buffer containing the received udp
|
|
datagram.
|
|
|
|
**/
|
|
VOID
|
|
Udp4Demultiplex (
|
|
IN UDP4_SERVICE_DATA *Udp4Service,
|
|
IN EFI_NET_SESSION_DATA *NetSession,
|
|
IN NET_BUF *Packet
|
|
);
|
|
|
|
/**
|
|
This function handles the received Icmp Error message and demultiplexes it to the
|
|
instance.
|
|
|
|
@param[in] Udp4Service Pointer to the udp service context data.
|
|
@param[in] IcmpError The icmp error code.
|
|
@param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstracted
|
|
from the received Icmp Error packet.
|
|
@param[in] Packet Pointer to the Icmp Error packet.
|
|
|
|
**/
|
|
VOID
|
|
Udp4IcmpHandler (
|
|
IN UDP4_SERVICE_DATA *Udp4Service,
|
|
IN UINT8 IcmpError,
|
|
IN EFI_NET_SESSION_DATA *NetSession,
|
|
IN NET_BUF *Packet
|
|
);
|
|
|
|
/**
|
|
This function builds and sends out a icmp port unreachable message.
|
|
|
|
@param[in] IpIo Pointer to the IP_IO instance.
|
|
@param[in] NetSession Pointer to the EFI_NET_SESSION_DATA of the packet
|
|
causes this icmp error message.
|
|
@param[in] Udp4Header Pointer to the udp header of the datagram causes
|
|
this icmp error message.
|
|
|
|
**/
|
|
VOID
|
|
Udp4SendPortUnreach (
|
|
IN IP_IO *IpIo,
|
|
IN EFI_NET_SESSION_DATA *NetSession,
|
|
IN VOID *Udp4Header
|
|
);
|
|
|
|
|
|
/**
|
|
Create the Udp service context data.
|
|
|
|
@param[in, out] Udp4Service Pointer to the UDP4_SERVICE_DATA.
|
|
@param[in] ImageHandle The image handle of this udp4 driver.
|
|
@param[in] ControllerHandle The controller handle this udp4 driver binds on.
|
|
|
|
@retval EFI_SUCCESS The udp4 service context data is created and
|
|
initialized.
|
|
@retval EFI_OUT_OF_RESOURCES Cannot allocate memory.
|
|
@retval other Other error occurs.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Udp4CreateService (
|
|
IN OUT UDP4_SERVICE_DATA *Udp4Service,
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_HANDLE ControllerHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
IP_IO_OPEN_DATA OpenData;
|
|
EFI_IP4_CONFIG_DATA *Ip4ConfigData;
|
|
|
|
ZeroMem (Udp4Service, sizeof (UDP4_SERVICE_DATA));
|
|
|
|
Udp4Service->Signature = UDP4_SERVICE_DATA_SIGNATURE;
|
|
Udp4Service->ServiceBinding = mUdp4ServiceBinding;
|
|
Udp4Service->ImageHandle = ImageHandle;
|
|
Udp4Service->ControllerHandle = ControllerHandle;
|
|
Udp4Service->ChildrenNumber = 0;
|
|
|
|
InitializeListHead (&Udp4Service->ChildrenList);
|
|
|
|
//
|
|
// Create the IpIo for this service context.
|
|
//
|
|
Udp4Service->IpIo = IpIoCreate (ImageHandle, ControllerHandle, IP_VERSION_4);
|
|
if (Udp4Service->IpIo == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Set the OpenData used to open the IpIo.
|
|
//
|
|
Ip4ConfigData = &OpenData.IpConfigData.Ip4CfgData;
|
|
CopyMem (Ip4ConfigData, &mIp4IoDefaultIpConfigData, sizeof (EFI_IP4_CONFIG_DATA));
|
|
Ip4ConfigData->AcceptBroadcast = TRUE;
|
|
OpenData.RcvdContext = (VOID *) Udp4Service;
|
|
OpenData.SndContext = NULL;
|
|
OpenData.PktRcvdNotify = Udp4DgramRcvd;
|
|
OpenData.PktSentNotify = Udp4DgramSent;
|
|
|
|
//
|
|
// Configure and start the IpIo.
|
|
//
|
|
Status = IpIoOpen (Udp4Service->IpIo, &OpenData);
|
|
if (EFI_ERROR (Status)) {
|
|
goto ON_ERROR;
|
|
}
|
|
|
|
//
|
|
// Create the event for Udp timeout checking.
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EVT_TIMER | EVT_NOTIFY_SIGNAL,
|
|
TPL_CALLBACK,
|
|
Udp4CheckTimeout,
|
|
Udp4Service,
|
|
&Udp4Service->TimeoutEvent
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto ON_ERROR;
|
|
}
|
|
|
|
//
|
|
// Start the timeout timer event.
|
|
//
|
|
Status = gBS->SetTimer (
|
|
Udp4Service->TimeoutEvent,
|
|
TimerPeriodic,
|
|
UDP4_TIMEOUT_INTERVAL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto ON_ERROR;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
ON_ERROR:
|
|
|
|
if (Udp4Service->TimeoutEvent != NULL) {
|
|
gBS->CloseEvent (Udp4Service->TimeoutEvent);
|
|
}
|
|
|
|
IpIoDestroy (Udp4Service->IpIo);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Clean the Udp service context data.
|
|
|
|
@param[in] Udp4Service Pointer to the UDP4_SERVICE_DATA.
|
|
|
|
**/
|
|
VOID
|
|
Udp4CleanService (
|
|
IN UDP4_SERVICE_DATA *Udp4Service
|
|
)
|
|
{
|
|
//
|
|
// Cancel the TimeoutEvent timer.
|
|
//
|
|
gBS->SetTimer (Udp4Service->TimeoutEvent, TimerCancel, 0);
|
|
|
|
//
|
|
// Close the TimeoutEvent timer.
|
|
//
|
|
gBS->CloseEvent (Udp4Service->TimeoutEvent);
|
|
|
|
//
|
|
// Destroy the IpIo.
|
|
//
|
|
IpIoDestroy (Udp4Service->IpIo);
|
|
}
|
|
|
|
|
|
/**
|
|
This function checks and timeouts the I/O datagrams holding by the corresponding
|
|
service context.
|
|
|
|
@param[in] Event The event this function registered to.
|
|
@param[in] Context The context data registered during the creation of
|
|
the Event.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
Udp4CheckTimeout (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
UDP4_SERVICE_DATA *Udp4Service;
|
|
LIST_ENTRY *Entry;
|
|
UDP4_INSTANCE_DATA *Instance;
|
|
LIST_ENTRY *WrapEntry;
|
|
LIST_ENTRY *NextEntry;
|
|
UDP4_RXDATA_WRAP *Wrap;
|
|
|
|
Udp4Service = (UDP4_SERVICE_DATA *) Context;
|
|
NET_CHECK_SIGNATURE (Udp4Service, UDP4_SERVICE_DATA_SIGNATURE);
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
This function initializes the new created udp instance.
|
|
|
|
@param[in] Udp4Service Pointer to the UDP4_SERVICE_DATA.
|
|
@param[in, out] Instance Pointer to the un-initialized UDP4_INSTANCE_DATA.
|
|
|
|
**/
|
|
VOID
|
|
Udp4InitInstance (
|
|
IN UDP4_SERVICE_DATA *Udp4Service,
|
|
IN OUT UDP4_INSTANCE_DATA *Instance
|
|
)
|
|
{
|
|
//
|
|
// Set the signature.
|
|
//
|
|
Instance->Signature = UDP4_INSTANCE_DATA_SIGNATURE;
|
|
|
|
//
|
|
// Init the lists.
|
|
//
|
|
InitializeListHead (&Instance->Link);
|
|
InitializeListHead (&Instance->RcvdDgramQue);
|
|
InitializeListHead (&Instance->DeliveredDgramQue);
|
|
|
|
//
|
|
// Init the NET_MAPs.
|
|
//
|
|
NetMapInit (&Instance->TxTokens);
|
|
NetMapInit (&Instance->RxTokens);
|
|
NetMapInit (&Instance->McastIps);
|
|
|
|
//
|
|
// Save the pointer to the UDP4_SERVICE_DATA, and initialize other members.
|
|
//
|
|
Instance->Udp4Service = Udp4Service;
|
|
CopyMem (&Instance->Udp4Proto, &mUdp4Protocol, sizeof (Instance->Udp4Proto));
|
|
Instance->IcmpError = EFI_SUCCESS;
|
|
Instance->Configured = FALSE;
|
|
Instance->IsNoMapping = FALSE;
|
|
Instance->InDestroy = FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
This function cleans the udp instance.
|
|
|
|
@param[in] Instance Pointer to the UDP4_INSTANCE_DATA to clean.
|
|
|
|
**/
|
|
VOID
|
|
Udp4CleanInstance (
|
|
IN UDP4_INSTANCE_DATA *Instance
|
|
)
|
|
{
|
|
NetMapClean (&Instance->McastIps);
|
|
NetMapClean (&Instance->RxTokens);
|
|
NetMapClean (&Instance->TxTokens);
|
|
}
|
|
|
|
|
|
/**
|
|
This function finds the udp instance by the specified <Address, Port> pair.
|
|
|
|
@param[in] InstanceList Pointer to the head of the list linking the udp
|
|
instances.
|
|
@param[in] Address Pointer to the specified IPv4 address.
|
|
@param[in] Port The udp port number.
|
|
|
|
@retval TRUE The specified <Address, Port> pair is found.
|
|
@retval FALSE Otherwise.
|
|
|
|
**/
|
|
BOOLEAN
|
|
Udp4FindInstanceByPort (
|
|
IN LIST_ENTRY *InstanceList,
|
|
IN EFI_IPv4_ADDRESS *Address,
|
|
IN UINT16 Port
|
|
)
|
|
{
|
|
LIST_ENTRY *Entry;
|
|
UDP4_INSTANCE_DATA *Instance;
|
|
EFI_UDP4_CONFIG_DATA *ConfigData;
|
|
|
|
NET_LIST_FOR_EACH (Entry, InstanceList) {
|
|
//
|
|
// Iterate all the udp instances.
|
|
//
|
|
Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);
|
|
ConfigData = &Instance->ConfigData;
|
|
|
|
if (!Instance->Configured || ConfigData->AcceptAnyPort) {
|
|
//
|
|
// If the instance is not configured or the configdata of the instance indicates
|
|
// this instance accepts any port, skip it.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
if (EFI_IP4_EQUAL (&ConfigData->StationAddress, Address) &&
|
|
(ConfigData->StationPort == Port)) {
|
|
//
|
|
// if both the address and the port are the same, return TRUE.
|
|
//
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// return FALSE when matching fails.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
This function tries to bind the udp instance according to the configured port
|
|
allocation strategy.
|
|
|
|
@param[in] InstanceList Pointer to the head of the list linking the udp
|
|
instances.
|
|
@param[in, out] ConfigData Pointer to the ConfigData of the instance to be
|
|
bound. ConfigData->StationPort will be assigned
|
|
with an available port value on success.
|
|
|
|
@retval EFI_SUCCESS The bound operation is completed successfully.
|
|
@retval EFI_ACCESS_DENIED The <Address, Port> specified by the ConfigData is
|
|
already used by other instance.
|
|
@retval EFI_OUT_OF_RESOURCES No available port resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Udp4Bind (
|
|
IN LIST_ENTRY *InstanceList,
|
|
IN OUT EFI_UDP4_CONFIG_DATA *ConfigData
|
|
)
|
|
{
|
|
EFI_IPv4_ADDRESS *StationAddress;
|
|
UINT16 StartPort;
|
|
|
|
if (ConfigData->AcceptAnyPort) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
StationAddress = &ConfigData->StationAddress;
|
|
|
|
if (ConfigData->StationPort != 0) {
|
|
|
|
if (!ConfigData->AllowDuplicatePort &&
|
|
Udp4FindInstanceByPort (InstanceList, StationAddress, ConfigData->StationPort)) {
|
|
//
|
|
// Do not allow duplicate port and the port is already used by other instance.
|
|
//
|
|
return EFI_ACCESS_DENIED;
|
|
}
|
|
} else {
|
|
//
|
|
// select a random port for this instance;
|
|
//
|
|
|
|
if (ConfigData->AllowDuplicatePort) {
|
|
//
|
|
// Just pick up the random port if the instance allows duplicate port.
|
|
//
|
|
ConfigData->StationPort = mUdp4RandomPort;
|
|
} else {
|
|
|
|
StartPort = mUdp4RandomPort;
|
|
|
|
while (Udp4FindInstanceByPort(InstanceList, StationAddress, mUdp4RandomPort)) {
|
|
|
|
mUdp4RandomPort++;
|
|
if (mUdp4RandomPort == 0) {
|
|
mUdp4RandomPort = UDP4_PORT_KNOWN;
|
|
}
|
|
|
|
if (mUdp4RandomPort == StartPort) {
|
|
//
|
|
// No available port.
|
|
//
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
}
|
|
|
|
ConfigData->StationPort = mUdp4RandomPort;
|
|
}
|
|
|
|
mUdp4RandomPort++;
|
|
if (mUdp4RandomPort == 0) {
|
|
mUdp4RandomPort = UDP4_PORT_KNOWN;
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
This function is used to check whether the NewConfigData has any un-reconfigurable
|
|
parameters changed compared to the OldConfigData.
|
|
|
|
@param[in] OldConfigData Pointer to the current ConfigData the udp instance
|
|
uses.
|
|
@param[in] NewConfigData Pointer to the new ConfigData.
|
|
|
|
@retval TRUE The instance is reconfigurable.
|
|
@retval FALSE Otherwise.
|
|
|
|
**/
|
|
BOOLEAN
|
|
Udp4IsReconfigurable (
|
|
IN EFI_UDP4_CONFIG_DATA *OldConfigData,
|
|
IN EFI_UDP4_CONFIG_DATA *NewConfigData
|
|
)
|
|
{
|
|
if ((NewConfigData->AcceptAnyPort != OldConfigData->AcceptAnyPort) ||
|
|
(NewConfigData->AcceptBroadcast != OldConfigData->AcceptBroadcast) ||
|
|
(NewConfigData->AcceptPromiscuous != OldConfigData->AcceptPromiscuous) ||
|
|
(NewConfigData->AllowDuplicatePort != OldConfigData->AllowDuplicatePort)
|
|
) {
|
|
//
|
|
// The receiving filter parameters cannot be changed.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
if ((!NewConfigData->AcceptAnyPort) &&
|
|
(NewConfigData->StationPort != OldConfigData->StationPort)
|
|
) {
|
|
//
|
|
// The port is not changeable.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
if (!NewConfigData->AcceptPromiscuous) {
|
|
|
|
if (NewConfigData->UseDefaultAddress != OldConfigData->UseDefaultAddress) {
|
|
//
|
|
// The NewConfigData differs to the old one on the UseDefaultAddress.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
if (!NewConfigData->UseDefaultAddress &&
|
|
(!EFI_IP4_EQUAL (&NewConfigData->StationAddress, &OldConfigData->StationAddress) ||
|
|
!EFI_IP4_EQUAL (&NewConfigData->SubnetMask, &OldConfigData->SubnetMask))
|
|
) {
|
|
//
|
|
// If the instance doesn't use the default address, and the new address or
|
|
// new subnet mask is different from the old values.
|
|
//
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (!EFI_IP4_EQUAL (&NewConfigData->RemoteAddress, &OldConfigData->RemoteAddress)) {
|
|
//
|
|
// The remoteaddress is not the same.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
if (!EFI_IP4_EQUAL (&NewConfigData->RemoteAddress, &mZeroIp4Addr) &&
|
|
NewConfigData->RemotePort != OldConfigData->RemotePort
|
|
) {
|
|
//
|
|
// The RemotePort differs if it's designated in the configdata.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// All checks pass, return TRUE.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**
|
|
This function builds the Ip4 configdata from the Udp4ConfigData.
|
|
|
|
@param[in] Udp4ConfigData Pointer to the EFI_UDP4_CONFIG_DATA.
|
|
@param[in, out] Ip4ConfigData Pointer to the EFI_IP4_CONFIG_DATA.
|
|
|
|
**/
|
|
VOID
|
|
Udp4BuildIp4ConfigData (
|
|
IN EFI_UDP4_CONFIG_DATA *Udp4ConfigData,
|
|
IN OUT EFI_IP4_CONFIG_DATA *Ip4ConfigData
|
|
)
|
|
{
|
|
CopyMem (Ip4ConfigData, &mIp4IoDefaultIpConfigData, sizeof (*Ip4ConfigData));
|
|
|
|
Ip4ConfigData->DefaultProtocol = EFI_IP_PROTO_UDP;
|
|
Ip4ConfigData->AcceptBroadcast = Udp4ConfigData->AcceptBroadcast;
|
|
Ip4ConfigData->AcceptPromiscuous = Udp4ConfigData->AcceptPromiscuous;
|
|
Ip4ConfigData->UseDefaultAddress = Udp4ConfigData->UseDefaultAddress;
|
|
CopyMem (&Ip4ConfigData->StationAddress, &Udp4ConfigData->StationAddress, sizeof (EFI_IPv4_ADDRESS));
|
|
CopyMem (&Ip4ConfigData->SubnetMask, &Udp4ConfigData->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
|
|
|
|
//
|
|
// use the -1 magic number to disable the receiving process of the ip instance.
|
|
//
|
|
Ip4ConfigData->ReceiveTimeout = (UINT32) (-1);
|
|
}
|
|
|
|
|
|
/**
|
|
This function validates the TxToken, it returns the error code according to the spec.
|
|
|
|
@param[in] Instance Pointer to the udp instance context data.
|
|
@param[in] TxToken Pointer to the token to be checked.
|
|
|
|
@retval EFI_SUCCESS The TxToken is valid.
|
|
@retval EFI_INVALID_PARAMETER One or more of the following are TRUE: This is
|
|
NULL. Token is NULL. Token.Event is NULL.
|
|
Token.Packet.TxData is NULL.
|
|
Token.Packet.TxData.FragmentCount is zero.
|
|
Token.Packet.TxData.DataLength is not equal to the
|
|
sum of fragment lengths. One or more of the
|
|
Token.Packet.TxData.FragmentTable[].
|
|
FragmentLength fields is zero. One or more of the
|
|
Token.Packet.TxData.FragmentTable[].
|
|
FragmentBuffer fields is NULL.
|
|
Token.Packet.TxData. GatewayAddress is not a
|
|
unicast IPv4 address if it is not NULL. One or
|
|
more IPv4 addresses in Token.Packet.TxData.
|
|
UdpSessionData are not valid unicast IPv4
|
|
addresses if the UdpSessionData is not NULL.
|
|
@retval EFI_BAD_BUFFER_SIZE The data length is greater than the maximum UDP
|
|
packet size.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Udp4ValidateTxToken (
|
|
IN UDP4_INSTANCE_DATA *Instance,
|
|
IN EFI_UDP4_COMPLETION_TOKEN *TxToken
|
|
)
|
|
{
|
|
EFI_UDP4_TRANSMIT_DATA *TxData;
|
|
UINT32 Index;
|
|
UINT32 TotalLen;
|
|
EFI_UDP4_CONFIG_DATA *ConfigData;
|
|
EFI_UDP4_SESSION_DATA *UdpSessionData;
|
|
IP4_ADDR SourceAddress;
|
|
IP4_ADDR GatewayAddress;
|
|
|
|
if (TxToken->Event == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
TxData = TxToken->Packet.TxData;
|
|
|
|
if ((TxData == NULL) || (TxData->FragmentCount == 0)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
TotalLen = 0;
|
|
for (Index = 0; Index < TxData->FragmentCount; Index++) {
|
|
|
|
if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||
|
|
(TxData->FragmentTable[Index].FragmentLength == 0)) {
|
|
//
|
|
// if the FragmentBuffer is NULL or the FragmentLeng is zero.
|
|
//
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
TotalLen += TxData->FragmentTable[Index].FragmentLength;
|
|
}
|
|
|
|
if (TotalLen != TxData->DataLength) {
|
|
//
|
|
// The TotalLen calculated by adding all the FragmentLeng doesn't equal to the
|
|
// DataLength.
|
|
//
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (TxData->GatewayAddress != NULL) {
|
|
CopyMem (&GatewayAddress, TxData->GatewayAddress, sizeof (IP4_ADDR));
|
|
|
|
if (!Instance->ConfigData.UseDefaultAddress &&
|
|
(EFI_NTOHL(Instance->ConfigData.SubnetMask) != 0) &&
|
|
!NetIp4IsUnicast (NTOHL (GatewayAddress), EFI_NTOHL(Instance->ConfigData.SubnetMask))) {
|
|
//
|
|
// The specified GatewayAddress is not a unicast IPv4 address while it's not 0.
|
|
//
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
ConfigData = &Instance->ConfigData;
|
|
UdpSessionData = TxData->UdpSessionData;
|
|
|
|
if (UdpSessionData != NULL) {
|
|
|
|
CopyMem (&SourceAddress, &UdpSessionData->SourceAddress, sizeof (IP4_ADDR));
|
|
|
|
if ((SourceAddress != 0) &&
|
|
!Instance->ConfigData.UseDefaultAddress &&
|
|
(EFI_NTOHL(Instance->ConfigData.SubnetMask) != 0) &&
|
|
!NetIp4IsUnicast (HTONL (SourceAddress), EFI_NTOHL(Instance->ConfigData.SubnetMask))) {
|
|
//
|
|
// Check whether SourceAddress is a valid IPv4 address in case it's not zero.
|
|
// The configured station address is used if SourceAddress is zero.
|
|
//
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((UdpSessionData->DestinationPort == 0) && (ConfigData->RemotePort == 0)) {
|
|
//
|
|
// Ambiguous, no available DestinationPort for this token.
|
|
//
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (EFI_IP4_EQUAL (&UdpSessionData->DestinationAddress, &mZeroIp4Addr)) {
|
|
//
|
|
// The DestinationAddress specified in the UdpSessionData is 0.
|
|
//
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
} else if (EFI_IP4_EQUAL (&ConfigData->RemoteAddress, &mZeroIp4Addr)) {
|
|
//
|
|
// the configured RemoteAddress is all zero, and the user doesn't override the
|
|
// destination address.
|
|
//
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (TxData->DataLength > UDP4_MAX_DATA_SIZE) {
|
|
return EFI_BAD_BUFFER_SIZE;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
This function checks whether the specified Token duplicates with the one in the Map.
|
|
|
|
@param[in] Map Pointer to the NET_MAP.
|
|
@param[in] Item Pointer to the NET_MAP_ITEM contain the pointer to
|
|
the Token.
|
|
@param[in] Context Pointer to the Token to be checked.
|
|
|
|
@retval EFI_SUCCESS The Token specified by Context differs from the
|
|
one in the Item.
|
|
@retval EFI_ACCESS_DENIED The Token duplicates with the one in the Item.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Udp4TokenExist (
|
|
IN NET_MAP *Map,
|
|
IN NET_MAP_ITEM *Item,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_UDP4_COMPLETION_TOKEN *Token;
|
|
EFI_UDP4_COMPLETION_TOKEN *TokenInItem;
|
|
|
|
Token = (EFI_UDP4_COMPLETION_TOKEN*) Context;
|
|
TokenInItem = (EFI_UDP4_COMPLETION_TOKEN*) Item->Key;
|
|
|
|
if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
|
|
//
|
|
// The Token duplicates with the TokenInItem in case either the two pointers are the
|
|
// same or the Events of these two tokens are the same.
|
|
//
|
|
return EFI_ACCESS_DENIED;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
This function calculates the checksum for the Packet, utilizing the pre-calculated
|
|
pseudo HeadSum to reduce some overhead.
|
|
|
|
@param[in] Packet Pointer to the NET_BUF contains the udp datagram.
|
|
@param[in] HeadSum Checksum of the pseudo header except the length
|
|
field.
|
|
|
|
@retval The 16-bit checksum of this udp datagram.
|
|
|
|
**/
|
|
UINT16
|
|
Udp4Checksum (
|
|
IN NET_BUF *Packet,
|
|
IN UINT16 HeadSum
|
|
)
|
|
{
|
|
UINT16 Checksum;
|
|
|
|
Checksum = NetbufChecksum (Packet);
|
|
Checksum = NetAddChecksum (Checksum, HeadSum);
|
|
|
|
Checksum = NetAddChecksum (Checksum, HTONS ((UINT16) Packet->TotalSize));
|
|
|
|
return (UINT16) ~Checksum;
|
|
}
|
|
|
|
|
|
/**
|
|
This function removes the specified Token from the TokenMap.
|
|
|
|
@param[in, out] TokenMap Pointer to the NET_MAP containing the tokens.
|
|
@param[in] Token Pointer to the Token to be removed.
|
|
|
|
@retval EFI_SUCCESS The specified Token is removed from the TokenMap.
|
|
@retval EFI_NOT_FOUND The specified Token is not found in the TokenMap.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Udp4RemoveToken (
|
|
IN OUT NET_MAP *TokenMap,
|
|
IN EFI_UDP4_COMPLETION_TOKEN *Token
|
|
)
|
|
{
|
|
NET_MAP_ITEM *Item;
|
|
|
|
//
|
|
// Find the Token first.
|
|
//
|
|
Item = NetMapFindKey (TokenMap, (VOID *) Token);
|
|
|
|
if (Item != NULL) {
|
|
//
|
|
// Remove the token if it's found in the map.
|
|
//
|
|
NetMapRemoveItem (TokenMap, Item, NULL);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
|
|
/**
|
|
This function is the packet transmitting notify function registered to the IpIo
|
|
interface. It's called to signal the udp TxToken when IpIo layer completes the
|
|
transmitting of the udp datagram.
|
|
|
|
@param[in] Status The completion status of the output udp datagram.
|
|
@param[in] Context Pointer to the context data.
|
|
@param[in] Sender Specify a pointer of EFI_IP4_PROTOCOL for sending.
|
|
@param[in] NotifyData Pointer to the notify data.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
Udp4DgramSent (
|
|
IN EFI_STATUS Status,
|
|
IN VOID *Context,
|
|
IN IP_IO_IP_PROTOCOL Sender,
|
|
IN VOID *NotifyData
|
|
)
|
|
{
|
|
UDP4_INSTANCE_DATA *Instance;
|
|
EFI_UDP4_COMPLETION_TOKEN *Token;
|
|
|
|
Instance = (UDP4_INSTANCE_DATA *) Context;
|
|
Token = (EFI_UDP4_COMPLETION_TOKEN *) NotifyData;
|
|
|
|
if (Udp4RemoveToken (&Instance->TxTokens, Token) == EFI_SUCCESS) {
|
|
//
|
|
// The token may be cancelled. Only signal it if the remove operation succeeds.
|
|
//
|
|
Token->Status = Status;
|
|
gBS->SignalEvent (Token->Event);
|
|
DispatchDpc ();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
This function processes the received datagram passed up by the IpIo layer.
|
|
|
|
@param[in] Status The status of this udp datagram.
|
|
@param[in] IcmpError The IcmpError code, only available when Status is
|
|
EFI_ICMP_ERROR.
|
|
@param[in] NetSession Pointer to the EFI_NET_SESSION_DATA.
|
|
@param[in] Packet Pointer to the NET_BUF containing the received udp
|
|
datagram.
|
|
@param[in] Context Pointer to the context data.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
Udp4DgramRcvd (
|
|
IN EFI_STATUS Status,
|
|
IN UINT8 IcmpError,
|
|
IN EFI_NET_SESSION_DATA *NetSession,
|
|
IN NET_BUF *Packet,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
NET_CHECK_SIGNATURE (Packet, NET_BUF_SIGNATURE);
|
|
|
|
//
|
|
// IpIo only passes received packets with Status EFI_SUCCESS or EFI_ICMP_ERROR.
|
|
//
|
|
if (Status == EFI_SUCCESS) {
|
|
//
|
|
// Demultiplex the received datagram.
|
|
//
|
|
Udp4Demultiplex ((UDP4_SERVICE_DATA *) Context, NetSession, Packet);
|
|
} else {
|
|
//
|
|
// Handle the ICMP_ERROR packet.
|
|
//
|
|
Udp4IcmpHandler ((UDP4_SERVICE_DATA *) Context, IcmpError, NetSession, Packet);
|
|
}
|
|
|
|
//
|
|
// Dispatch the DPC queued by the NotifyFunction of the rx token's events
|
|
// which are signaled with received data.
|
|
//
|
|
DispatchDpc ();
|
|
}
|
|
|
|
|
|
/**
|
|
This function removes the multicast group specified by Arg from the Map.
|
|
|
|
@param[in, out] Map Pointer to the NET_MAP.
|
|
@param[in] Item Pointer to the NET_MAP_ITEM.
|
|
@param[in] Arg Pointer to the Arg, it's the pointer to a
|
|
multicast IPv4 Address.
|
|
|
|
@retval EFI_SUCCESS The multicast address is removed.
|
|
@retval EFI_ABORTED The specified multicast address is removed and the
|
|
Arg is not NULL.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Udp4LeaveGroup (
|
|
IN OUT NET_MAP *Map,
|
|
IN NET_MAP_ITEM *Item,
|
|
IN VOID *Arg OPTIONAL
|
|
)
|
|
{
|
|
EFI_IPv4_ADDRESS *McastIp;
|
|
|
|
McastIp = Arg;
|
|
|
|
if ((McastIp != NULL) && (!EFI_IP4_EQUAL (McastIp, &(Item->Key)))) {
|
|
//
|
|
// McastIp is not NULL and the multicast address contained in the Item
|
|
// is not the same as McastIp.
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Remove this Item.
|
|
//
|
|
NetMapRemoveItem (Map, Item, NULL);
|
|
|
|
if (McastIp != NULL) {
|
|
//
|
|
// Return EFI_ABORTED in case McastIp is not NULL to terminate the iteration.
|
|
//
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
This function cancels the token specified by Arg in the Map. This is a callback
|
|
used by Udp4InstanceCancelToken().
|
|
|
|
@param[in] Map Pointer to the NET_MAP.
|
|
@param[in] Item Pointer to the NET_MAP_ITEM.
|
|
@param[in] Arg Pointer to the token to be cancelled, if NULL,
|
|
the token specified by Item is cancelled.
|
|
|
|
@retval EFI_SUCCESS The token is cancelled if Arg is NULL or the token
|
|
is not the same as that in the Item if Arg is not
|
|
NULL.
|
|
@retval EFI_ABORTED Arg is not NULL, and the token specified by Arg is
|
|
cancelled.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
Udp4CancelTokens (
|
|
IN NET_MAP *Map,
|
|
IN NET_MAP_ITEM *Item,
|
|
IN VOID *Arg OPTIONAL
|
|
)
|
|
{
|
|
EFI_UDP4_COMPLETION_TOKEN *TokenToCancel;
|
|
NET_BUF *Packet;
|
|
IP_IO *IpIo;
|
|
|
|
if ((Arg != NULL) && (Item->Key != Arg)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (Item->Value != NULL) {
|
|
//
|
|
// If the token is a transmit token, the corresponding Packet is recorded in
|
|
// Item->Value, invoke IpIo to cancel this packet first. The IpIoCancelTxToken
|
|
// will invoke Udp4DgramSent, the token will be signaled and this Item will
|
|
// be removed from the Map there.
|
|
//
|
|
Packet = (NET_BUF *) (Item->Value);
|
|
IpIo = (IP_IO *) (*((UINTN *) &Packet->ProtoData[0]));
|
|
|
|
IpIoCancelTxToken (IpIo, Packet);
|
|
} else {
|
|
//
|
|
// The token is a receive token. Abort it and remove it from the Map.
|
|
//
|
|
TokenToCancel = (EFI_UDP4_COMPLETION_TOKEN *) Item->Key;
|
|
NetMapRemoveItem (Map, Item, NULL);
|
|
|
|
TokenToCancel->Status = EFI_ABORTED;
|
|
gBS->SignalEvent (TokenToCancel->Event);
|
|
}
|
|
|
|
if (Arg != NULL) {
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
This function removes all the Wrap datas in the RcvdDgramQue.
|
|
|
|
@param[in] Instance Pointer to the udp instance context data.
|
|
|
|
**/
|
|
VOID
|
|
Udp4FlushRcvdDgram (
|
|
IN UDP4_INSTANCE_DATA *Instance
|
|
)
|
|
{
|
|
UDP4_RXDATA_WRAP *Wrap;
|
|
|
|
while (!IsListEmpty (&Instance->RcvdDgramQue)) {
|
|
//
|
|
// Iterate all the Wraps in the RcvdDgramQue.
|
|
//
|
|
Wrap = NET_LIST_HEAD (&Instance->RcvdDgramQue, UDP4_RXDATA_WRAP, Link);
|
|
|
|
//
|
|
// The Wrap will be removed from the RcvdDgramQue by this function call.
|
|
//
|
|
Udp4RecycleRxDataWrap (NULL, (VOID *) Wrap);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Cancel Udp4 tokens from the Udp4 instance.
|
|
|
|
@param[in] Instance Pointer to the udp instance context data.
|
|
@param[in] Token Pointer to the token to be canceled, if NULL, all
|
|
tokens in this instance will be cancelled.
|
|
|
|
@retval EFI_SUCCESS The Token is cancelled.
|
|
@retval EFI_NOT_FOUND The Token is not found.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Udp4InstanceCancelToken (
|
|
IN UDP4_INSTANCE_DATA *Instance,
|
|
IN EFI_UDP4_COMPLETION_TOKEN *Token OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Cancel this token from the TxTokens map.
|
|
//
|
|
Status = NetMapIterate (&Instance->TxTokens, Udp4CancelTokens, Token);
|
|
|
|
if ((Token != NULL) && (Status == EFI_ABORTED)) {
|
|
//
|
|
// If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from
|
|
// the TxTokens, just return success.
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Try to cancel this token from the RxTokens map in condition either the Token
|
|
// is NULL or the specified Token is not in TxTokens.
|
|
//
|
|
Status = NetMapIterate (&Instance->RxTokens, Udp4CancelTokens, Token);
|
|
|
|
if ((Token != NULL) && (Status == EFI_SUCCESS)) {
|
|
//
|
|
// If Token isn't NULL and Status is EFI_SUCCESS, the token is neither in the
|
|
// TxTokens nor the RxTokens, or say, it's not found.
|
|
//
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
ASSERT ((Token != NULL) || ((0 == NetMapGetCount (&Instance->TxTokens))
|
|
&& (0 == NetMapGetCount (&Instance->RxTokens))));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
This function matches the received udp datagram with the Instance.
|
|
|
|
@param[in] Instance Pointer to the udp instance context data.
|
|
@param[in] Udp4Session Pointer to the EFI_UDP4_SESSION_DATA abstracted
|
|
from the received udp datagram.
|
|
|
|
@retval TRUE The udp datagram matches the receiving requirements of the
|
|
udp Instance.
|
|
@retval FALSE Otherwise.
|
|
|
|
**/
|
|
BOOLEAN
|
|
Udp4MatchDgram (
|
|
IN UDP4_INSTANCE_DATA *Instance,
|
|
IN EFI_UDP4_SESSION_DATA *Udp4Session
|
|
)
|
|
{
|
|
EFI_UDP4_CONFIG_DATA *ConfigData;
|
|
IP4_ADDR Destination;
|
|
|
|
ConfigData = &Instance->ConfigData;
|
|
|
|
if (ConfigData->AcceptPromiscuous) {
|
|
//
|
|
// Always matches if this instance is in the promiscuous state.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
if ((!ConfigData->AcceptAnyPort && (Udp4Session->DestinationPort != ConfigData->StationPort)) ||
|
|
((ConfigData->RemotePort != 0) && (Udp4Session->SourcePort != ConfigData->RemotePort))
|
|
) {
|
|
//
|
|
// The local port or the remote port doesn't match.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
if (!EFI_IP4_EQUAL (&ConfigData->RemoteAddress, &mZeroIp4Addr) &&
|
|
!EFI_IP4_EQUAL (&ConfigData->RemoteAddress, &Udp4Session->SourceAddress)
|
|
) {
|
|
//
|
|
// This datagram doesn't come from the instance's specified sender.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
if (EFI_IP4_EQUAL (&ConfigData->StationAddress, &mZeroIp4Addr) ||
|
|
EFI_IP4_EQUAL (&Udp4Session->DestinationAddress, &ConfigData->StationAddress)
|
|
) {
|
|
//
|
|
// The instance is configured to receive datagrams destined to any station IP or
|
|
// the destination address of this datagram matches the configured station IP.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
CopyMem (&Destination, &Udp4Session->DestinationAddress, sizeof (IP4_ADDR));
|
|
|
|
if (IP4_IS_LOCAL_BROADCAST (Destination) && ConfigData->AcceptBroadcast) {
|
|
//
|
|
// The instance is configured to receive broadcast and this is a broadcast packet.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
if (IP4_IS_MULTICAST (NTOHL (Destination)) &&
|
|
NetMapFindKey (&Instance->McastIps, (VOID *) (UINTN) Destination) != NULL
|
|
) {
|
|
//
|
|
// It's a multicast packet and the multicast address is accepted by this instance.
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
This function removes the Wrap specified by Context and release relevant resources.
|
|
|
|
@param[in] Event The Event this notify function registered to.
|
|
@param[in] Context Pointer to the context data.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
Udp4RecycleRxDataWrap (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
UDP4_RXDATA_WRAP *Wrap;
|
|
|
|
Wrap = (UDP4_RXDATA_WRAP *) Context;
|
|
|
|
//
|
|
// Remove the Wrap from the list it belongs to.
|
|
//
|
|
RemoveEntryList (&Wrap->Link);
|
|
|
|
//
|
|
// Free the Packet associated with this Wrap.
|
|
//
|
|
NetbufFree (Wrap->Packet);
|
|
|
|
//
|
|
// Close the event.
|
|
//
|
|
gBS->CloseEvent (Wrap->RxData.RecycleSignal);
|
|
|
|
FreePool (Wrap);
|
|
}
|
|
|
|
|
|
/**
|
|
This function wraps the Packet and the RxData.
|
|
|
|
@param[in] Instance Pointer to the instance context data.
|
|
@param[in] Packet Pointer to the buffer containing the received
|
|
datagram.
|
|
@param[in] RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this
|
|
datagram.
|
|
|
|
@return Pointer to the structure wrapping the RxData and the Packet.
|
|
|
|
**/
|
|
UDP4_RXDATA_WRAP *
|
|
Udp4WrapRxData (
|
|
IN UDP4_INSTANCE_DATA *Instance,
|
|
IN NET_BUF *Packet,
|
|
IN EFI_UDP4_RECEIVE_DATA *RxData
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UDP4_RXDATA_WRAP *Wrap;
|
|
|
|
//
|
|
// Allocate buffer for the Wrap.
|
|
//
|
|
Wrap = AllocatePool (sizeof (UDP4_RXDATA_WRAP) +
|
|
(Packet->BlockOpNum - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA));
|
|
if (Wrap == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
InitializeListHead (&Wrap->Link);
|
|
|
|
CopyMem (&Wrap->RxData, RxData, sizeof (Wrap->RxData));
|
|
|
|
//
|
|
// Create the Recycle event.
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
Udp4RecycleRxDataWrap,
|
|
Wrap,
|
|
&Wrap->RxData.RecycleSignal
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (Wrap);
|
|
return NULL;
|
|
}
|
|
|
|
Wrap->Packet = Packet;
|
|
Wrap->TimeoutTick = Instance->ConfigData.ReceiveTimeout;
|
|
|
|
return Wrap;
|
|
}
|
|
|
|
|
|
/**
|
|
This function enqueues the received datagram into the instances' receiving queues.
|
|
|
|
@param[in] Udp4Service Pointer to the udp service context data.
|
|
@param[in] Packet Pointer to the buffer containing the received
|
|
datagram.
|
|
@param[in] RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this
|
|
datagram.
|
|
|
|
@return The times this datagram is enqueued.
|
|
|
|
**/
|
|
UINTN
|
|
Udp4EnqueueDgram (
|
|
IN UDP4_SERVICE_DATA *Udp4Service,
|
|
IN NET_BUF *Packet,
|
|
IN EFI_UDP4_RECEIVE_DATA *RxData
|
|
)
|
|
{
|
|
LIST_ENTRY *Entry;
|
|
UDP4_INSTANCE_DATA *Instance;
|
|
UDP4_RXDATA_WRAP *Wrap;
|
|
UINTN Enqueued;
|
|
|
|
Enqueued = 0;
|
|
|
|
NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {
|
|
//
|
|
// Iterate the instances.
|
|
//
|
|
Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);
|
|
|
|
if (!Instance->Configured) {
|
|
continue;
|
|
}
|
|
|
|
if (Udp4MatchDgram (Instance, &RxData->UdpSession)) {
|
|
//
|
|
// Wrap the RxData and put this Wrap into the instances RcvdDgramQue.
|
|
//
|
|
Wrap = Udp4WrapRxData (Instance, Packet, RxData);
|
|
if (Wrap == NULL) {
|
|
continue;
|
|
}
|
|
|
|
NET_GET_REF (Packet);
|
|
|
|
InsertTailList (&Instance->RcvdDgramQue, &Wrap->Link);
|
|
|
|
Enqueued++;
|
|
}
|
|
}
|
|
|
|
return Enqueued;
|
|
}
|
|
|
|
|
|
/**
|
|
This function delivers the received datagrams for the specified instance.
|
|
|
|
@param[in] Instance Pointer to the instance context data.
|
|
|
|
**/
|
|
VOID
|
|
Udp4InstanceDeliverDgram (
|
|
IN UDP4_INSTANCE_DATA *Instance
|
|
)
|
|
{
|
|
UDP4_RXDATA_WRAP *Wrap;
|
|
EFI_UDP4_COMPLETION_TOKEN *Token;
|
|
NET_BUF *Dup;
|
|
EFI_UDP4_RECEIVE_DATA *RxData;
|
|
EFI_TPL OldTpl;
|
|
|
|
if (!IsListEmpty (&Instance->RcvdDgramQue) &&
|
|
!NetMapIsEmpty (&Instance->RxTokens)) {
|
|
|
|
Wrap = NET_LIST_HEAD (&Instance->RcvdDgramQue, UDP4_RXDATA_WRAP, Link);
|
|
|
|
if (NET_BUF_SHARED (Wrap->Packet)) {
|
|
//
|
|
// Duplicate the Packet if it is shared between instances.
|
|
//
|
|
Dup = NetbufDuplicate (Wrap->Packet, NULL, 0);
|
|
if (Dup == NULL) {
|
|
return;
|
|
}
|
|
|
|
NetbufFree (Wrap->Packet);
|
|
|
|
Wrap->Packet = Dup;
|
|
}
|
|
|
|
NetListRemoveHead (&Instance->RcvdDgramQue);
|
|
|
|
Token = (EFI_UDP4_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL);
|
|
|
|
//
|
|
// Build the FragmentTable and set the FragmentCount in RxData.
|
|
//
|
|
RxData = &Wrap->RxData;
|
|
RxData->FragmentCount = Wrap->Packet->BlockOpNum;
|
|
|
|
NetbufBuildExt (
|
|
Wrap->Packet,
|
|
(NET_FRAGMENT *) RxData->FragmentTable,
|
|
&RxData->FragmentCount
|
|
);
|
|
|
|
Token->Status = EFI_SUCCESS;
|
|
Token->Packet.RxData = &Wrap->RxData;
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
|
|
InsertTailList (&Instance->DeliveredDgramQue, &Wrap->Link);
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
gBS->SignalEvent (Token->Event);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
This function delivers the datagrams enqueued in the instances.
|
|
|
|
@param[in] Udp4Service Pointer to the udp service context data.
|
|
|
|
**/
|
|
VOID
|
|
Udp4DeliverDgram (
|
|
IN UDP4_SERVICE_DATA *Udp4Service
|
|
)
|
|
{
|
|
LIST_ENTRY *Entry;
|
|
UDP4_INSTANCE_DATA *Instance;
|
|
|
|
NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {
|
|
//
|
|
// Iterate the instances.
|
|
//
|
|
Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);
|
|
|
|
if (!Instance->Configured) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Deliver the datagrams of this instance.
|
|
//
|
|
Udp4InstanceDeliverDgram (Instance);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
This function demultiplexes the received udp datagram to the appropriate instances.
|
|
|
|
@param[in] Udp4Service Pointer to the udp service context data.
|
|
@param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstracted from
|
|
the received datagram.
|
|
@param[in] Packet Pointer to the buffer containing the received udp
|
|
datagram.
|
|
|
|
**/
|
|
VOID
|
|
Udp4Demultiplex (
|
|
IN UDP4_SERVICE_DATA *Udp4Service,
|
|
IN EFI_NET_SESSION_DATA *NetSession,
|
|
IN NET_BUF *Packet
|
|
)
|
|
{
|
|
EFI_UDP_HEADER *Udp4Header;
|
|
UINT16 HeadSum;
|
|
EFI_UDP4_RECEIVE_DATA RxData;
|
|
EFI_UDP4_SESSION_DATA *Udp4Session;
|
|
UINTN Enqueued;
|
|
|
|
if (Packet->TotalSize < sizeof (EFI_UDP_HEADER)) {
|
|
NetbufFree (Packet);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get the datagram header from the packet buffer.
|
|
//
|
|
Udp4Header = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, NULL);
|
|
ASSERT (Udp4Header != NULL);
|
|
|
|
if (Udp4Header->Checksum != 0) {
|
|
//
|
|
// check the checksum.
|
|
//
|
|
HeadSum = NetPseudoHeadChecksum (
|
|
NetSession->Source.Addr[0],
|
|
NetSession->Dest.Addr[0],
|
|
EFI_IP_PROTO_UDP,
|
|
0
|
|
);
|
|
|
|
if (Udp4Checksum (Packet, HeadSum) != 0) {
|
|
//
|
|
// Wrong checksum.
|
|
//
|
|
NetbufFree (Packet);
|
|
return;
|
|
}
|
|
}
|
|
|
|
Udp4Session = &RxData.UdpSession;
|
|
Udp4Session->SourcePort = NTOHS (Udp4Header->SrcPort);
|
|
Udp4Session->DestinationPort = NTOHS (Udp4Header->DstPort);
|
|
|
|
CopyMem (&Udp4Session->SourceAddress, &NetSession->Source, sizeof (EFI_IPv4_ADDRESS));
|
|
CopyMem (&Udp4Session->DestinationAddress, &NetSession->Dest, sizeof (EFI_IPv4_ADDRESS));
|
|
|
|
//
|
|
// Trim the UDP header.
|
|
//
|
|
NetbufTrim (Packet, UDP4_HEADER_SIZE, TRUE);
|
|
|
|
RxData.DataLength = (UINT32) Packet->TotalSize;
|
|
|
|
//
|
|
// Try to enqueue this datagram into the instances.
|
|
//
|
|
Enqueued = Udp4EnqueueDgram (Udp4Service, Packet, &RxData);
|
|
|
|
if (Enqueued == 0) {
|
|
//
|
|
// Send the port unreachable ICMP packet before we free this NET_BUF
|
|
//
|
|
Udp4SendPortUnreach (Udp4Service->IpIo, NetSession, Udp4Header);
|
|
}
|
|
|
|
//
|
|
// Try to free the packet before deliver it.
|
|
//
|
|
NetbufFree (Packet);
|
|
|
|
if (Enqueued > 0) {
|
|
//
|
|
// Deliver the datagram.
|
|
//
|
|
Udp4DeliverDgram (Udp4Service);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
This function builds and sends out a icmp port unreachable message.
|
|
|
|
@param[in] IpIo Pointer to the IP_IO instance.
|
|
@param[in] NetSession Pointer to the EFI_NET_SESSION_DATA of the packet
|
|
causes this icmp error message.
|
|
@param[in] Udp4Header Pointer to the udp header of the datagram causes
|
|
this icmp error message.
|
|
|
|
**/
|
|
VOID
|
|
Udp4SendPortUnreach (
|
|
IN IP_IO *IpIo,
|
|
IN EFI_NET_SESSION_DATA *NetSession,
|
|
IN VOID *Udp4Header
|
|
)
|
|
{
|
|
NET_BUF *Packet;
|
|
UINT32 Len;
|
|
IP4_ICMP_ERROR_HEAD *IcmpErrHdr;
|
|
EFI_IP4_HEADER *IpHdr;
|
|
UINT8 *Ptr;
|
|
IP_IO_OVERRIDE Override;
|
|
IP_IO_IP_INFO *IpSender;
|
|
|
|
IpSender = IpIoFindSender (&IpIo, NetSession->IpVersion, &NetSession->Dest);
|
|
if (IpSender == NULL) {
|
|
//
|
|
// No appropriate sender, since we cannot send out the ICMP message through
|
|
// the default zero station address IP instance, abort.
|
|
//
|
|
return;
|
|
}
|
|
|
|
IpHdr = NetSession->IpHdr.Ip4Hdr;
|
|
|
|
//
|
|
// Calculate the required length of the icmp error message.
|
|
//
|
|
Len = sizeof (IP4_ICMP_ERROR_HEAD) + (EFI_IP4_HEADER_LEN (IpHdr) -
|
|
sizeof (IP4_HEAD)) + ICMP_ERROR_PACKET_LENGTH;
|
|
|
|
//
|
|
// Allocate buffer for the icmp error message.
|
|
//
|
|
Packet = NetbufAlloc (Len);
|
|
if (Packet == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Allocate space for the IP4_ICMP_ERROR_HEAD.
|
|
//
|
|
IcmpErrHdr = (IP4_ICMP_ERROR_HEAD *) NetbufAllocSpace (Packet, Len, FALSE);
|
|
ASSERT (IcmpErrHdr != NULL);
|
|
|
|
//
|
|
// Set the required fields for the icmp port unreachable message.
|
|
//
|
|
IcmpErrHdr->Head.Type = ICMP_TYPE_UNREACH;
|
|
IcmpErrHdr->Head.Code = ICMP_CODE_UNREACH_PORT;
|
|
IcmpErrHdr->Head.Checksum = 0;
|
|
IcmpErrHdr->Fourth = 0;
|
|
|
|
//
|
|
// Copy the IP header of the datagram tragged the error.
|
|
//
|
|
CopyMem (&IcmpErrHdr->IpHead, IpHdr, EFI_IP4_HEADER_LEN (IpHdr));
|
|
|
|
//
|
|
// Copy the UDP header.
|
|
//
|
|
Ptr = (UINT8 *) &IcmpErrHdr->IpHead + EFI_IP4_HEADER_LEN (IpHdr);
|
|
CopyMem (Ptr, Udp4Header, ICMP_ERROR_PACKET_LENGTH);
|
|
|
|
//
|
|
// Calculate the checksum.
|
|
//
|
|
IcmpErrHdr->Head.Checksum = (UINT16) ~(NetbufChecksum (Packet));
|
|
|
|
//
|
|
// Fill the override data.
|
|
//
|
|
Override.Ip4OverrideData.DoNotFragment = FALSE;
|
|
Override.Ip4OverrideData.TypeOfService = 0;
|
|
Override.Ip4OverrideData.TimeToLive = 255;
|
|
Override.Ip4OverrideData.Protocol = EFI_IP_PROTO_ICMP;
|
|
|
|
CopyMem (&Override.Ip4OverrideData.SourceAddress, &NetSession->Dest, sizeof (EFI_IPv4_ADDRESS));
|
|
ZeroMem (&Override.Ip4OverrideData.GatewayAddress, sizeof (EFI_IPv4_ADDRESS));
|
|
|
|
//
|
|
// Send out this icmp packet.
|
|
//
|
|
IpIoSend (IpIo, Packet, IpSender, NULL, NULL, &NetSession->Source, &Override);
|
|
|
|
NetbufFree (Packet);
|
|
}
|
|
|
|
|
|
/**
|
|
This function handles the received Icmp Error message and demultiplexes it to the
|
|
instance.
|
|
|
|
@param[in] Udp4Service Pointer to the udp service context data.
|
|
@param[in] IcmpError The icmp error code.
|
|
@param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstracted
|
|
from the received Icmp Error packet.
|
|
@param[in] Packet Pointer to the Icmp Error packet.
|
|
|
|
**/
|
|
VOID
|
|
Udp4IcmpHandler (
|
|
IN UDP4_SERVICE_DATA *Udp4Service,
|
|
IN UINT8 IcmpError,
|
|
IN EFI_NET_SESSION_DATA *NetSession,
|
|
IN NET_BUF *Packet
|
|
)
|
|
{
|
|
EFI_UDP_HEADER *Udp4Header;
|
|
EFI_UDP4_SESSION_DATA Udp4Session;
|
|
LIST_ENTRY *Entry;
|
|
UDP4_INSTANCE_DATA *Instance;
|
|
|
|
if (Packet->TotalSize < sizeof (EFI_UDP_HEADER)) {
|
|
NetbufFree (Packet);
|
|
return;
|
|
}
|
|
|
|
Udp4Header = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, NULL);
|
|
ASSERT (Udp4Header != NULL);
|
|
|
|
CopyMem (&Udp4Session.SourceAddress, &NetSession->Source, sizeof (EFI_IPv4_ADDRESS));
|
|
CopyMem (&Udp4Session.DestinationAddress, &NetSession->Dest, sizeof (EFI_IPv4_ADDRESS));
|
|
|
|
Udp4Session.SourcePort = NTOHS (Udp4Header->DstPort);
|
|
Udp4Session.DestinationPort = NTOHS (Udp4Header->SrcPort);
|
|
|
|
NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {
|
|
//
|
|
// Iterate all the instances.
|
|
//
|
|
Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);
|
|
|
|
if (!Instance->Configured) {
|
|
continue;
|
|
}
|
|
|
|
if (Udp4MatchDgram (Instance, &Udp4Session)) {
|
|
//
|
|
// Translate the Icmp Error code according to the udp spec.
|
|
//
|
|
Instance->IcmpError = IpIoGetIcmpErrStatus (IcmpError, IP_VERSION_4, NULL, NULL);
|
|
|
|
if (IcmpError > ICMP_ERR_UNREACH_PORT) {
|
|
Instance->IcmpError = EFI_ICMP_ERROR;
|
|
}
|
|
|
|
//
|
|
// Notify the instance with the received Icmp Error.
|
|
//
|
|
Udp4ReportIcmpError (Instance);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
NetbufFree (Packet);
|
|
}
|
|
|
|
|
|
/**
|
|
This function reports the received ICMP error.
|
|
|
|
@param[in] Instance Pointer to the udp instance context data.
|
|
|
|
**/
|
|
VOID
|
|
Udp4ReportIcmpError (
|
|
IN UDP4_INSTANCE_DATA *Instance
|
|
)
|
|
{
|
|
EFI_UDP4_COMPLETION_TOKEN *Token;
|
|
|
|
if (NetMapIsEmpty (&Instance->RxTokens)) {
|
|
//
|
|
// There are no receive tokens to deliver the ICMP error.
|
|
//
|
|
return;
|
|
}
|
|
|
|
if (EFI_ERROR (Instance->IcmpError)) {
|
|
//
|
|
// Try to get a RxToken from the RxTokens map.
|
|
//
|
|
Token = (EFI_UDP4_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL);
|
|
|
|
if (Token != NULL) {
|
|
//
|
|
// Report the error through the Token.
|
|
//
|
|
Token->Status = Instance->IcmpError;
|
|
gBS->SignalEvent (Token->Event);
|
|
|
|
//
|
|
// Clear the IcmpError.
|
|
//
|
|
Instance->IcmpError = EFI_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
This function is a dummy ext-free function for the NET_BUF created for the output
|
|
udp datagram.
|
|
|
|
@param[in] Context Pointer to the context data.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
Udp4NetVectorExtFree (
|
|
VOID *Context
|
|
)
|
|
{
|
|
}
|
|
|