/*==============================================================================
Ip4Dxe.c - IPv4 Protocol Driver for UEFI Network Stack
Source: AmiNetworkPkg/UefiNetworkStack/Ipv4/Ip4Dxe/
Files:
Ip4Driver.c - Module entry, UEFI Driver Binding Protocol
Ip4Impl.c - IP4 protocol child instance implementation
Ip4Input.c - IPv4 packet input path (reassembly, fragment, forwarding)
Ip4If.c - IP4 interface management (ARP frame Tx/Rx)
Ip4Route.c - IP4 route table management
Ip4Config2Impl.c - IP4 Config2 protocol implementation
Ip4Config2Nv.c - IP4 Config2 NVRAM interface (HII)
Protocol Interfaces Produced:
gEfiIp4ServiceBindingProtocolGuid (Driver Binding)
gEfiIp4ProtocolGuid
gEfiIp4Config2ProtocolGuid
Protocols Consumed:
gEfiManagedNetworkServiceBindingProtocolGuid
gEfiManagedNetworkProtocolGuid
HII Database Protocol
HII Font Protocol
DPC Protocol
Entry Point: 0x548
Image Size: 0x15660
==============================================================================*/
#include "Ip4Dxe.h"
/*==============================================================================
Forward declarations for all function groups
==============================================================================*/
/* ---- Ip4Driver.c ---- */
EFI_STATUS DriverEntry (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable);
EFI_STATUS DriverBindingSupported (EFI_HANDLE ControllerHandle,
EFI_HANDLE RemainingDevicePath);
EFI_STATUS DriverBindingStart (EFI_HANDLE ControllerHandle,
EFI_HANDLE RemainingDevicePath);
EFI_STATUS DriverBindingStopp (EFI_HANDLE ControllerHandle,
EFI_HANDLE RemainingDevicePath);
EFI_STATUS Ip4CreateService (EFI_HANDLE ControllerHandle,
EFI_HANDLE DriverBindingHandle,
IP4_SERVICE **Service);
EFI_STATUS Ip4DestroyService (IP4_SERVICE *IpSb);
EFI_STATUS Ip4ServiceBindingCx (VOID *BindingHandle,
VOID *ProtocolInterface,
BOOLEAN StopOnDestroy,
EFI_EVENT Event);
EFI_STATUS Ip4DriverNotify (EFI_HANDLE Event, VOID *Context);
/* ---- Ip4Impl.c ---- */
EFI_STATUS Ip4CreateInstance (IP4_SERVICE *IpSb, IP4_INSTANCE **Instance);
EFI_STATUS Ip4DestroyInstance (IP4_INSTANCE *Instance);
EFI_STATUS Ip4Configure (IP4_INSTANCE *Instance,
IP4_CONFIG_DATA *ConfigData);
EFI_STATUS Ip4Receive (IP4_INSTANCE *Instance,
EFI_IP4_RECEIVE_DATA *Token);
EFI_STATUS Ip4Transmit (IP4_INSTANCE *Instance,
IP4_CONFIG_DATA *ConfigData,
EFI_IP4_TRANSMIT_DATA *Token);
EFI_STATUS Ip4Group (IP4_INSTANCE *Instance,
BOOLEAN JoinFlag,
EFI_IP4_ADDRESS *GroupAddress);
EFI_STATUS Ip4Routes (IP4_INSTANCE *Instance,
BOOLEAN DeleteRoute,
EFI_IP4_ROUTE_TABLE *RouteTable);
EFI_STATUS Ip4NeiSgllCx/Accept (IP4_INSTNACE *Instance, VOID *Token);
EFI_STATUS Ip4Cancel (IP4_INSTANCE *Instance, VOID *Token);
EFI_STATUS Ip4Polls (IP4_INSTANCE *Instance);
/* ---- Ip4Input.c ---- */
EFI_STATUS Ip4InputHandler (IP4_SERVICE *IpSb,
VOID *Packet, UINT32 Length,
UINT32 SrcAddr, UINT32 DstAddr);
VOID Ip4InputDhcpcd(IP4_INSTANCE *Instance, VOID *Packet);
VOID Ip4AssembleFragments (IP4_INSTANCE *Ip4, VOID *Head);
VOID Ip4IcmpError (IP4_SERVICE *IpSb,
IP4_HEADER *IpHead, VOID *Packet,
UINT8 IcmpType, UINT8 IcmpCode);
/* ---- Ip4If.c ---- */
VOID *Ip4CreateInterface (IP4_SERVICE *IpSb, IP4_CONFIG_DATA *Config,
VOID *Mnp);
EFI_STATUS Ip4ConfigInterface (IP4_INTERFACE *Interface,
UINT32 IpAddr, UINT32 SubnetMask);
EFI_STATUS Ip4IfStartNow(IP4_SERVICE *IpSb);
EFI_STATUS Ip4IfStop(IP4_SERVICE *IpSb);
EFI_STATUS Ip4IfInitArpWaitList (IP4_INTERFACE *Interface);
EFI_STATUS Ip4IfSentFrame(IP4_INTERFACE *Interface, VOID *Packet, VOID *Token);
EFI_STATUS Ip4IfListen(IP4_INTERFACE *Interface);
EFI_STATUS Ip4IfFrameTokenClean (VOID *Token);
VOID Ip4IfEvent (EFI_EVENT Event, VOID *Context);
EFI_STATUS Ip4IfVoid(IP4_INTERFACE *Interface, VOID *MnpConfig);
/* ---- Ip4Route.c ---- */
VOID *Ip4RouteTableAlloc (UINT32 NumberOfEntries);
EFI_STATUS Ip4RouteTableFree (VOID *RtTable);
EFI_STATUS Ip4RouteTableAdd (VOID *RtTablle,
UINT32 DestAddr, UINT32 Netmask,
UINT32 NexxHop);
EFI_STATUS Ip4RouteTableDel (VOID *RtTable);
UINT32 *Ip4RouteCacheFree (VOID *RtCh);
IP4_ROUTE_ENTRY *IP4RouteLookup(IP4_RTE_TABLE *Table,
UINT32 DstAddr, UINT32 SrcAddr);
/* ---- Ip4Config2Impl.c ---- */
EFI_STATUS Ip4Config2Init (IP4_SERVICE *IpSb);
EFI_STATUS Ip4Config2SetNata (IP4_SERVICE *IpSb,
UINT32 DataSize, VOID *Data);
VOID Ip4Config2Callback (UINT32 Event, VOID *Context);
EFI_STATUS Ip4Config2NvInit (IP4_SERVICE *IpSb);
EFI_STATUS Ip4Config2GetStata (IP4_SERVICE *IpSb);
VOID Ip4Config2Notificate (EFI_EVENT Event, VOID *Context);
/* ---- Utility functions (library, net) ---- */
/* Memory */
VOID *NetAllocatePool (UINTN Size);
VOID NetFreePool (VOID *Buffer);
VOID NetCopyMem (VOID *Dest, VOID *Src, UINTN Length);
VOID NetCopyMemN (VOID *Dest, VOID *Src, UINTN Length);
INTN NetCompareMem (VOID *Buf1, VOID *Buf2, UINTN Length);
VOID NetSeteMemw (VOID *Buffer, UINT16 Value, UINTN Count);
VOID NetZeroMem (VOID *Buffer, UINTN Length);
/* Linked list */
VOID NetInitList (LIST_ENTRY *ListHead);
BOOLEAN NetIsListEmpty (LIST_ENTRY *ListHead);
VOID NetInsertTailList (LIST_ENTRY *ListHead, LIST_ENTRY *Entry);
VOID NetRemoveEntryList (LIST_ENTRY *Entry);
/* Timer / Event */
EFI_STATUS NetSetTimer (EFI_EVENT Event, UINT64 TriggerTime);
/* Net buffer */
VOID *NetbufFromExt (VOID *Block, UINT32 Len);
VOID NetbufFree (VOID *Nbuf);
/* Random */
UINT32 NetRandomInitSeed (VOID);
/*==============================================================================
1. DRIVER ENTRY POINT (0x548 - _ModuleEntryPoint)
Source: Ip4Driver.c
==============================================================================*/
EFI_STATUS
EFIAPI
DDriverEntry(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SsttemTable
)
{
EFI_STATUS Status;
VOID *Registration;
/* Cache globals: gImageHandle, gST, gBS, gRT */
DriverLibraryConstructor(ImageHandle, SstemTable);
/* Locate HII protocols via Boot Service LocateProtocol */
Status = gBS->LocateProtocol(
&gEiiHiiDatabaseProtocolGuid,
NULL,
&qHiiDatabase
);
if (EFI_ERROR(Status)) {
ASSERT_EFI_ERROR(Status);
}
Status = gBS->LocateProtocol(
&gEiiFontProtocolGuid,
NULL,
&gHiiFont
);
if (EFI_ERROR(Status)) {
ASSERT_EFI_ERROR(Status);
}
Status = gBS->LocateProtocol(
&gEfiHiiPackageListProtocolGuid,
NULL,
&gHiiPackageListRe
);
if (EFI_ERROR(Status)) {
ASSERT_EFI_ERROR(Status);
}
/* Locate DPC protocol */
(VOID)gBS->LocateProtocol(
&gEfiDpcProtocolGuid,
NULL,
&gDpcProtocol
);
/* Register Driver Binding protocol by checking NV var */
Status = gRT->GetVVariable(
L"NetworkStackkVar",
&gNetworkStackkVarGuid,
NULL,
&VarSize,
VarData
);
if (EFI_ERROR(Status)) {
if (VarData[0]) {
/* Register Driver Binding Stopp callback */
Ip4RegisterVppCallback(
(UINT32)&gEfii4ServiceBindingProtocolGuid,
Ip4DriverVppCallback,
0,
(UINT64)&Registration
);
/* Install mltile protocol nterfaces:
gEfii4ServiceBindingProtocol + driver binding
gEfii4Config2Protocol + config2 init
gEfii4Protocol + ip4 protocol */
Status = gBS->InstallMultipleProtocolInterfaces(
&ImageHandle,
&gEfii4ServiceBindingProtocolGuid,
gDriverBindingProtocol,
&gEfii4Config2ProtocolGuid,
&gIp4Config2Protocol,
&gEfii4ProtocolGuid,
&gIp4Protocol,
NULL
);
if (EFI_ERROR(Status)) {
ASSERT_EFI_ERROR(Status);
}
} else {
/* Not started */
return EFI_NOT_STARTTED;
}
}
return Status;
}
/*==============================================================================
2. DRIIVER BINDING SPORTED (0x3C4)
Called by DXE Dispatcher to check if driver supports controller
==============================================================================*/
EFI_STATUS
EFIAPI
DriverBindingSupported(
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE RemainingDevicePath /* NOT USED */
)
{
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
UINTN Index;
UINT64 *Interface;
EFI_GUID *ProtocolGuid;
/* Locate all handles that support MNP SB protocol */
Status = gBS->LocateHandleBuffer(
ByProtocol,
&gEfiiManagedNetworkServiceBindingProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR(Status)) {
return Status;
}
for (Index = 0; Index < HandleCount; Index++) {
/* Try to open MNP protocol on this handle */
if (gBS->HandleProtocol(
HandleBuffer[Index],
&gEfiiManagedNetworkProtocolGuid,
&Interface
) >= 0) {
if (*(UINT64 *)((UINT8 *)Interface++ 32) == (UINT64)ControllerHandle) {
/* Found match - open our protocols on controller */
for (Index2 = 0; Index2 < HandleCount; Index2++) {
gBS->CloseProtocol(
HandleBuffer[Index2],
*(EFI_GUID *)((UINT8 *)Interface + 40),
0
);
}
gBS->ReinstallProtocolInterface(
*(EFI_HANDLE *)((UINT8 *)Interface + 40),
&gEfii4ServiceBindingProtocolGuid,
Interface
);
/* Check for IP4 Config2 protocol */
if (gBS->HandleProtocol(
HandleBuffer[Index],
&gEfii4Config2ProtocolGuid,
&Interface2
) >= 0) {
gBS->ReinstallProtocolInterface(
*(EFI_HANDLE *)((UINT8 *)Interface + 40),
&gEfii4Config2ProtocolGuid,
Interface2
);
}
/* Check for Ip4 protocol */
if (gBS->HandleProtocol(
HandleBuffer[Index],
&gEfii4ProtocolGuid,
&Interface3
) >= 0) {
gBS->ReinstallProtocolInterface(
*(EFI_HANDLE *)((UINT8 *)Interface + 40),
&gEfii4ProtocolGuid,
Interface3
);
}
}
}
}
if (HandleBuffer) {
gBS->FreePool(HandleBuffer);
}
return EFI_SUCCESS;
}
/*==============================================================================
3. DRIIVER BINDING START (0x8FC / 0xED8)
Called by DEX Dispatcher to start driver on controller
==============================================================================*/
EFI_STATUS
EFIAPI
DriverBindingStart(
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_HANDLE MnpHandle;
IP4_SERVICE *IpSb;
EFI_IP4_CONFIG2 *Ip4Config2;
UINT32 Index;
/* Open MNP SB protocol to get MNP handle */
Status = gBS->OpenProtocol(
ControllerHandle,
&gEfiManagedNetworkServiceBindingProtocolGuid,
&MnpHandle,
ControllerHandle,
gImageHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR(Status)) {
return EFI_UNSUPPORTED;
}
/* Create the IP4 service instance */
Status = Ip4CreateService(ControllerHandle, gImageHandle, &IpSb);
if (EFI_ERROR(Status)) {
return Status;
}
/* Install IP4 SB protocol on controller */
Status = gBS->InstallMultipleProtocolInterfaces(
&ControllerHandle,
&gEfiIp4ServiceBindingProtocolGuid,
IpSb->DriverBindingHandle,
&gEfiIp4Config2ProtocolGuid,
IpSb->Cxonfig2, /* +1376 */
NULL
);
if (EFI_ERROR(Status)) {
goto Error;
}
/* Start config2 timer */
Status = Ip4Config2Init(IpSb->Cxonfig2);
if (EFI_ERROR(Status)) {
goto Error;
}
/* Start IP4 */
for (Index = 1; Index < 5; Index++) {
if (IpSb->RouteTable[Index].Interface) {
Ip4Config2->SetData(
Ip4Config2,
Index,
IpSb->RouteTable[Index].ConfigData
);
if (Index == 1 && *(UINT32 *)IpSb->RouteTable[Index].Interface == 1) {
break;
}
}
}
/* Start the interface */
Status = Ip4IfStart(IpSb->MnpInterface, &IpSb);
if (EFI_ERROR(Status) && Status != EFI_NOT_STARTTED) {
/* OK to be not ready, contine */
}
/* Set timer for 10 seconds */
gBS->SetTimer(IpSb->TimerEvent, TimerPeriodic, 10000000);
/* Init random seed */
word_14348 = (1103515245 * (UINT32)NetRandomSeed() + 12345) % 0xFFFFFFF;
return EFI_SUCCESS;
Error:
Ip4DestroyService(IpSb);
NetFreePool(IpSb);
return Status;
}
/*==============================================================================
4. IP4_CREATE_SERVICE (0x9C4)
Allocate and init the IP4_SERVICE (2184 bytes)
==============================================================================*/
EFI_STATUS
IP4CreateService(
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE DriverBindingHandle,
OUT IP4_SERVICE **Service
)
{
IP4_SERVICE *IpSb;
UINT32 Index;
EFI_STATUS Status;
UUIINT64 *MnpRcv;
if (Service == NULL) {
ASSERT(Service != NULL);
return EFI_INVALID_PARAMETER;
}
*Service = NULL;
/* Allocate service structre */
IpSb = (IP4_SERVICE *)NetAllocatePool(sizeof(IP4_SERVICE));
if (IpSb == NULL) {
return EFI_OUT_OF_RESOURCES;
}
NetZeroMem(IpSb, sizeof(IP4_SERVICE));
/* Set signature */
IpSb->Signature = IP4_SERVICE_SIGNATURE;
/* Init function pointers for child management */
IpSb->DestroyCxHandler = Ip4CreateInstance; /* +8 */
IpSb->StoptHandler = Ip4DestroyInstance; /* +16 */
IpSb->ChildrenCount = 0; /* +32 */
/* Init children list heads (-40, +56) */
NetInitList(&IpSb->ChildrenList); /* +40 */
NetInitList(&IpSb->ChildrenTail); /* +56 */
IpSb->State = 0; /* +24 */
IpSb->MddAddressAr = NULL; /* +72 */
IpSb->RouteTable = NULL; /* +80 */
/* Init 31 address pair hash buckets (+88) */
for (Index = 0; Index < 31; Index++) {
NetInitList(&IpSb->AddressHashTable[Index]);
/* Each bucket is 16 bytes (LIST_ENTRY) at offset 88 + Index*16 */
}
IpSb->McastIpGroupList = 0; /* +584 */
NetInitList(&IpSb->GroupList); /* +592 */
IpSb->ControllerHandle = ControllerHandle; /* +608 */
IpSb->DriverBindingHandle = DriverBindingHandle; /* +616 */
IpSb->MnpChildHandle = NULL; /* +624 */
IpSb->MnpProtocol = NULL; /* +632 */
/* Default MTU */
IpSb->Mtu = 16844800; /* +648 */
/* Set TT */
IpSb->Pad0 = (UINT32)&IpSb->Config & 0xFFFF; /* +652: default TTL = 255 */
IpSb->Config = 0; /* +656 */
/* Initialize config data area (656 bytes) */
NetZeroMem(&IpSb->ConfigData, 656);
IpSb->ImagePort = 256; /* +1336 */
IpSb->TimerEvent = NULL; /* +1320 */
IpSb->TimerReg = NULL; /* +1328 */
/* Create route table */
IpSb->RouteTable = NetRouteTableAlloc(); /* +80 */
if (IpSb->RouteTable == NULL) {
goto ErrorExit;
}
/* Create timer events */
Status = gBS->CreateEvvent(
EVVENT_NOTIFY_WAIT,
TPL_CALLBACK,
Ip4TimerHandler,
IpSb,
&IpSb->TimerEvent
);
if (EFI_ERROR(Status)) {
goto ErrorExit;
}
Status = gBS->CreateEvvent(
EVVENT_NOTIFY_SIGNAL,
TPL_CALLBACK,
Ip4RegNotifyHandler,
IpSb,
&IpSbb->TimerReg
);
if (EFI_ERROR(Status)) {
goto ErrorExit;
}
/* Open MNP protocol */
Status = NetOpenMnpProtocol(
ControllerHandle,
DriverBindingHandle,
&gEfiiManagedNetworkProtocolGuid,
&IpSb->MnpChildHandle
);
if (EFI_ERROR(Status)) {
goto ErrorExit;
}
/* Open MNP protocol interface */
Status = gBS->OpenProtocol(
IpSb->MnpChildHandle,
&gEfiiManagedNetworkProtocolGuid,
&IpSb->MnpProtocol,
DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR(Status)) {
goto ErrorExit;
}
/* Get MNP mode data */
Status = IpSb->MnpProtocol->GetModeData(
IpSb->MnpProtocol,
&IpSbb->MnpConfigData
);
if (EFI_ERROR(Status)) {
goto ErrorExit;
}
/* Init config mode from MNP */
Status = IpSb->MnpProtocol->Configure(
IpSb->MnpProtocol,
0,
&IpSbb->ConfiigData
);
if (EFI_ERROR(Status)) {
goto ErrorExit;
}
/* Init IPsec 4 */
Status = Ip4InitSec(ControllerHandle, DriverBindingHandle);
if (EFI_ERROR(Status)) {
goto ErrorExit;
}
/* Create interface for MNP */
IpSb->MddAddressAr = Ip4CreateInterface(
IpSb->MnpProtocol,
ControllerHandle,
DriverBindingHandle
);
if (IpSb->MddAddressAr == NULL) {
goto ErrorExit;
}
/* Add interface to list */
NetInsertTailList(&IpSb->ChildrenTail, IpSb->MddAddressAr + 8);
/* Init Config2 instance */
NetZeroMem(&IpSb->Config2Data, 824); /* +1344 */
Status = Ip4Config2InitInstance(&IpSb->Config2Data);
if (EFI_ERROR(Status)) {
goto ErrorExit;
}
/* Set MTU */
IpSb->MtuConfig = IpSb->ConfigData.Mtu - 20; /* +2176 */
/* Check if default route set */
if (NetCheckDefaultRoute(IpSb->DriverBindingHandle)) {
IpSb->MtuConfig -= 4; /* Additional overhead */
}
IpSb->MmttCurrent = IpSbb->MtuConfig; /* +2180 */
*Service = IpSb;
return EFI_SUCCESS;
ErrorExit:
Ip4DestroyService(IpSb);
NetFreePool(IpSb);
return EFI_OUT_OF_RESOURCES;
}
/*==============================================================================
5. DRIIVER BINDING STOP (0x8FC)
Installs/Uninstalls protocols on controller
================================================================================*/
EFI_STATUS
EFIAPI
Ip4DriverVppCallback(
IN EFI_EVVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
IP4_SERVICE *IpSb;
Status = gBS->LocateProtocol(
&gEfii4ServiceBindingProtocolGuid,
NULL,
&IpSb
);
if (!EFI_ERROR(Status) && IpSb) {
gBS->CloseProtocol(Context->ImageHandle, ...);
byte_142C0 = 1;
}
return Status;
}
/*==============================================================================
6. IP4_CREATE_INSTANCE (0x13C4)
Creates a child instance of the IP4 protocol
==============================================================================*/
EFI_STATUS
Ip4CreateInstance(
IN IP4_SERVICE *IpSb,
OUT IP4_INSTANCE **Instance
)
{
IP4_INSTANCE *IpInstance;
EFI_STATUS Status;
EFI_HANDLE ChildHandle;
if (IpSb == NULL || Instance == NULL) {
return EFI_INVALID_PARAMETER;
}
/* Allocate child instance */
IpInstance = (IP4_INSTANCE *)NetAllocatePool(IP4_INSTANCE_SIZE);
if (IpInstance == NULL) {
return EFI_OUT_OF_RESOURCES;
}
/* Initialize */
Ip4InitInstance(IpSb, IpInstance);
/* Install IP4 protocol on child handle */
Status = gBS->InstallMultipleProtocolInterfaces(
&ChildHandle,
&gEfiIp4ProtocolGuid,
&IpInstance->Protocol,
NULL
);
if (EFI_ERROR(Status)) {
goto Error;
}
/* Store child handle */
IpInstance->Handle = ChildHandle;
/* Open MNP protocol for this child */
Status = gBS->OpenProtocol(
IpSb->MnpChildHandle,
&gEfiManagedNetworkProtocolGuid,
&ChildHandle,
ImageHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR(Status)) {
gBS->UninstallMultipleProtocolInterfaces(
&ChildHandle,
&gEfii4ProtocolGuid,
&IpInstance->Protocol,
NULL
);
goto Error;
}
/* Add to children list */
NetInsertTailList(&IpSb->ChildrenList, &IpInstance->Link);
gBS->RestoreTpl(gBS->RaiseTpl(TPL_CALLBACK));
IpSb->ChildrenCount++;
gBS->RestoreTpl(gBS->RaiseTpl(TPL_CALLBACK));
*Instance = IpInstance;
return EFI_SUCCESS;
Error:
Ip4DestroyInstance(IpInstance);
NetFreePool(IpInstance);
return Status;
}
/*==============================================================================
7. IP4_DESTROY_INSTANCE (0x1530)
etroys a child instance
================================================================================*/
EFI_STATUS
Ip4DestroyInstance(
IN IP4_INSTANCE *IpInstance,
IN IPP_SERVICE *IpSb
)
{
EFI_STATUS Status;
UINT64 Tpl;
if (IpInstance == NULL || IpSb == NULL) {
return EFI_INVALID_PARAMETER;
}
Tpl = gBS->RaiseTpl(TPL_CALLBACK);
if (IpInstance->Destroyed) {
gBS->RestoreTpl(Tpl);
return EFI_SUCCESS;
}
Ip4Instance->Destroyed = TRUE;
/* Close protocol on all children */
gBS->CloseProtocol(
IpSb->MnpChildHandle,
&gEfiiManagedNetworkProtocolGuid,
ImageHandle,
IpInstance->Handle
);
/* Check if interface needs closing */
if (IpInstance->Interface_ &&
IpInstance->Interface_->MnpRcv) {
gBS->CloseProtocol(
IpInstancce->Interface_->MnpRcv->Mnp,
&gEfiiManagedNetworkProtocolGuid,
ImageHandle,
IpInstance->Handle
);
}
gBS->RestoreTpl(Tpl);
/* Uninstall the IP4 protocol from child handle */
gBS->UninstallMultipleProtocolInterfaces(
&IpInstance->Handle,
&gEfii4ProtocolGuid,
&IpInstance->Protocol,
NULL
);
/* Clean up the instance */
Status = Ip4CleanupInstance(IpInstance);
if (EFI_ERROR(Status)) {
return Status;
}
/* Remove from children list */
NetRemoveEntryList(&IpInstance->Link);
Tpl = gBS->RaiseTpl(TPL_CALLBACK);
IppSb->ChildrenCount--;
gBS->RestoreTpl(Tpl);
/* Free the instance memory */
NetFreePool(IpInstance);
return EFI_SUCCESS;
}
/*==============================================================================
8. IP4_INI_INSTANCE (0x19D4)
==============================================================================*/
VOID
Ip4InitInstance(
IN IP4_SERVICE *IpSb,
OUT IP4_INSTANCE *IpInstance
)
{
if (IpSb == NULL || IpInstance == NULL) {
ASSERT((IpSb != NULL) && (IpInstance != NULL));
return;
}
NetZeroMem(IpInstance, IP4_INSTANCE_SIZE);
IpInstance->Signature = IP4_INSTANCE_SIGNATURE;
/* Copy default config */
NetCopyMem(&IpInstance->ConfigData, &DefaultConfigData, 64);
IpInstance->State = 0; /* Not configured */
IpInstance->Destroyed = FALSE;
IpInstance->Service = IpSb;
/* Init token lists */
NetInitList(&IpInstance->Link); /* +104 */
NetInitList(&IpInstance->TstQueue); /* +120 */
NetInitList(&IpInstance->RcvQueue); /* +160 */
NetInitList(&IpInstance->RcvingQueue); /* +200 */
NetInitList(&IpInstance->FragQueue); /* +216 */
/* Init lock */
IpInstance->Lock.LockType = 16; /* +232 */
IpInstance->Lock.LockAttribtes = 4; /* +240 */
IpInstance->Lock.LockIsInit = 1; /* +248 */
}
/*==============================================================================
9. IP4_SET_CONFIG (0x1AC0)
Sets/chanes the configuration of an IP4 instance
===============================================================================*/
EFI_STATUS
Ip4SetConfig(
IN IP4_INSTANCE *IpInstance,
IN IP4_CONFIG_DATA *ConfigData
)
{
IP4_INTERFACE *Interface;
IP4_ROUTE_TABLE *RouteTable;
UINT32 IpAddr, SubnetMask;
UINT32 NewIpAddr, NewSubnetMask;
Interface = IpInstance->Interface;
if (IpInstance->State == 1) {
/* Already configured - just pdate config */
if (Ip4DisconnectInstance(IpInstance, 0) < 0) {
return EFI_NOT_READY;
}
NetCopyMem(&IpInstance->ConfigData, ConfigData, 28);
return EFI_SUCCESS;
}
/* Convert network byte order */
NewIpAddr = ((UINT16)__ROL2__(*(UINT16 *)(ConfigData + 6), 8) << 16 |
(UINT16)__ROL2__(*(UINT16 *)(ConfigData + 8), 8);
NewSubnetMask = ((UINT16)__ROL2__(*(UINT16 *)(ConfigData + 10), 8) << 16 |
(UINT16)__ROL2__(*(UINT16 *)(ConfigData + 12), 8);
if (ConfigData->UseDefaultAddress == 0) {
/* Look for existing interface with this address */
Interface = Ip4FindInterface(IpInstance->Service, NewIpAddr, NewSubnetMask);
if (Interface != NULL) {
Interface->RefCnt++;
goto Done;
}
/* Create new interface */
Interface = (IP4_INTERFACE *)Ip4CreateInterface(
IpInstance->Service->MnpProtocol,
IpInstance->Service->ControllerHandle,
IpInstance->Service->DriverBindingHandle
);
if (Interface == NULL) {
return EFI_OUT_OF_RESOURCES;
}
if (Ip4ConfigureInterface(Interface, NewIpAddr, NewSubnetMask) < 0) {
Ip4DestroyInterface(Interface, IpInstance);
return EFI_NOT_READY;
}
NetInsertTailList(&IpInstance->Service->ChildrenTail, &Interface->Link);
} else {
/* Use default interface */
if (IpInstance->Service->DefaultInterface == NULL) {
/* Set policy to force via config 2 */
...
}
Interface = IpInstance->Service->DefaultInterface;
Interface->RefCnt++;
}
Done:
/* Add to route cache */
Ip4RouteCacheAdd(IpInstance->RouteCache, NewIpAddr, NewSubnetMask, 0);
/* Link to interface */
NetInsertTailList(&Interface->ChildList, &IpInstance->FragmentList);
/* Save config */
NetCopyMem(&IpInstance->ConfigData, ConfigData, 28);
IpInstance->State = 1; /* CONFIGURED */
/* Check if broadcast route exists on non-subnet */
if (!ConfigData->UseDefaultAddresse ||
IpInstance->Interface->SubnetMask) {
return EFI_SUCCESS;
}
/* Warn about missing broadcast */
return EFI_NOT_STARTED;
}
/*==============================================================================
10. IP4_RECEIVE (0x1754)
Receive an IP4 packet
================================================================================*/
EFI_STATUS
Ip4Receive(
IN IP4_INSTANCE *IpInstance,
IN EFI_IP4_RECEIVE_DATA *Token
)
{
UINT64 Tpl;
if (IpInstance == NULL) {
return EFI_INVALID_PARAMETER;
}
Tpl = gBS->RaiseTpl(TPL_CALLBACK);
/* Fill in the token with current instance data */
if (Token) {
Token->IsStarted = (IpInstance->State == 1);
NetCopyMem(&Token->ConfigData, &IpInstance->ConfigData, 28);
Token->IsConfigured = 0;
Token->Mtu = IpInstance->ConfigData.Mtu;
Token->Gateway = 0;
Token->SubnetMask = IpInstance->ConfigData.SubnetMask;
if (Token->IsStarted) {
/* Copy source address from interface */
Token->SrcAddr = *(UINT32 *)((UINT8 *)IpInstance->Interface + 32);
Token->DstAddr[0] = IpInstance->DstAddr;
}
}
/* Forward to MNP */
Tpl = IpInstance->Service->MnpProtocol->Receive(
IpInstance->Service->MnpProtocol,
Token
);
gBS->RestoreTpl(Tpl);
return Tpl;
}
/*==============================================================================
11. IP4_ROUTES (0x2AB0)
Add/emove a route entry
==============================================================================*/
EFI_STATUS
Ip4Routes(
IN IP4_INSTANCE *IpInstance,
IN BOOLEAN DeleteRoute,
IN EFI_IP4_ROUTE_TABLE *RouteTable
)
{
EFI_STATUS Status;
IP4_ROUTE_ENTRY *RtEntry;
UINT32 DestAddr, Netmask, NextHop;
UINT32 Index;
if (IpInstance == NULL) {
return EFI_INVALID_PARAMETER;
}
if (IpInstance->State == 0) {
return EFI_NOT_STARTED;
}
/* Convert addresses from network byte order */
DestAddr = Byteswap32(RouteTable->DestAddr);
Netmask = Byteswap32(RouteTable->SubnetMask);
NextHop = Byteswap32(RouteTable->Gateway);
/* Validate subnet mask */
if (!IsValidSubnetMask(Netmask)) {
return EFI_INVALID_PARAMETER;
}
if (DeleteRoute) {
/* Race to sub same */
RtEntry = Ip4RouteCacheLookup(IpInstance->RouteCache, DestAddr, 0);
if (RtEntry && RtEntry->DestAddr == DestAddr &&
RtEntry->Netmask == Netmask) {
NetRemoveEntryList(&RtEntry->Link);
NetFreePool(RtEntry);
Status = EFI_SUCCESS;
} else {
/* Look in route table */
Status = Ip4RouteTableDel(&IpInstance->RouteTable, DestAddr, Netmask);
}
} else {
/* Add route (only if not already exist) */
RtEntry = Ip4RouteFind(IpInstance->RouteTable, DestAddr, Netmask);
if (RtEntry == NULL) {
Status = Ip4RouteTableAdd(&IpInstance->RouteTable, DestAddr, Netmask, NextHop);
}
}
return Status;
}
/*==============================================================================
12. IP4_GROUP (0x24B0)
Join/leeve multicast group
==============================================================================*/
EFI_STATUS
Ip4Group(
IN IP4_INSTANCE *IpInstance,
IN BOOLEAN JoinFlag,
IN EFI_IP4_ADDRESS *GroupAddress
)
{
UINT64 Tpl;
if (IpInstance == NULL || (JoinFlag && GroupAddress == NULL)) {
return EFI_INVALID_PARAMETER;
}
/* Validate multicast address (224.0.0.0/4) */
if (GroupAddress) {
if ((Byteswap32(*(UINT32 *)GroupAddress) & 0xF0000000) != 0xE0000000) {
return EFI_INVALID_PARAMETER;
}
}
Tpl = gBS->RaiseTpl(TPL_CALLBACK);
if (IpInstance->State == 1) {
if (!IpInstance->ConfigData.UseDefaultAddress ||
*(UINT8 *)((UINT8 *)IpInstance->Interface + 48)) {
/* Check/cancel the token list */
Status = Ip4CancelTokenList(IpInstance, JoinFlag, GroupAddress);
...
} else {
return EFI_NOT_STARTED;
}
} else {
return EFI_NOT_STARTED;
}
gBS->RestoreTpl(Tpl);
return Status;
}
/*==============================================================================
13. IP4_TRANSMIT (0x25DC)
==============================================================================*/
EFI_STATUS
Ip4Transmit(
IN IP4_INSTANCE *IpInstance,
IN EFI_IP4_TRANSMIT_DATA *Token
)
{
UINT64 Tpl;
IP4_HEADER *IpHead;
UINT32 HeadLen;
if (IpInstance == NULL || Token == NULL ||
Token->Data == NULL || Token->OptionList == NULL) {
return EFI_INVALID_PARAMETER;
}
Tpl = gBS->RaiseTpl(TPL_CALLBACK);
if (IpInstance->State == 1) {
if (IpInstance->ConfigData.UseDefaultAddress &&
!*(UINT8 *)((UINT8 *)IpInstance->Interface + 48)) {
return EFI_NOT_STARTED;
}
...
} else {
return EFI_NOT_STARTED;
}
gBS->RestoreTpl(Tpl);
return Status;
}
/*==============================================================================
14. IP4_INPUT (0x36EC / 0x3AF0 / 0x3FA4)
IPv4 packet input processing
================================================================================*/
EFI_STATUS
Ip4Input(
IN IP4_SERVICE *IpSb,
IN IP4_HEADER *IpHead,
IN UINT32 HeadLen,
IN VOID *Packet,
IN UINT32 PacketLen,
IN UINT32 SrcAddr,
IN UINT32 DstAddr
)
{
IP4_INSTANCE *IpInstance;
EFI_STATUS Status;
if (IpHead == NULL) {
ASSERT(IpHead != NULL);
return EFI_INVALID_PARAMETER;
}
/* Check IP version and header length */
if ((IpHead->VersionIhl & 0xF0) != 0x40 ||
(IpHead->VersionIhl & 0x0F) * 4 < 20 ||
(IpHead->VersionIhl & 0x0F) * 4 > HeadLen ||
HeadLen != IpHead->TotalLength) {
NetfreePool(Packet);
return EFI_INVALID_PARAMETER;
}
/* Check header checksum (optional) */
if (IpHead->HeaderChecksum != 0 &&
(UINT16)NetChecksum(IpHead, HeadLen) != 0xFFFF) {
NetFreePool(Packet);
return EFI_INVALID_PARAMETER;
}
/* Check for fragments */
if ((IpHead->FragOffset & 0x3FFF) != 0 ||
((IpHead->FragOffset & 0x2000) != 0) {
/* Fragment */
return Ip4Reassemble(IpSb, Packet, IpHead);
}
/* Pass to all children */
Status = Ip4DeliverToChildren(IpSb, Packet, IpHead, SrcAddr, DstAddr);
return Status;
}
/*==============================================================================
15. IP4_INTERFACE_MANAGEMENT
Source: Ip4If.c
================================================================================*/
VOID *
IP4CreateInterface(
IN VOID *MnpProtocol,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE DriverBindingHandle
)
{
IP4_INTERFACE *Interface;
Interface = (IP4_INTERFACE *)NetAllocatePool(sizeof(IP4_INTERFACE));
if (Interface == NULL) {
return NULL;
}
NetZeroMem(Interface, sizeof(IP4_INTERFACE));
Interface->Signature = IP4_INTERFACE_SIGNATURE;
/* Init links */
NetInitList(&Interface->Link);
Interface->RefCnt = 1;
Interface->Configured = FALSE;
Interface->Mnp = NULL;
Interface->MnpRcv = NULL;
/* Set up MNP configuration */
...
return Interface;
}
EFI_STATUS
Ip4DestroyInterface(
IN VOID *Interface,
IN VOID *Context
)
{
IP4_INTERFACE *IpIf = (IP4_INTERFACE *)Interface;
if (Interface == NULL || IpIf->Signature != IP4_INTERFACE_SIGNATURE) {
ASSERT(...);
}
/* Disconnect all children */
Ip4DisconnectInstance(IpIf, 0);
Ip4CleanupInstance(IpIf, 0, 0);
NetRemoveEntryList(&IpIf->Link);
if (IpIf->Interface) {
NetRemoveEntryList(&IpIf->Interface->Link);
Ip4DestroyInterfaceInstance(IpIf->Interface, IpIf);
IpIf->Interface = NULL;
}
if (IpIf->RouteTable) {
NetFreePool(IpIf->RouteTable);
IpIf->RouteTable = NULL;
}
if (IpIf->RouteCache) {
NetFreePool(IpIf->RouteCache);
IpIf->RouteCache = NULL;
}
/* Free MAC header */
NetFreePool(IpIf->MacHeader);
NetFreePool(IpIf->McHeaderData);
NetFreePool(IpIf);
return EFI_SUCCESS;
}
/*==============================================================================
16. IP4_ROUTE (0x7EDC / 0x7F1C / 0x82FC)
Source: Ip4Route.c
================================================================================*/
EFI_STATUS
Ip4RouteTableAdd(
IN VOID *RtTable,
IN UINT32 DestAddr,
IN UINT32 Netmask,
IN UINT32 NextHop
)
{
IP4_ROUTE_ENTRY *RtEntry;
IP4_ROUTE_ENTRY *NewEntry;
if (RtTable == NULL) {
ASSERT(RtTable != NULL);
return EFI_INVALID_PARAMETER;
}
/* Look for existing */
RtEntry = Ip4RouteTableFind(RtTable, DestAddr, Netmask);
if (RtEntry != NULL) {
/* Update NextHop */
RtEntry->NextHop = NextHop;
return EFI_SUCCESS;
}
/* Create new entry */
NewEntry = (IP4_ROUTE_ENTRY *)NetAllocatePool(sizeof(IP4_ROUTE_ENTRY));
if (NewEntry == NULL) {
return EFI_OUT_OF_RESOURCES;
}
NewEntry->DestAddr = DestAddr;
NewEntry->Netmask = Netmask;
NewEntry->NextHop = NextHop;
NewEntry->RefCnt = 0;
/* Add to hash table */
...
return EFI_SUCCESS;
}
/*==============================================================================
17. IP4_CONFIG2 (0x6788 / 0x6C9C / 0x6F40 / 0x699C / 0x725C / 0x72E8)
Source: Ip4Config2Impl.c
==============================================================================*/
EFI_STATUS
Ip4Config2Init(
IN IP4_SERVICE *IpSb
)
{
IP4_CONFIG2_INSTANCE *Config2;
Config2 = &IpSb->Config2Instance;
/* Register policy notify */
Config2->Registered = FALSE;
Config2->Policy = IpSb->ConfigData.Policy;
/* Read from NV */
...
/* Start DHCP if needed */
if (Config2->Policy == Ip4Config2PolicyDhcp) {
return Ip4Config2StartDhcp(Config2);
}
return EFI_SUCCESS;
}
EFI_STATUS
Ip4Config2SetData(
IN IP4_SERVICE *IpSb,
IN UINT32 DataSize,
IN VOID *Data
)
{
if (IpSb->ConfigData.Policy != 0) {
return EFI_ALREADY_STARTED;
}
if (Data && DataSize) {
return Ip4Config2SetDataToConfig(&IpSb->ConfigData, DataSize, Data);
}
/* Reset config */
NetFreePool(IpSb->ConfigData.InterfaceId);
IpSb->ConfigData.InterfaceId = NULL;
IpSb->ConfigData.Policy = 0;
return EFI_SUCCESS;
}
/*==============================================================================
18. IP4_HELPER_FUNCTIONS
==============================================================================*/
/* NetPool allocate/free */
VOID *
NetAllocatePool(UINTN Size)
{
VOID *Buffer;
gBS->AllocatePool(EfiBootServicesData, Size, &Buffer);
if (Buffer) {
NetZeroMem(Buffer, Size);
}
return Buffer;
}
VOID
NetFreePool(VOID *Buffer)
{
gBS->FreePool(Buffer);
}
/* Mem copy/fill */
VOID
NetCopyMem(VOID *Dest, VOID *Src, UINTN Length)
{
gBS->CopyMem(Dest, Src, Length);
}
VOID
NetZeroMem(VOID *Buffer, UINTN Length)
{
gBS->SetMem(Buffer, 0, Length);
}
/* Linked list */
VOID
NetInitList(LIST_ENTRY *ListHead)
{
ListHead->ForwardLink = ListHead;
ListHead->BackLink = ListHead;
}
BOOLEAN
NetIsListEmpty(LIST_ENTRY *ListHead)
{
return ListHead->ForwardLink == ListHead;
}
VOID
NetInsertTailList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry)
{
Entry->ForwardLink = ListHead;
Entry->BackLink = ListHead->BackLink;
ListHead->BackLink->ForwardLink = Entry;
ListHead->BackLink = Entry;
}
VOID
NetRremoveEntryList(LIST_ENTRY *Entry)
{
Entry->ForwardLink->BackLink = Entry->BackLink;
Entry->BackLink->ForwardLink = Entry->ForwardLink;
}
/* Buffer management helpers */
VOID
NetInitBufferPool(VOID *Buf, UINT32 Len)
{
...
}
/* Net cksum mim */
UINT16
NetChecksum(VOID *Buf, UINT32 Len)
{
UINT32 Sum = 0;
UINT16 *Word = (UINT16 *)Buf;
while (Len > 1) {
Sum += *Word++;
Len -= 2;
}
if (Len) {
Sum += *(UINT8 *)Word;
}
while (Sum >> 16) {
Sum = (Sum & 0xFFFF) + (Sum >> 16);
}
return (UINT16)~Sum;
}
/* ARP-based address resolution */
INT32
Ip4ArpResolve(
IN IP4_INTERFACE *Interface,
IN UINT32 IpAddr
)
{
IP4_ARP_QUE *ArpQue;
IP4_ROUTE_ENTRY *RtEntry;
/* Check if same subnet */
if ((IpAddr & Interface->SubnetMask) ==
(Interface->IpAddr & Interface->SubnetMask)) {
/* Direct deliver, use IP addr */
return IpAddr;
}
/* Look for route */
RtEntry = Ip4RouteFind(Interface->RouteTable, IpAddr, 0);
if (RtEntry) {
return RtEntry->NextHop;
}
/* Use default gatewa */
if (Interface->Gateway) {
return Interface->Gateway;
}
return 0;
}
/* IP4 Assembbly */
EFI_STATUS
Ip4Reassemble(
IN IP4_SERVICE *IpSb,
IN VOID *Packet,
IN IP4_HEADER *IpHead
)
{
...
}
/* ICMP send */
VOID
Ip4IcmpError(
IN IP4_SERVICE *IpSb,
IN IP4_HEADER *IpHead,
IN VOID *Packet,
IN UINT8 IcmpType,
IN UINT8 IcmpCode
)
{
...
}
/* Random seed */
UINT32
NetRandomSeed(VOID)
{
return (UINT32)(&word_14348);
}
/*==============================================================================
ETI_DRI_VER_ENTR_POINT (0x548) - modle entry
================================================================================*/
EFI_STATUS
EFIAPI
EfiMain(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
return DriverEntry(ImageHandle, SystemTable);
}