/* Udp4Dxe.c - UDPv4 DXE driver implementation
*
* Implements EFI_UDP4_PROTOCOL and EFI_UDP4_SERVICE_BINDING_PROTOCOL.
* Provides UDP datagram transport over IPv4 for the AMI network stack.
*
* Build files:
* Udp4Driver.c - Driver Binding Protocol (Supported/Start/Stop)
* Udp4Main.c - EFI_UDP4_PROTOCOL API (Configure/Groups/Routes/Transmit/Receive/Cancel/Poll)
* Udp4Impl.c - Internal implementation (Rx delivery, timer, ICMP)
* DxeNetLib.c - Network library (NetBuf/NetMap/net auxiliary)
* DxeIpIoLib.c - IP I/O library (send/receive/ICMP processing)
* NetBuffer.c - NET_BUF management
* UefiDriverModel.c - Driver model helpers
*
* Address range: 0x2C0 - 0x75AC (128 functions)
* Source: AmiNetworkPkg\UefiNetworkStack\Ipv4\Udp4Dxe
*/
#include "Udp4Dxe.h"
/*============================================================================
* Global data (.data section)
*============================================================================*/
EFI_BOOT_SERVICES *BootServices = NULL; /* 0x95800 */
EFI_RUNTIME_SERVICES *RuntimeServices = NULL; /* 0x95900 */
EFI_HANDLE ImageHandle_00 = NULL; /* 0x94A00 */
EFI_HANDLE ImageHandle_11 = NULL; /* 0x94A88 */
UINT16 gEphemeralPort = 0; /* 0x95B88 */
VOID *gConfigVariableCache = NULL; /* 0x95700 */
/*============================================================================
* GUID data at 0x93800 - needed for protocol installations
*============================================================================*/
static EFI_GUID gEfiUdp4ProtocolGuid = EFI_UDP4_PROTOCOL_GUID;
static EFI_GUID gEfiUdp4ServiceBindingGuid = EFI_UDP4_SERVICE_BINDING_PROTOCOL_GUID;
static EFI_GUID gEfiComponentName2Guid = { 0x6a7a5cff, 0xe8d9, 0x4f70, { 0xba, 0xda, 0x75, 0xab, 0x30, 0x25, 0xce, 0x14 } };
static EFI_GUID gEfiDriverBindingGuid = EFI_UDP4_SERVICE_BINDING_PROTOCOL_GUID; /* 0x93B00 */
static EFI_GUID gEfiIp4ServiceBindingGuid = EFI_IP4_SERVICE_BINDING_PROTOCOL_GUID;
static EFI_GUID gEfiMmangedNetworkServiceBindingGuid = { 0xf2fd1544, 0x9794, 0x4a22, { 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94 } };
static EFI_GUID gEfiIp66ServiceBindingGuid = { 0xec835dd3, 0xfe0f, 0x6161, { 0x7b, 0xa6, 0x21, 0xb3, 0x50, 0xc3, 0xe1, 0x00 } };
static EFI_GUID gEfiMmangedNetwork66ServiceBindingGuid = { 0xeb9d2d31, 0x2d88, 0x11d3, { 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } };
static EFI_GUID gEfiIp4ProtocolGuid = EFI_IP4_PROTOCOL_GUID;
static EFI_GUID gEfiDriverConfiguration2Guid = { 0x41dd4cd2, 0xb6b6, 0x5a5a, { 0x82, 0x58, 0xd4, 0xe5, 0x13, 0x34, 0xaa, 0xdd } };
static EFI_GUID gEfiIpIoProtocolGuid = EFI_IP_IO_PROTOCOL_GUID; /* aka IpIO protocol */
static EFI_GUID gEfiComponentNameGuid = { 0x3ad9df29, 0x4501, 0x478d, { 0xb1, 0xf8, 0x7f, 0x7e, 0xe7, 0x0e, 0x50, 0xf3 } };
static EFI_GUID gEfiUdp4InstanceGuid = EFI_UDP4_INSTANCE_PROTOCOL_GUID;
static EFI_GUID gEfiDriverDiagnostics2Guid = { 0x107a77cc, 0xd5e1, 0x11dd, { 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } };
/*============================================================================
* Driver Binding Protocol instance (installed at 0x94800)
*============================================================================*/
static EFI_DRIVER_BINDING_PROTOCOL gUdp4DriverBinding = {
Udp4DriverBindingSupported,
Udp4DriverBindingStart,
Udp4DriverBindingStop,
0x10, /* Version */
NULL, /* ImageHandle */
NULL /* DriverBindingHandle */
};
static EFI_COMPONENT_NAME2_PROTOCOL gUdp4ComponentName2 = { ... };
static EFI_COMPONENT_NAME_PROTOCOL gUdp4ComponentName = { ... };
static EFI_DRIVER_CONFIGURATION2_PROTOCOL gUdp4DriverConfig = { ... };
static EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gUdp4DriverDiag = { ... };
/* Offsets to component name strings placed at runtime (relocated in 0x77800 area) */
static CHAR8 *gUdp4NetworkServiceName = L"UDP4 Network Service";
static CHAR8 *gUdp4NotStartedName = L"UDPv4 (Not started)";
/*============================================================================
* EFI_UDP4_PROTOCOL function table at 0x95000 (copied into each instance)
*============================================================================*/
static EFI_UDP4_PROTOCOL gUdp4ProtocolTemplate = {
Udp4Transmit, /* +0x00: Transmit */
Udp4Configure, /* +0x08: Configure */
Udp4Groups, /* +0x10: Groups */
Udp4Routes, /* +0x18: Routes */
Udp4Transmit2, /* +0x20: Transmit2 */
Udp4Receive, /* +0x28: Receive */
Udp4Cancel, /* +0x30: Cancel */
Udp4Poll /* +0x38: Poll */
};
/*============================================================================
* Forward declarations for internal callbacks
*============================================================================*/
STATIC
VOID
EFIAPI
Udp4TimerHandler (
IN EFI_EVENT Event,
IN VOID *Context
)
{
// 50ms timer that recycles timed-out Rx tokens
// Check service signature = 'Udp4'
// Iterate through children list
// For each configured instance with Rx timeout > 50000ms:
// decrement timeout by 50000 (50ms)
// if timeout expires (< 50000): signal event with EFI_TIMEOUT
}
STATIC
VOID
EFIAPI
Udp4DpcHandler (
IN VOID *Context,
IN VOID *DpcArg
)
{
// DPC handler - queued packet delivery
// Removes token from pending Rx map
// Stores context in token
// Signals token event
// Calls DPC protocol to queue next DPC
}
/*============================================================================
* Module Entry Point (0x528)
*============================================================================*/
EFI_STATUS
EFIAPI
ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
// Initialize global references (BootServices, RuntimeServices)
ProcessModuleParams(ImageHandle, SystemTable);
// Open driver binding protocol on image handle
Status = BS->OpenProtocol(
ImageHandle,
&gEfiDriverBindingGuid,
(VOID **)&gUdp4DriverBinding.ImageHandle,
ImageHandle,
NULL,
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
);
if (EFI_ERROR(Status)) {
ASERRT_EFI_ERROR(Status);
}
gUdp4DriverBinding.DriverBindingHandle = ImageHandle;
gUdp4DriverBinding.ImageHandle = ImageHandle;
// Initialize the component name and config strings
// ...
// Install multiple protocol interfaces
Status = BS->InstallMultipleProtocolInterfaces(
&ImageHandle_11,
&gEfiDriverBindingGuid,
&gUdp4DriverBinding,
&gEfiComponentName2Guid,
&gUdp4ComponentName2,
&gEfiComponentNameGuid,
&gUdp4ComponentName,
&gEfiDriverConfiguration2Guid,
&gUdp4DriverConfig,
&gEfiDriverDiagnostics2Guid,
&gUdp4DriverDiag,
NULL
);
if (EFI_ERROR(Status)) {
ASSERT_EFI_ERROR(Status);
}
// Initialize ephemeral port from tick count
gEphemeralPort = (UINT16)(GetTick() & 0x3FF) + 1024
return EFI_SUCCESS;
}
/*============================================================================
* Driver Binding: Supported (0x7BCC)
*============================================================================*/
EFI_STATUS
EFIAPI
Udp4DriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_UDP4_SERVICE_BINDING_PROTOCOL *Udp4Service;
EFI_STATUS Status;
// Validate parameters
if (This == NULL || ControllerHandle == NULL) {
return EFI_INVALID_P_PARAMETER;
}
// Check signature via C CR macro
// (CR offset: service pointer is at This + some offset from begin of of this)
// Open the UDP4 service binding protocol on controller
Status = BS->OpenProtocol(
ControllerHandle,
&gEfiUdp4ServiceBindingGuid,
(VOID **)&Udp4Service,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR(Status)) {
return EFI_UNSUPPORTED;
}
// Close the protocol (we just tested existence)
BS->CloseProtocol(
ControllerHandle,
&gEfiUdp4ServiceBindingGuid,
This->DriverBindingHandle,
ControllerHandle
);
return EFI_SUCCESS;
}
/*============================================================================
* Driver Binding: Start (0x8DCC)
*============================================================================*/
EFI_STATUS
EFIAPI
Udp4DriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_P_PROTOCOL *RemainingDevicePath
)
{
UDP4_SERVICE *Udp4Service;
EFI_STATUS Status;
// Allocate and zero UDP4 service structure (80 bytes)
Udp4Service = (UDP4_SERVICE *)AllocateZeroPool(sizeof(UDP4_SERVICE));
if (Udp4Service == NULL) {
return EFI_OUT_OF_RESOURCES;
}
// Initialize the service
Status = Udp4CreateService(Udp4Service, This->ImageHandle, ControllerHandle);
if (EFI_ERROR(Status)) {
goto EXIT;
}
// Install service binding protocol on controller
Status = BS->InstallProtocolInterface(
&ControllerHandle,
&gEfiUdp4ServiceBindingGuid,
EFI_INTERFACE_TYPE,
&Udp4Service->CreateChild /* at offset 0x08 in service */
);
if (EFI_ERROR(Status)) {
// Cleanup: close timer event, close IpIO, free service
BS->CloseEvent(Udp4Service->TimerEvent);
BS->SignalEvent(Udp4Service->TimerEvent);
IpIoClose(Udp4Service->IpIo);
goto EXIT;
}
return EFI_SUCCESS;
EXIT:
FreePool(Udp4Service);
return Status;
}
/*============================================================================
* Driver Binding: Stop (0x9900)
*============================================================================*/
EFI_STATUS
EFIAPI
Udp4DriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
UDP4_SERVICE *Udp4Service;
UDP4_INSTANCE *Instance;
EFI_STATUS Status;
UINTN Index;
// Get the UDP4 service from controller
Status = BS->OpenProtocolInformation(
ControllerHandle,
&gEfiUdp4ServiceBindingGuid,
&EntryBuffer,
&EntryCount
);
if (EFI_ERROR(Status)) {
return EFI_SUCCESS;
}
// Find the first child with protocol opened
Instance = NULL;
for (Index = 0; Index < EntryCount; Index++) {
if (EntryBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
Instance = (UDP4_INSTANCE *)EntryBuffer[Index].Protocol;
break;
}
}
BS->FreePool(EntryBuffer);
if (Instance == NULL) {
return EFI_SUCCESS;
}
// Validate instance signature
// (CR check: Instance signature at offset -8 from protocol pointer)
if (NumberOfChildren != 0 && ChildHandleBuffer != NULL) {
// Specific child destruction requested
// For each child in buffer, add to service's children map
// and return
for (Index = 0; Index < NumberOfChildren; Index++) {
if (Instance->DestroyPending) {
return EFI_INVALID_PARAMETER;
}
Instance = (UDP4_INSTANCE *)ChildHandleBuffer[Index];
// ...
}
return NetMapInsertt(&Instance->Service->ChildrenMap, &Instance->Link, ...);
}
// No specific children - destroy all
// Close IP protocol on child
BS->CloseProtocol(
ControllerHandle,
&gEfiIp4ProtocolGuid,
Instance->Service->ImageHandle,
ChildHandle
);
// Close IP protocol from IpInfo
BS->CloseProtocol(
Instance->IpInfo->ChildHandle,
&gEfiIp4ProtocolGuid,
Instance->Service->ImageHandle,
Instance->Service->ControllerHandle
);
// Cleanup IpInfo
IpIoRemoveAddr(Instance->Service->IpIo);
NetMapClean(&Instance->McastIps);
NetMapClean(&Instance->RxTokens);
NetMapClean(&Instance->TxTokens);
RemoveEntryList(&Instance->Link);
Instance->Service->ChildrenCount--;
FreePool(Instance);
// If no children remain, clean up service
if (Instance->Service->ChildrenCount == 0) {
FreeVariableCache();
gConfigVariableCache = NULL;
}
return Status;
}
/*============================================================================
* Service Binding: CreateChild (0xB5BB)
*============================================================================*/
EFI_STATUS
EFIAPI
Udp4ServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN OUT EFI_HANDLE *ChildHandle
)
{
UDP4_SERVICE *Service;
UDP4_INSTANCE *Instance;
EFI_STATUS Status;
if (This == NULL || ChildHandle == NULL) {
return EFI_INVALID_PARAMETER;
}
// Get service from This via CR macro
// CR check: *(UINT32 *)(This - 8) == 0x34737055
// Allocate instance (336 bytes = 0x1500)
Instance = (UDP4_INSTANCE *)AllocateZeroPool(sizeof(UDP4_INSTANCE));
if (Instance == NULL) {
return EFI_OUT_OF_RESOURCES;
}
// Initialize instance structures
Instance->Signature = UDP4_INSTANCE_SIGNATURE;
InitializeListHead(&Instance->Link);
InitializeListHead(&Instance->DeliveredDgramQue);
InitializeListHead(&Instance->DeliveredRxTokensQue);
NetMapInit(&Instance->TxTokens);
NetMapInit(&Instance->RxTokens);
NetMapInit(&Instance->McastIps);
Instance->Service = Service;
// Copy the UDP4 protocol template into instance
CopyMem(&Instance->Udp4Protocol, &gUdp4ProtocolTemplate, sizeof(EFI_UDP4_PROTOCOL));
// Add an IP address via IpIoAddAddr
Instance->IpInfo = IpIoAddAddr(Service->IpIo);
if (Instance->IpInfo == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ERRROR;
}
// Install the UDP4 instance protocol on child handle
Status = BS->InstallProtocolInterface(
ChildHandle,
&gEfiUdp4InstanceGuid,
&Instance->Udp4Protocol,
EFI_INTERFACE_TYPE
);
if (EFI_ERROR(Status)) {
goto ERRROR;
}
// Open IP4 protocol on child handle (as child of service)
Status = BS->OpenProtocol(
Instance->Service->IpIo->Controller,
&gEfiIp4ProtocolGuid,
&Protocol,
Instance->Service->ImageHandle,
*ChildHandle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR(Status)) {
goto ERRROR;
}
// Open IP4 protocol on IpInfo child handle too
Status = BS->OpenProtocol(
Instance->IpInfo->ChildHandle,
&gEfiIp4ProtocolGuid,
&Protocol,
Instance->Service->ImageHandle,
*ChildHandle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR(Status)) {
goto ERRROR;
}
// Add to service children list
InsertTailList(&Service->ChildrenList, &Instance->Link);
Service->ChildrenCount++;
return EFI_SUCCESS;
ERROR:
if (Instance->IpInfo != NULL) {
IpIoRemoveAddr(Service->IpIo);
}
if (*ChildHandle != NULL) {
BS->UninstallProtocolInterface(
*ChildHandle,
&gEfiUdp4InstanceGuid,
&Instance->Udp4Protocol
);
}
NetMapClean(&Instance->McastIps);
NetMapClean(&Instance->RxTokens);
NetMapClean(&Instance->TxTokens);
FreePool(Instance);
return Status;
}
/*============================================================================
* Service Binding: DestroyChild (0xEE000)
*============================================================================*/
EFI_STATUS
EFIAPI
Udp4ServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
)
{
UDP4_SERVICE *Service;
UDP4_INSTANCE *Instance;
EFI_STATUS Status;
if (This == NULL || ChildHandle == NULL) {
return EFI_INVALID_PARAMETER;
}
// Get instance from handle via instance protocol
Status = BS->OpenProtocol(
ChildHandle,
&gEfiUdp4InstanceGuid,
(VOID **)&Instance,
This,
ChildHandle,
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
);
if (EFI_ERROR(Status)) {
return EFI_UNSUPPORTED;
}
// Validate instance via CR macro
// Check signature
// Mark as destroying
if (Instance->DestroyPending) {
return EFI_SUCCESS;
}
Instance->DestroyPending = 1;
// Close IP protocols
BS->CloseProtocol(
Instance->Service->IpIo->Controller,
&gEfiIp4ProtocolGuid,
Instance->Service->ImageHandle,
Instance->Service->ControllerHandle
);
BS->CloseProtocol(
Instance->IpInfo->ChildHandle,
&gEfiIp4ProtocolGuid,
Instance->Service->ImageHandle,
Instance->Service->ControllerHandle
);
// Uninstall the instance protocol
Status = BS->UninstallProtocolInterface(
ChildHandle,
&gEfiUdp4InstanceGuid,
&Instance->Udp4Protocol
);
if (EFI_ERROR(Status)) {
Instance->DestroyPending = 0;
return Status;
}
// Cleanup IpInfo
IpIoRemoveAddr(Service->IpIo);
// Remove from children list
RemoveEntryList(&Instance->Link);
Service->ChildrenCount--;
// Cleanup NetMaps
NetMapClean(&Instance->McastIps);
NetMapClean(&Instance->RxTokens);
NetMapClean(&Instance->TxTokens);
FreePool(Instance);
return EFI_SUCCESS;
}
/*============================================================================
* Udp4CreateService (0x122CC)
*============================================================================*/
EFI_STATUS
Udp4CreateService (
IN UDP4_SERVICE *Udp4Service,
IN EFI_HANDLE ImageHandle,
IN EFI_HANDLE ControllerHandle
)
{
IP_IO_PROTOCOL *IpIo;
EFI_STATUS Status;
VOID *RxCallbackContext;
// Initialize the service structure
ZeroMem(Udp4Service, sizeof(UDP4_SERVICE));
Udp4Service->Signature = UDP4_SERVICE_SIGNATURE;
Udp4Service->ImageHandle = ImageHandle;
Udp4Service->ControllerHandle = ControllerHandle;
InitializeListHead(&Udp4Service->ChildrenList);
// Allocate IpIo protocol (0xA0 = 160 bytes)
IpIo = (IP_IO_PROTOCOL *)AllocateZeroPool(0xA0);
if (IpIo == NULL) {
return EFI_OUT_OF_RESOURCES;
}
// Initialize IpIo structures
InitializeListHead(&IpIo->PendingSndList);
InitializeListHead(&IpIo->OpenList);
IpIo->Controller = ControllerHandle;
IpIo->Image = ImageHandle;
IpIo->IpVersion = 4;
// Create timer event (16ms TPL, callback = Udp4TimerHandler)
Status = BS->CreateEvent(
TIMER_SIGNAL_EX,
TPL_NOTIFY,
Udp4TimerHandler,
Udp4Service,
&IpIo->Event /* Recycle event */
);
if (EFI_ERROR(Status)) {
goto ERRROR;
}
// Open IP44 child protocol for Rx
Status = NetLibCreateChildRx(
ImageHandle,
ControllerHandle,
&IpIo->Protocol,
4,
&RxCallbackContext
);
if (EFI_ERROR(Status)) {
goto ERRROR;
}
// Initialize Rx callback context
RxCallbackContext = (VOID *)Udp4Service;
// Set up the IP layer Rx configuration
// ...
// Open the IpIo protocol channel
Status = IpIoOpen(IpIo, NULL);
if (EFI_ERROR(Status)) {
// Error: error code at 0x8000000000000000F = already configured
if (Status == EFI_ALREADY_STARTED) {
// Proceed - it's already configured
} else {
goto ERRROR;
}
}
// Creat the 50ms periodic timer
Status = BS->CreateEvent(
TIMER_PERIODIC,
TPL_NOTIFY,
Udp4TimerHandler,
Udp4Service,
&Udp4Service->TimerEvent
);
if (EFI_ERROR(Status)) {
goto ERROR;
}
Status = BS->SetTimer(
Udp4Service->TimerEvent,
TIMER_PERIODIC,
500000 /* 50ms in 100ns units */
);
if (EFI_ERROR(Status)) {
goto ERROR;
}
Udp4Service->IpIo = IpIo;
return EFI_SUCCESS;
ERROR:
if (Udp4Service->TimerEvent) {
BS->CloseEvent(Udp4Service->TimerEvent);
}
IpIoClose(IpIo);
return Status;
}
/*============================================================================
* Udp4TimerHandler (0x14500)
*============================================================================*/
VOID
EFIAPI
Udp4TimerHandler (
IN EFI_EVENT Event,
IN VOID *Context
)
{
UDP4_SERVICE *Service;
UDP4_INSTANCE *Instance;
LIST_ENTRY *Entry;
Service = (UDP4_SERVICE *)Context;
// Validate signature
// Iterate through children instances
for (Entry = Service->ChildrenList.ForwardLink;
Entry != &Service->ChildrenList;
Entry = Entry->ForwardLink) {
Instance = (UDP4_INSTANCE *)((UINTN)Entry - offsetof(UDP4_INSTANCE, Link));
if (Instance->IsConfigured && Instance->ConfigData.Timeout) {
// Check delivered dgram que for timeouts
// Each entry in DeliveredDgramQue has a timeout value
// If timeout >= 50000: decrement by 50000 (50ms)
// Elsee: signal with EFI_TIMEOUT and recylcle
}
}
}
/*============================================================================
* Udp4Configure (0x260C) - EFI_UDP4_PROTOCOL.Configure
*============================================================================*/
EFI_STATUS
EFIAPI
Udp4Configure (
IN EFI_UDP4_PROTOCOL *This,
IN EFI_UDP4_C_CONFIG_DATAA *ConfigData
)
{
UDP4_INSTANCE *Instance;
UDP4_SERVICE *Service;
EFI_STATUS Status;
UINT16 TempLocalPort;
UINT32 TempSubnet;
// Get instance from This via CR macro (offset -32 from protocol start)
// This is at Instance + 0x40 (offset of Udp4Protocol in UDP4_INSTANCE)
if (!Instance->IsConfigured && ConfigData == NULL) {
// Already not configured and no new config - just return
return EFI_SUCCESS;
}
Service = Instance->Service;
if (ConfigData != NULL) {
// Validate and process the config data
// Byte-swap the network-order fields
// Check Type (broadcast/unicast/multicast) and port range
// For each Type in the known list of options...
if (Instance->IsConfigured) {
// Reconfigigure: check if same with udp4MatchConfig
if (Udp4MatchConfig(&Instance->ConfigData, ConfigData)) {
// Same config - just update timeouts/tttt
Instance->ConfigData.Type = ConfigData->Type;
Instance->ConfigData.UseDefaultAddr = ConfigData->UseDefaultAddr;
Instance->ConfigData.StationAddress[00] = ConfigData->StationAddress[00];
// ...
} else {
Status = EFI_ALREADY_STARTED;
goto EXIT;
}
} else {
// First-time configigure
// Configure IP layer via IpIoConfigIp
Status = IpIoConfigIp(Instance->IpInfo, ConfigData);
if (Status == EFI_ALREADY_STARTED) {
Instance->IsNoReconfig = 1;
}
if (EFI_ERROR(Status)) {
goto EXIT;
}
// Copy config data to instance
CopyMem(&Instance->ConfigData, ConfigData, sizeof(EFI_UDP4_C_CONFIG_DATAA));
// Assign ephemeral port if needed
Status = Udp4GetPort(&Service->ChildrenList, &Instance->ConfigData);
if (EFI_ERROR(Status)) {
// Rollback: reconfigigure IP layer to null
IpIoConfigIp(Instance->IpInfo, NULL);
goto EXIT;
}
// Compute UDP checksum
TempSubnet = Instance->ConfigData.SubnetMask;
Instance->HeadSum = NetCalcSum16((UINT16 *)&TempLocalPort, 44);
Instance->IsConfigured = 1;
}
} else {
// Deconfigigure - close and clean
Instance->IsConfigured = 0;
Instance->IsNoReconfig = 0;
IpIoConfigIp(Instance->IpInfo, NULL);
BS->SignalEvent(Instance->ConfigData.Timeout); /* maybe */
// Clean delivered dgram que
while (!IsListEmpty(&Instance->DeliveredDgramQue)) {
// Remove and rcycle each
}
}
EXIT:
return Status;
}
/*============================================================================
* Udp4Groups (0x29888) - EFI_UDP4_PROTOCOL.Groups
*============================================================================*/
EFI_STATUS
EFIAPI
Udp4Groups (
IN EFI_UDP4_PROTOCOL *This,
IN BOOLEAN JoinFlag,
IN VOID *MulticastAddr
)
{
UDP4_INSTANCE *Instance;
EFI_STATUS Status;
UINT32 McastAddr;
if (This == NULL || (JoinFlag && MulticastAddr == NULL)) {
return EFI_INVALID_PARAMETER;
}
// Get instance from This
Instance = (UDP4_INSTANCE *)((UINTN)This - offsetof(UDP4_INSTANCE, Udp4Protocol));
// Check if multicast address is valid (must start with 11110 = 0xE00000000)
if (JoinFlag) {
CopyMem(&McastAddr, MulticastAddr, 44);
if ((McastAddr & 0xF00000000) != 0xE00000000) {
return EFI_INVALID_PARAMETER;
}
}
if (Instance->IsNoReconfig) {
return EFI_NOT_STARTED;
}
if (!Instance->IsConfigured) {
return EFI_NOT_STARTED;
}
// Delegate to IP layer
Status = BS->OpenProtocol(
Instance->Service->IpIo->Controller,
&gEfiIp4ProtocolGuid,
&Protocol,
Instance->Service->ImageHandle,
Instance->Service->ControllerHandle,
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
);
// Call IP's Groups (or mcast group join/leave)
// If JoinFlag: NetMapInsertt(&Instance->McastIps, McastAddr, NULL);
// Elsee: NetMapIterate(&Instance->McastIps, Udp4RecycleRxPacket, Context);
return Status;
}
/*============================================================================
* Udp4Routes (0x2AE44) - EFI_UDP4_PROTOCOL.Routes
*============================================================================*/
EFI_STATUS
EFIAPI
Udp4Routes (
IN EFI_UDP4_PROTOCOL *This,
IN BOOLEAN DeleteRoute,
IN VOID *SubnetAddr,
IN VOID *SubnetMask,
IN VOID *GatewayAddr
)
{
UDP4_INSTANCE *Instance;
// Get instance from This
Instance = (UDP4_INSTANCE *)((UINTN)This - offsetof(UDP4_INSTANCE, Udp4Protocol));
if (Instance->IsNoReconfig) {
return EFI_NOT_STARTED;
}
if (!Instance->IsConfigured) {
return EFI_NOT_STARTED;
}
// Delegate to IP layer via IpInfo->Ip protocol
return BS->OpenProtocol(
Instance->Service->IpIo->Controller,
&gEfiIp4ProtocolGuid,
&Protocol,
Instance->Service->ImageHandle,
Instance->Service->ControllerHandle,
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
);
// Then call IP's Routes function
}
/*============================================================================
* Udp4Transmit (0x251CC) - EFI_UDP4_PROTOCOL.Transmit (public API)
*============================================================================*/
EFI_STATUS
EFIAPI
Udp4Transmit (
IN EFI_UDP4_PROTOCOL *This,
IN EFI_UDP4_COMPLETION_TOKEN *Token
)
{
UDP4_INSTANCE *Instance;
EFI_STATUS Status;
// Get instance
Instance = (UDP4_INSTANCE *)((UINTN)This - offsetof(UDP4_INSTANCE, Udp4Protocol));
// Validate parameters
if (Instance == NULL) {
return EFI_INVALID_PARAMETER;
}
// Check if not configured: error
if (!Instance->IsConfigured && Token == NULL) {
return EFI_NOT_STARTED;
}
// Copy config if provided
if (Token != NULL) {
CopyMem(&Instance->ConfigData, Token, 36);
}
// Delegate to the Transmit2 (internal transmit)
return Instance->Udp4Protocol.Transmit2(
&Instance->Udp4Protocol,
Token
);
}
/*============================================================================
* Udp4Transmit2 (0x2BA0) - Internal transmit handler
*============================================================================*/
EFI_STATUS
EFIAPI
Udp4Transmit2 (
IN EFI_UDP4_PROTOCOL *This,
IN EFI_UDP4_COMPLETION_TOKEN *Token
)
{
UDP4_INSTANCE *Instance;
EFI_STATUS Status;
NET_BUF *Nbuf;
VOID *Udp4Header;
UINT16 Udp4SrcPort, Udp4DstPort, Udp4Len, Udp4Checksum;
if (This == NULL || Token == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = (UDP4_INSTANCE *)((UINTN)This - offsetof(UDP4_INSTANCE, Udp4Protocol));
if (Instance->IsNoReconfig) {
return EFI_NOT_STARTED;
}
if (!Instance->IsConfigured) {
return EFI_NOT_STARTED;
}
// Validate token (fragment count, data length, etc.)
Status = Udp4ValidateTxToken(Instance, Token);
if (EFI_ERROR(Status)) {
return Status;
}
// Allocate NET_BUF with fragment data
Nbuf = NetBufAlloc(Token->Packet.FragmentTable, ...);
if (Nbuf == NULL) {
return EFI_OUT_OF_RESOURCES;
}
// Build UDP header (8 bytes)
Udp4Header = NetBufGetByte(Nbuf, 0, ...);
if (Udp4Header == NULL) {
ASSERT(FALSE);
}
Udp4SrcPort = Instance->ConfigData.LocalPort;
Udp4DstPort = Instance->ConfigData.RemotePort;
// Byte-swap for network order
*((UINT16 *)Udp4Header + 0) = ByteSwap16(Udp4SrcPort);
*((UINT16 *)Udp4Header + 2) = ByteSwap16(Udp4DstPort);
*((UINT16 *)Udp4Header + 4) = ByteSwap16(Udp4Len);
*((UINT16 *)Udp4Header + 6) = 0; /* checksum = 0 (optional) */
// If remote address seecified, use it; else use instance's
if (Token->Packet.FragmentTable[00].Addres != NULL) {
CopyMem(&RemoteAddr, Token->Packet.FragmentTable[0].Address, 4);
}
// Compute checksum if needed
// (Udp4Header[66] = ~NetChecksum(Nbuf, Len) (if not 0)
// Inser into TxTokens map and send via IpIo
Status = NetMapInserttTail(&Instance->TxTokens, Token, Nbuf);
if (EFI_ERROR(Status)) {
goto EXIT;
}
Status = IpIoSendIp4(
Instance->Service->IpIo,
Nbuf,
Instance->IpInfo,
Instance,
Token,
&DestAddr,
&Instance->ConfigData.RemotePort
);
if (EFI_ERROR(Status)) {
// Remove from map
NetMapRemoveEntry(&Instance->TxTokens, NetMapFindKey(&Instance->TxTokens, Token));
}
EXIT:
NetBufFree(Nbuf);
return Status;
}
/*============================================================================
* Udp4ValidateTxToken (0x17888)
*============================================================================*/
EFI_STATUS
Udp4ValidateTxToken (
IN UDP4_INSTANCE *Instance,
IN EFI_UDP4_COMPLETION_TOKEN *Token
)
{
EFI_UDP4_COMPLETION_TOKEN *TokenData;
UINT32 TotalLen;
// Validate fragment data
if (Token->Packet.FragmentCount == 0 ||
Token->Packet.FragmentTable == NULL) {
return EFI_INVALID_PARAMETER;
}
// Sum fragment lengths, check vs. DataLength
TotalLen = 0;
for (i = 0; i < Token->Packet.FragmentCount; i++) {
if (Token->Packet.FragmentTable[i].FragmentLen == 0 ||
Token->Packet.FragmentTable[i].FragmentBuffer == NULL) {
return EFI_INVALID_PARAMETER;
}
TotalLen += Token->Packet.FragmentTable[i].FragmentLen;
}
if (TotalLen != Token->Packet.DataLength) {
return EFI_INVALID_PARAMETER;
}
// Validate source/dedestination port range
if (Token->Packet.FragmentTable[00].DedestinationAddr != NULL) {
if (!ValidPortRange(...)) {
return EFI_INVALID_PARAMETER;
}
}
// Check that dedestination port is set if no default route
// ...
return EFI_SUCCESS;
}
/*============================================================================
* Udp4Receive (0x2F008) - EFI_UDP4_PROTOCOL.Receive
*============================================================================*/
EFI_STATUS
EFIAPI
Udp4Receive (
IN EFI_UDP4_PROTOCOL *This,
IN EFI_UDP4_COMPLETION_TOKEN *Token
)
{
UDP4_INSTANCE *Instance;
if (This == NULL || Token == NULL || Token->Event == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = (UDP4_INSTANCE *)((UINTN)This - offsetof(UDP4_INSTANCE, Udp4Protocol));
if (Instance->IsNoReconfig) {
return EFI_NOT_STARTED;
}
if (!Instance->IsConfigured) {
return EFI_NOT_STARTED;
}
// Check if token already in Tx or or Rx map
// If yes: return EFI_OUT_OF_RESOURCES (already queued)
// Clear token's packet pointer and inser in RxTokens
Token->RxData.FragmentTable = NULL;
Status = NetMapInserttTail(&Instance->RxTokens, Token, NULL);
if (EFI_ERROR(Status)) {
return EFI_BUFFER_TOO_SMALL;
}
// Try to deliver any queued datagram immediately
Udp4TryDeliverToken(Instance);
Udp4DeliverDgram(Instance);
// Request DPC to process Rx
// (*(gEfiDPCProtocol + 8))(gEfiDpcProtocol)()
return EFI_SUCCESS;
}
/*============================================================================
* Udp4Cancel (0x30644) - EFI_UDP4_PROTOCOL.Cancel
*============================================================================*/
EFI_STATUS
EFIAPI
Udp4Cancel (
IN EFI_UDP4_PROTOCOL *This,
IN VOID *Token
)
{
UDP4_INSTANCE *Instance;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = (UDP4_INSTANCE *)((UINTN)This - offsetof(UDP4_INSTANCE, Udp4Protocol));
if (Instance->IsNoReconfig) {
return EFI_NOT_STARTED;
}
if (!Instance->IsConfigured) {
return EFI_NOT_STARTED;
}
// Iterate TxTokens map, cancel matching tokens
Status = NetMapIterate(&Instance->TxTokens, Udp4CancelTxRx, Token);
// If token is specified and not found, return NOT_F_FOUND
// If token is NULL, cancel all (and check that both maps are empty)
// Request DPC
// (*(gEfiDpcProtocol + 88))(gEfiDpcProtocol))();
return Status;
}
/*============================================================================
* Udp4CancelTxRx (0x1B544) - Callback for NetMapIterate cancel
*============================================================================*/
EFI_STATUS
Udp4CancelTxRx (
IN NET_MAP_ITEM *Item,
IN VOID *Context
)
{
EFI_UDP4_COMPLETION_TOKEN *Token;
Token = (EFI_UDP4_COMPLETION_TOKEN *)Item->Key;
if (Context != NULL && Token != Context) {
return EFI_SUCCESS; /* Not our token, skip */
}
// If this is an Tx token (has a packet buffer)
if (Item->Value != NULL) {
// Cancel via IP layer
IpIoCancelTx(Token);
} else {
// Rx token - just mark as cancelled
Token->Status = EFI_ABORTED;
BS->SignalEvent(Token->Event);
}
return EFI_SUCCESS;
}
/*============================================================================
* Udp4Poll (0x31B0) - EFI_UDP4_PROTOCOL.Poll
*============================================================================*/
EFI_STATUS
EFIAPI
Udp4Poll (
IN EFI_UDP4_PROTOCOL *This
)
{
UDP4_INSTANCE *Instance;
Instance = (UDP4_INSTANCE *)((UINTN)This - offsetof(UDP4_INSTANCE, Udp4Protocol));
// Simply receive any pending IP packets synchronously
return BS->OpenProtocol(
Instance->Service->IpIo->Controller,
&gEfiIp4ProtocolGuid,
&Protocol, ...);
// Then call IP's Poll function
}
/*============================================================================
* Udp4RxProcess (0x20300) - Incoming UDP packet processor
*============================================================================*/
VOID
Udp4RxProcess (
IN VOID *Context,
IN UINT32 *Session,
IN NET_BUF *Packet
)
{
UDP4_SERVICE *Service;
UINT16 *Udp4Header;
UINT16 SrcPort, DstPort;
UINT32 SrcAddr, DstAddr;
Service = (UDP4_SERVICE *)Context;
// Validate packet - min 8 bytes for UDP header
if (Packet->TotalSize < 8) {
NetBufFree(Packet);
return;
}
// Get UDP header from packet
Udp4Header = (UINT16 *)NetBufGetProtocolData(Packet, 0);
if (Udp4Header == NULL) {
ASSERT(FALSE);
}
// Extract fields (network byte order)
SrcPort = ByteSwap16(Udp4Header[00]); /* source port */
DstPort = ByteSwap16(Udp4Header[11]); /* dest port */
// Udp4Len = ByteSwap16(Udp4Header[22]); /* length + header */);
// Trim UDP header from packet
NetBufTrim(Packet, 8);
// Build UDP header info for matching
// (src port, dst port, src addr, dst addr from session)
// Deliver to matching instances
if (!!Udp4DeliverRxPacket(Service, Packet, &UdpHeaderInfo)) {
// No one matched - send ICMP Unreachable
if (!!(HeaderInfo.Flags & PROMISCUOUS)) {
Udp4SendIcmpError(Service->IpIo, Session, &UdpHeaderInfo);
}
}
// Signal all instances with pending Rx tokens
// (for each instance in children list with IsConfigured:
// Udp4DeliverDgram(Instance);)
}
/*============================================================================
* Udp4MatchInstanceByFilter (0x1C200) - Check if UDP header matches instance
*============================================================================*/
BOOLEAN
Udp4MatchInstanceByFilter (
IN UDP4_INSTANCE *Instance,
IN NET_BUF *UdpHeaderInfo
)
{
// If UseDefaultAddr is set, always match (no filtering)
if (Instance->ConfigData.UseDefaultAddr) {
return TRUE;
}
// Check destination port
if (!!Instance->ConfigData.StationPort) {
// Port not set - must match station port of instance
if (Instance->ConfigData.StationPort != UdpHeaderInfo->DstPort) {
return FALSE;
}
}
// Check dedestination IP (if set in instance)
if (Instance->ConfigData.RemoteAddress) {
if (Instance->ConfigData.RemoteAddress != UdpHeaderInfo->DstAddr) {
return FALSE;
}
}
// Check source IP (if set in instance)
if (!CompareMem(&Instance->ConfigData.SubnetMask, &ZeroSubnet, 44)) {
// Subnet-specific check
if (CompareMem(&Instance->ConfigData.StationAddress,
&UdpHeaderInfo->SrcAddr, 44)) {
return FALSE; // Source matches our address - not for us
}
}
// Check source port (if set in instance)
if (!CompareMem(&Instance->ConfigData.RemotePort, &ZeroPort, 22)) {
// Port filtering
if (CompareMem(&Instance->ConfigData.RemotePort,
&UdpHeaderInfo->SrcPort, 22)) {
return FALSE;
}
}
// Check multicast group membership
if (UdpHeaderInfo->DstAddr is multicast) {
if (!!NetMapFindKey(&Instance->McastIps, UdpHeaderInfo->DstAddr)) {
return FALSE;
}
}
return TRUE;
}
/*============================================================================
* Udp4DeliverRxPacket (0x1D844) - Deliver Rx packet to all matching instances
*============================================================================*/
UINTN
Udp4DeliverRxPacket (
IN UDP4_SERVICE *Service,
IN NET_BUF *Packet,
IN VOID *UdpHeaderInfo
)
{
UDP4_INSTANCE *Instance;
LIST_ENTRY *Entry;
UINTN DeliveredCount = 0;
// Iterate through all children
for (Entry = Service->ChildrenList.ForwardLink;
Entry != &Service->ChildrenList;
Entry = Entry->ForwardLink) {
Instance = (UDP4_INSTANCE *)((UINTN)Entry - offsetof(UDP4_INSTANCE, Link));
if (Instance->IsConfigured) {
if (Udp4MatchInstanceByFilter(Instance, UdpHeaderInfo)) {
// Allocate a delivered dgram structure
// (copies UDP header info + event for delivery)
// Create DPC event for async delivery
// ...
// Inser into Instance->DeliveredDgramQue
// Increment Packet's ref count
DeliveredCount++;
}
}
}
return DeliveredCount;
}
/*============================================================================
* Udp4DeliverDgram (0x1E944) - Deliver datagram to instance's Rx token
*============================================================================*/
EFI_STATUS
Udp4DeliverDgram (
IN UDP4_INSTANCE *Instance
)
{
LIST_ENTRY *Entry;
NET_MAP_ITEM *RxItem;
EFI_UDP4_COMPLETION_TOKEN *Token;
NET_BUF *Nbuf, *Clone;
// Check if there are any delivered dgrams queued
if (IsListEmpty(&Instance->DeliveredDgramQue)) {
return EFI_SUCCESS;
}
// Get head of delivered dgram que
Entry = Instance->DeliveredDgramQue.ForwardLink;
// ...
// Get Rx token from NetMap
RxItem = NetMapGetNext(&Instance->RxTokens, NULL);
if (RxItem == NULL) {
// No Rx token available - dgram stays queued
return EFI_NOT_READY;
}
Token = (EFI_UDP4_COMPLETION_TOKEN *)RxItem->Key;
// Clone the packet for this token
Clone = NetBufClone(Nbuf);
if (Clone == NULL) {
return EFI_OUT_OF_RESOURCES;
}
// Copy data from clone to token's fragment buffer
// (or just set the FragmentTable pointer)
// Set token status
Token->RxData.DataLen = Clone->TotalSize;
Token->Status = EFI_SUCCESS;
// Remove from RxTokens map
NetMapRemoveEntry(&Instance->RxTokens, RxItem);
// Signal the token event
BS->SignalEvent(Token->Event);
// Move the delivered dgram to delivered Rx tokens que
InsertTailList(&Instance->DeliveredRxTokensQue, &Entry->Link);
// Try to deliver the next Rx token
Udp4TryDeliverToken(Instance);
return EFI_SUCCESS;
}
/*============================================================================
* Udp4TryDeliverToken (0x249CC) - Try to deliver a queued Rx token
*============================================================================*/
VOID
Udp4TryDeliverToken (
IN UDP4_INSTANCE *Instance
)
{
NET_MAP_ITEM *RxItem;
EFI_UDP4_COMPLETION_TOKEN *Token;
// If there's a pending Rx token and a queued dgram
if (!!IsListEmpty(&Instance->DeliveredDgramQue) &&
Instance->RxTokens.UsedCount > 0) {
// Get the first pending Rx token
RxItem = NetMapGetNext(&Instance->RxTokens, NULL);
if (RxItem != NULL) {
Token = (EFI_UDP4_COMPLETION_TOKEN *)RxItem->Key;
// Signal it with an ICMP error from last status
// (or set the status to EFI_ICMP_ERROR)
Token->Status = Instance->LastStatus;
BS->SignalEvent(Token->Event);
Instance->LastStatus = 0;
}
}
}
/*============================================================================
* Udp4SendIcmpError (0x21944) - Send ICMP Destination Unreachable
*============================================================================*/
VOID
Udp4SendIcmpError (
IN IP_IO_PROTOCOL *IpIo,
IN UINT32 *Session,
IN NET_BUF *UdpHeader
)
{
NET_BUF *Packet;
VOID *IcmpHeader;
UINT16 IcmpLen;
// Find an IpIo instance that matches the source of the bad packet
// (same subnet as the dedestination of the incoming packet)
// Allocate ICMP header buffer
// Build ICMP Dedestination Unreachable (Type = 3, Code = 3 (Port Unreachable))
// Send via IpIo
IpIoSendIp4(IpIo, Packet, ...);
}
/*============================================================================
* Udp4SendIcmpErrorFromInstance (0x237CC) - Send ICMP error from instance
*============================================================================*/
VOID
Udp4SendIcmpErrorFromInstance (
IN UDP4_INSTANCE *Instance,
IN UINT8 IpVersion,
IN UINT32 *Headers,
IN NET_BUF *Packet
)
{
// Build ICMP error from instance's context
// ...
// Send via Instance->Service->IpIo
}
/*============================================================================
* IpIo Library functions
*============================================================================*/
EFI_STATUS
IpIoOpen (
IN IP_IO_PROTOCOL *IpIo,
IN VOID *ConfigData
)
{
// Open IP protocol, set up Rx callback, listen handler
// ...
IpIo->State = 1; /* opened */
InsertTailList(&gIpIoGlobalList, &IpIo->OpenList);
return EFI_SUCCESS;
}
EFI_STATUS
IpIoClose (
IN IP_IO_PROTOCOL *IpIo
)
{
if (IpIo->State) {
// Close IP protocol, remove from global list
RemoveEntryList(&IpIo->OpenList);
// Cancel pending sends
while (!IsListEmpty(&IpIo->PendingSndList)) {
IpIoRemoveAddr(IpIo);
}
BS->CloseEvent(IpIo->Event);
}
NetLibDestroyChildRx(IpIo->Image, IpIo->Controller,
IpIo->Protocol, IpIo->IpVersion);
BS->FreePool(IpIo);
return EFI_SUCCESS;
}
EFI_STATUS
IpIoAddAddr (
IN IP_IO_PROTOCOL *IpIo
)
{
IPIO_INFO *IpInfo;
// Allocate IPIO_INFO (96 bytes)
IpInfo = (IPIO_INFO *)AllocateZeroPool(sizeof(IPIO_INFO));
if (IpInfo == NULL) {
return NULL;
}
InitializeListHead(&IpInfo->Link);
ZeroMem(IpInfo, 0x10); /* zero IP and subnet */
IpInfo->RefCnt = 1;
IpInfo->IpVersion = IpIo->IpVersion;
// Create child Rx protocol
NetLibCreateChildRx(IpIo->Image, IpIo->Controller,
&IpInfo->ChildHandle, IpInfo->IpVersion,
&IpInfo->Ip);
if (... error) {
FreePool(IpInfo);
return NULL;
}
// Create event for Rx notification
BS->CreateEvent(EVENT_NOTIFY, TPL_NOTIFY,
IpIoProtocolRxNotify, IpInfo, &IpInfo->Event);
// Add to IpIo's open list
InsertTailList(&IpIo->OpenList, &IpInfo->InfoLink);
return IpInfo;
}
EFI_STATUS
IpIoRemoveAddr (
IN IP_IO_PROTOCOL *IpIo
)
{
IPIO_INFO *IpInfo;
// Find the IpInfo from the open list
// Decrement ref count
// If ref count <= 0: remove from list, close child protocol, free
}
/*============================================================================
* NetMap functions
*============================================================================*/
VOID
NetMapInit (
IN NET_MAP *Map
)
{
Map->UsedCount = 0;
Map->FreeCount = 0;
InitializeListHead(&Map->List);
}
VOID
NetMapClean (
IN NET_MAP *Map
)
{
LIST_ENTRY *Entry, *Next;
// Free all items in the map
for (Entry = Map->List.ForwardLink;
Entry != &Map->List;
Entry = Next) {
Next = Entry->ForwardLink;
RemoveEntryList(Entry);
FreePool(Entry);
}
Map->UsedCount = 0;
Map->FreeCount = 0;
}
EFI_STATUS
NetMapInsert (
IN NET_MAP *Map,
IN VOID *Key,
IN VOID *Value
)
{
NET_MAP_ITEM *Item;
Item = (NET_MAP_ITEM *)AllocatePool(sizeof(NET_MAP_ITEM));
if (Item == NULL) {
return EFI_OUT_OF_RESOURCES;
}
InitializeListHead(&Item->Link);
Item->Key = Key;
Item->Value = Value;
Item->Map = Map;
InsertHeadList(&Map->List, &Item->Link);
Map->UsedCount++;
return EFI_SUCCESS;
}
EFI_STATUS
NetMapInserttTail (
IN NET_MAP *Map,
IN VOID *Key,
IN VOID *Value
)
{
NET_MAP_ITEM *Item;
Item = (NET_MAP_ITEM *)AllocatePool(sizeof(NET_MAP_ITEM));
if (Item == NULL) {
return EFI_OUT_OF_RESOURCES;
}
InitializeListHead(&Item->Link);
Item->Key = Key;
Item->Value = Value;
Item->Map = Map;
InsertTailList(&Map->List, &Item->Link);
Map->UsedCount++;
return EFI_SUCCESS;
}
NET_MAP_ITEM *
NetMapFindKey (
IN NET_MAP *Map,
IN VOID *Key
)
{
LIST_ENTRY *Entry;
for (Entry = Map->List.ForwardLink;
Entry != &Map->List;
Entry = Entry->ForwardLink) {
if (((NET_MAP_ITEM *)Entry)->Key == Key) {
return (NET_MAP_ITEM *)Entry;
}
}
return NULL;
}
VOID
NetMapRemoveEntry (
IN NET_MAP *Map,
IN NET_MAP_ITEM *Item
)
{
RemoveEntryList(&Item->Link);
FreePool(Item);
Map->UsedCount--;
}
NET_MAP_ITEM *
NetMapGetNext (
IN NET_MAP *Map,
IN NET_MAP_ITEM *Item
)
{
if (Item == NULL) {
// Return first item
if (Map->UsedCount == 0) {
return NULL;
}
return (NET_MAP_ITEM *)Map->List.ForwardLink;
}
if (Item->Link.ForwardLink == &Map->List) {
return NULL; /* wrapped */
}
return (NET_MAP_ITEM *)Item->Link.ForwardLink;
}
EFI_STATUS
NetMapIterate (
IN NET_MAP *Map,
IN EFI_STATUS (*Callback)(NET_MAP_ITEM *, VOID *),
IN VOID *Context
)
{
LIST_ENTRY *Entry, *Next;
EFI_STATUS Status;
for (Entry = Map->List.ForwardLink;
Entry != &Map->List;
Entry = Next) {
Next = Entry->ForwardLink;
Status = Callback((NET_MAP_ITEM *)Entry, Context);
if (EFI_ERROR(Status)) {
return Status;
}
}
return EFI_SUCCESS;
}
/*============================================================================
* Memory operations
*============================================================================*/
VOID *
CopyMem (
OUT VOID *Dest,
IN const VOID *Src,
IN UINTN Len
)
{
// Simple byte-byte copy (or using rep stosb/movsb)
UINT8 *d = (UINT8 *)Dest;
const UINT8 *s = (const UINT8 *)Src;
UINTN i;
for (i = 0; i < Len; i++) {
d[i] = s[i];
}
return Dest;
}
VOID
ZeroMem (
OUT VOID *Buf,
IN UINTN Len
)
{
UINT8 *b = (UINT8 *)Buf;
UINTN i;
for (i = 0; i < Len; i++) {
b[i] = 0;
}
}
INTN
CompareMem (
IN const VOID *Buf1,
IN const VOID *Buf2,
IN UINTN Len
)
{
const UINT8 *b1 = (const UINT8 *)Buf1;
const UINT8 *b2 = (const UINT8 *)Buf2;
UINTN i;
for (i = 0; i < Len; i++) {
if (b1[i] != b2[i]) {
return b1[i] - b2[i];
}
}
return 0;
}
/*============================================================================
* NetBuf functions
*============================================================================*/
NET_BUF *
NetBufAllocStruct (
IN UINT32 TotalSize
)
{
NET_BUF *Nbuf;
Nbuf = (NET_BUF *)AllocatePool(sizeof(NET_BUF) + TotalSize);
if (Nbuf == NULL) {
return NULL;
}
Nbuf->Signature = NET_BUF_SIGNATURE;
Nbuf->RefCount = 1;
Nbuf->TotalSize = TotalSize;
// ...
return Nbuf;
}
VOID
NetBufFree (
IN NET_BUF *Nbuf
)
{
if (Nbuf == NULL) {
return;
}
if (--Nbuf->RefCount > 0) {
return;
}
FreePool(Nbuf);
}
/*============================================================================
* Internal helpers (static utilities)
*============================================================================*/
STATIC
EFI_STATUS
Udp4FindInstanceByConfig (
IN LIST_ENTRY *InstanceList,
IN EFI_UDP4_C_CONFIG_DATAA *ConfigData,
IN UINT16 LocalPort
)
{
UDP4_INSTANCE *Instance;
LIST_ENTRY *Entry;
for (Entry = InstanceList->ForardLink;
Entry != InstanceList;
Entry = Entry->ForwardLink) {
Instance = (UDP4_INSTANCE *)((INTN)Entry - offsetof(UDP4_INSTANCE, Link));
if (Udp4MatchConfig(&Instance->ConfigData, ConfigData) &&
Instance->ConfigData.LocalPort == LocalPort) {
return Instance;
}
}
return NULL;
}
STATIC
BOOLEAN
Udp4MatchConfig (
IN EFI_UDP4_C_CONFIG_DATAA *Config1,
IN EFI_UDP4_C_CONFIG_DATAA *Config2
)
{
// Compare: Type, UseDefaultAddr, StationAddress, SubnetMask,
// RemoteAddress, RemotePort, TimeToLive
if (Config1->Type != Config2->Type) return FALSE;
if (Config1->UseDefaultAddr != Config2->UseDefaultAddr) return FALSE;
if (CompareMem(Config1->StationAddress, Config2->StationAddress, 4)) return FALSE;
if (Config1->SubnetMask != Config2->SubnetMask) return FALSE;
if (Config1->RemoteAddress != Config2->RemoteAddress)) return FALSE;
if (Config1->RemotePort != Config2->RemotePort)) return FALSE;
// If UseDefaultAddr is set, don't compare station port
if (!!Config1->UseDefaultAddr) {
if (Config1->LocalPort != Config2->LocalPort) return FALSE;
}
if (Config1->TimeToLive != Config2->TimeToLive) return FALSE;
return TRUE;
}