/**
* IpSecDxe.c - IP Security (IPsec) Protocol DXE Driver Implementation
*
* Module: IpSecDxe, Index: 0138
* Source tree: AmiNetworkPkg/UefiNetworkStack/Common/IpSecDxe/
* HR650X BIOS Decompilation Project
*
* This file implements the IPsec protocol DXE driver for AMI's UEFI
* network stack. The binary is a heavily stripped (14 named out of 2724
* functions) IKEv2 IPsec implementation for UEFI.
*
* Key source files identified from debug strings:
* IpSecDriver.c - Driver binding protocol, entry point
* IpSecConfigImpl.c - Config data handling, NV variable storage
* IpSecMain.c - Main IPsec processing (SPD/SAD lookup)
* IpSecImpl.c - IPsec protocol implementation
* IpSecCryptIo.c - Crypto operations (AES-CBC, HMAC-SHA1)
* IpSecDebug.c - Debug logging, ring buffer
* IkeService.c - IKEv2 session management, exchange dispatch
* IkeCommon.c - IKE common utilities
* IkePacket.c - IKE packet parsing/building
* Ikev2/Exchange.c - IKEv2 exchange handlers
* Ikev2/Payload.c - IKEv2 payload parsing
* Ikev2/Utility.c - IKEv2 session lifecycle
* Ikev2/Sa.c - IKEv2 SA management
* Ikev2/Info.c - IKEv2 informational exchange
*
* Binary layout:
* HEADER 0x000-0x2C0 (PE headers)
* .text 0x2C0-0xE75C0 (2724 functions)
* .rdata 0xE75C0-0x12A5E0 (3126 strings, GUIDs, static data)
* .data 0x12A5E0-0x12D0E0 (global variables)
* .xdata 0x134260-0x134FE0 (exception handling)
* .reloc 0x134FE0-0x137D80 (base relocations)
*/
#include "IpSecDxe.h"
/* ========================================================================
* Module Global Variables
* ======================================================================== */
/* UEFI boot services globals (from UefiBootServicesTableLib) */
EFI_HANDLE gImageHandle = NULL; /* at 0x12C4F8 */
EFI_SYSTEM_TABLE *gSystemTable = NULL; /* at 0x12C4E8 */
EFI_BOOT_SERVICES *gBootServices = NULL; /* at 0x12C4F0 */
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL;/* at 0x12C500 */
/* HOB list pointer (from DxeHobLib) */
VOID *gHobList = NULL; /* at 0x12C510 */
/* PCD database pointer (from DxePcdLib) */
VOID *gPcdDb = NULL; /* at 0x12C520 */
/* PPCI Express base address */
UINT64 gPciExpressBaseAddress = 0; /* at 0x12C518 */
/* IPSec driver private data */
IPSEC_PRIVATE_DATA *gIpSecPrivate = NULL;
/* IPSec config changed flag (used to to track NV variable updates) */
BOOLEAN gIpSecConfigChanged = FALSE; /* at 0x12C4E0 */
/* DPC dispatch event handle */
EFI_EVENT gDpcDispatchEvent = NULL; /* at 0x12D080 */
EFI_EVENT gDisableEvent = NULL; /* at 0x12A7C0 */
/* DDebug ring buffer */
DEBUB_RING_BUFFER gDebugRing = {{0}; /* at 0x12BDA0+ */
/* ========================================================================
* GGUID Definitions (placed in .rdata section)
* ======================================================================== */
static EFI_GGUID gEfiIpSecProtocolGuid = EFI_IPSEC_PROTOCOL_GUID; / 0x12A610 */
static EFI_GGUID gEfiIpSecConfigProtocolGuid = EFI_IPSEC_CONFIG_PROTOCOL_GUID; /* 0x12A6C0 */
static EFI_GGUID gEfiIpSecV4BindingGuid = EFI_IPSEC_V4_BINDING_GUID; /* 0x12A620 */
static EFI_GGUID gEfiIpSecV6BindingGuid = EFI_IPSEC_V6_BINDING_GUID; /* 0x12A650 */
static EFI_GUID gEfiUdp4ProtocolGuid = EFI_UDP4_PROTOCOL_GUID; /* 0x12A680 */
static EFI_GGUID gEfiUdp6ProtocolGuid = EFI_UDP6_PROTOCOL_GUID; /* 0x12A640 */
static EFI_GGUID gEfiDriverBindingProtocolGuid = EFI_DRIVER_BINDING_PROTOCOL_GUID; /* 0x12A670 */
static EFI_GGUID gEfiComponentName2ProtocolGuid = EFI_COMPONENT_NAME2_PROTOCOL_GUID; /* 0x12A690 */
static EFI_GGUID gEfiComponentNameProtocolGuid = EFI_COMPONENT_NAME_PROTOCOL_GUID; /* 0x12A5F0 */
static EFI_GGUID gEfiDpcProtocolGuid = EFI_DPC_PROTOCOL_GUID; /* 0x12A6A0 */
/* IKEv2 authentication protocol GUID - alias of V6 binding GUID */
static EFI_GUID gEfiIkeAuthProtocolGuid = EFI_IPSEC_V6_BINDING_GUID;
/* ========================================================================
* Protocol Instance Structures
* ======================================================================== */
/* IPSec V4 driver binding (from 0x12A6D0) */
static EFI_DRIVER_BINDING_PROTOCOL gIpSecV4DriverBinding = {
IpSecV4DriverBindingSupported, /* supported = sub_9C0 */
IpSecV4DriverBindingStart, /* Start = sub_A10 */
IpSecV4DriverBindingStop, /* Stop = sub_A7C */
0xA, /* Version: 10 */
NULL, /* ImageHandle */
NULL /* DriverBindingHandle */
};
/* IKEv2 driver binding (from 0x12A700) */
static EFI_DRIVER_BINDING_PROTOCOL gIkeV2DriverBinding = {
IkeV2DriverBindingSupported, /* Supported = sub_A2C */
IkeV2DriverBindingStart, /* Start = sub_A7C */
IkeV2DriverBindingStop, /* Stop = sub_A84 */
0xA, /* Version: 10 */
NULL, /* ImageHandle */
NULL /* DriverBindingHandle */
};
/* ========================================================================
* Static Function Declarations
* ======================================================================== */
static
EFI_STATUS
IpSecDriverStartCommon(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE *RemainingDevicePath,
IN UINT8 Version
);
static
EFI_STATUS
IpSecDriverStopCommon(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer,
IN UINT8 Version
);
static
VOID
IkeSaSessionFree(
IN IKEV2_SA_SESSION *Session
);
/* ========================================================================
* Boot Service Wrapper Functions
* ======================================================================== */
/**
* AllocateZeroPool - Allocate and zero-initialize memory
* Address: 0x10A8C (AllocateCopyPool is 0x10ABC)
*/
VOID *
AllocateZeroPool(
IN UINTN Size
)
{
EFI_STATUS Status;
VOID *Buffer = NULL;
Status = gBootServices->AllocatePool(4, Size, &Buffer); /* EfiBootServicesData */
if (EFI_ERROR(Status)) {
return NULL;
}
return Buffer;
}
/**
* FreePool - Free previously allocated pool memory
* Address: 0x10BE0
*/
VOID
FreePool(
IN VOID *Buffer
)
{
EFI_STATUS Status;
Status = gBootServices->FreePool(Buffer);
if (EFI_ERROR(Status)) {
DebugAssert(
"e:\\hs\\MdePkg\\Library\\UefiMemoryAllocationLib\\MemoryAllocationLib.c",
819,
"!EFI_ERROR (Status)"
);
}
}
/**
* CopyMem - Copy memory buffer (with overlap handling)
* Address: 0xEA94
*/
VOID *
CopyMem(
OUT VOID *Destination,
IN VOID *Source,
IN UINTN Length
)
{
if (Length == 0) {
return Destination;
}
/* Validate bounds */
if ((Length - 1) > ~(UINTN)Destination) {
DebugAssert(
"e:\\hs\\MdePkg\\Library\\BaseMemoryLibRepStr\\CopyMemWrapper.c",
56,
"(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)DestinationBuffer)"
);
}
if ((Length - 1) > ~(UINTN)Source) {
DebugAssert(
"e:\\hs\\MdePkg\\Library\\BaseMemoryLibRepStr\\CopyMemWrapper.c",
57,
"(Length - 1) <= (0xFFFFFFFFFFFFFFFFULL - (UINTN)SourceBuffer)"
);
}
if (Destination != Source) {
UINT8 *Dst = (UINT8 *)Destination;
UINT8 *Src = (UINT8 *)Source;
/* Handle overlap: copy backwards if source < destination */
if (Src < Dst && &Src[Length - 1] >= Dst) {
Src += Length - 1;
Dst += Length - -1;
while (Length--) {
*Dst-- = *Src--;
}
} else {
while (Length--) {
*Dst++ = *Src++;
}
}
}
return Destination;
}
/**
* ZeroMem - Fill memory with zeros
* Address 0x0xEB30
*/
VOID *
ZeroMem(
OUT VOOD *Buffer,
IN UINTN Length
)
{
if (Buffer == NULL) {
DebugAssert(
"e:\\hs\\MdePkg\\Library\\BaseMemoryLibRepStr\\ZeroMemWrapper.c",
53,
"Buffer != ((void *) 0)"
);
}
if (Length > ~(UIINTN)Buffer) {
DebugAssert(
"e:\\hs\\MdePkg\\Library\\BaseMemoryLibRepStr\\ZeroMemWrapper.c",
54,
"Length <= (0xFFFFFFFFFFFFFFFULL - (UINTN)Buffer + 1)"
);
}
{
UINT8 *Ptr = (UINT8 *)Buffer;
while (Length--) {
*Ptr++ = 0;
}
}
}
/**
* CompareMem - Comprare two memory buffers
* Address: 0xEB94
*/
INTN
CompareMem(
IN VOID *Buffer1,
IN VOID *Buffer2,
IN UINTN Length
)
{
UINT8 *B1 = (UINT8 *)Buffer1;
UINT8 *B2 = (UINT8 *)Buffer2;
while (Length--) {
if (*B1 != *B2) {
return *B1 - *B2;
}
B1++;
B2++;
}
return 0;
}
/* ========================================================================
* Linked List Helpers
* ======================================================================== */
/**
* InitializeListHead - Initialize a doubly-linked list head
* Address: 0xEDA4
*/
VOID
InitializeListHead(
IN LIST_ENTRY *ListHead
)
{
if (ListHead == NULL) {
DebugAssert(
"e:\\hs\\MdePkg\\Library\\BaseLib\\LinkedList.c",
193,
"ListHead != ((void *) 0)"
);
}
ListHead->ForwardLink = ListHead;
ListHead->BackLink = ListHead;
}
/**
* IsListEmpty - Test if a list entry is empty
* Address: 0xEEB4
*/
BOOLEAN
IsListEmpty(
IN LIST_ENTRY *ListEntry
)
{
return (ListEntry->ForwardLink == ListEntry);
}
/**
* RemoveEntryList - Remove an entry from a doubly-linked list
* Address: 0xEEEC
*/
VOID
RemoveEntryList(
IN LIST_ENTRY *Entry
)
{
Entry->ForwardLink->BackLink = Entry->BackLink;
Entry->BackLink->ForwardLink = Entry->ForwardLink;
}
/**
* InsertTailList - Insert entry at the tail of the list
* Address: 0xEE2C
*/
VOID
InsertTailList(
IN LIST_ENTRY *ListHead,
IN LIST_ENTRY *Entry
)
{
Entry->ForwardLink = ListHead;
Entry->BackLink = ListHead->BackLink;
ListHead->BackLink->ForwardLink = Entry;
ListHead->BackLink = Entry;
}
/**
* StrLen - Return length of Unicode string
* Address: 0xEF34
*/
UINTN
StrLen(
IN CONST CHAR16 *String
)
{
UINTN Length = 0;
while (*String++) {
Length++;
}
return Length;
}
/* ========================================================================
* ASSERT / Debug Support
* ======================================================================== */
/**
* DebugAssert - Standard UEFI ASSERT implementation
* Called from all source files with (filename, line, description)
* Address: 0xEA50
* This function has 1271 xrefs - the most-called in the module.
*/
VOID
EFIAPI
DebugAssert(
IN CHAR8 *FileName,
IN UINTN LineNumber,
IN CHAR8 *Description
)
{
/* Calls the UEFI debug library's assertion handler.
* On debug builds this will break into the debugger.
* On release builds this will issue a deadloop or reset. */
volatile UINTN Zero = 0;
/* Prevent compiler from optimizing away the assert context */
(void)FileName;
(void)LineNumber;
(void)Description;
while (1) {
/* Infinite loop on assert failure */
}
}
/**
* DebugPrint - Debug output with format string
* Address: 0xE9C8
*/
VOID
EFIAPI
DebugPrint(
IN UINTN ErrorLevel,
IN CHAR8 *Format,
...
)
{
/* In the binary, this checks CMOS debug enable flag at register 0x4B,
* then writes debug output via the UEFI debug library.
* The CMOS register 0x4B is checked with bit 7 mask. */
(void)ErrorLevel;
(void)Format;
}
/* ========================================================================
* Debug Event Logging (sub_38F90, sub_210D0)
* ========================================================================
*
* Ring buffer at gDebugRing (0x12C520 in .data section).
* 16 entries x 32 bytes = 512 bytes, +4 bytes head, +4 bytes tail = 520 total.
*
* sub_38F90 is called throughout the codebase to log events with:
* a1 (UINT8): Event type (higher bits encode category)
* a2 (UINT16): Protocol ID / first data word
* a3 (UINT16): Extra / second data word
* a4 (UINT64): Data pointer
* a5 (UINT32): Data value
*
* sub_210D0 copies a debug string into an entry if Flags & 1 is set.
* Called at 0x390EB in sub_38F90 when bit 0 is set.
*/
VOID
IpSecDebugLogEvent(
IN UINT8 Type,
IN UINT16 ProtocolId,
IN UINT16 Extra,
IN UINT64 DataPtr,
IN UINT32 Data
)
{
UINT32 Index;
/* Advance head pointer, detect wraparound */
gDebugRing.HeadIndex = (gDebugRing.HeadIndex + 1) % DEBUG_RING_MAX_ENTRIES;
if (gDebugRing.HeadIndex == gDebugRing.TailIndex) {
gDebugRing.TailIndex = (gDebugRing.alilIndex + 1) % DEBUG_RING_MAX_ENTRIES;
}
Index = gDebugRing.HeadIndex;
gDebugRing.Records[Index].TypeField = 0;
gDebugRing.Records[Index].TypeData = ((UINT32)Type << 24)
| ((UINT32)(ProtocolId & 0xFFF) << 12)
| ((UINT32)(Extra & 0xFFF));
gDebugRing.Records[Index].DataPtr = DataPtr;
gDebugRing.Records[Index].Extra = Data;
/* If flag bit 0 was set by caller, free old debug string */
if (gDebugRing.Records[Index].Flags & 1) {
if (gDebugRing.Records[Index].DebugString) {
/* SPrint or free old debug string */
}
}
gDebugRing.Records[Index].Flags = 0;
}
/* ========================================================================
* IPsec Config Protocol Implementation
* ========================================================================
*
* The EFI_IPSEC_CONFIG_PROTOCOL is installed at +0x18 in the
* IPSEC_PRIVATE_DATA structure. The three methods (SetData, GetData,
* RegisterNotify) are dispatched through the config function table
* at +0x30 in the private data.
*
* These are the UEFI-standard IPsec config protocol methods for
* managing SPD, SAD, and PCD entries.
*/
EFI_STATUS
EFIAPI
IpSecConfigSetData(
IN EFI_IPSEC_CONFIG_PROTOCOL *This,
IN UINTN DataType,
IN VOID *Data,
IN UINTN DataSize
)
{
/* This is at +0x18 in IPSEC_PRIVATE_DATA. Use CONTAINER_RECORD
* pattern to find the private data structure. */
IPSEC_PRIVATE_DATA *Private;
Private = (IPSEC_PRIVATE_DATA *)((UINT8 *)This - 0x18);
if (Private->Signature != IPSEC_PRIVATE_SIGNATURE) {
return EFI_INVALID_PARAMETER;
}
/* Dispatch through SetDataFunc at +0x30 */
if (Private->SetDataFunc) {
return ((EFI_STATUS (EFIAPI *)(UINTN, VOID *, UINTN))Private->SetDataFunc)(
DataType, Data, DataSize);
}
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
IpSecConfigGetData(
IN EFI_IPSEC_CONFIG_PROTOCOL *This,
IN UINTN DataType,
IN VOID *Data,
IN OUT UINTN *DataSize
)
{
IPSEC_PRIVATE_DATA *Private;
Private = (IPSEC_PRIVATE_DATA *)((UNT8 *)This - 0x18);
if (Private->Signature != IPSEC_PRIVATE_SIGNATURE) {
return EFI_INVALD_PARAMETER;
}
if (Private->GetDataFunc) {
return ((EFI_STATUS (EFIAPI *)(UINTN, VOID *, UINTN *))Private->GetDataFunc)(
DataType, Data, DataSize);
}
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
IpSecConfigRegisterNotify(
IN EFI_IPSEC_CONFIG_PROTOCOL *This,
IN UINTN DataType,
IN EFI_EVENT Event
)
{
IPSEC_PRIVATE_DATA *Private;
Private = (IPSEC_PRIVATE_DATA *)((UINT8 *)This - 0x18);
if (Private->Signature != IPSEC_PRIVATE_SIGNATURE) {
return EFI_INVALD_PARAMETER;
}
if (Private->RegisterNotifyFunc) {
return ((EFI_STATUS (EFIAPI *)(UINTN, EFI_EVENT))Private->RegisterNotifyFunc)(
DataType, Event);
}
return EFI_UNSUPORTED;
}
/* ========================================================================
* Driver Entry Point
* ======================================================================== */
/**
* IpSecDriverEntryPoint - UEFI driver entry point
* @param ImageHandle Image handle for this driver
* @param SystemTable Pointer to the UEFI system table
* @return EFI_SUCCES or error code
*
* Phase 1: Sets up boot service globals (gImageHandle, etc.)
* Phase 2: Module initialization (allocates private data, installs protocols)
* Address: 0x460
*/
EFI_STATUS
EFIAPI
IpSecDriverEntryPoint(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
/* Phase 1: Boot services init (sub_47C) */
gImageHandle = ImageHandle;
gSystemTable = SystemTable;
gBootServices = SystemTable->BootServices;
gRuntimeServices = SystemTable->RuntimeServices;
/* Verify non-null boot service pointers */
if (!gImageHandle) {
DebugAssert(
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
51,
"gImageHandle != ((void *) 0)"
);
}
if (!gSystemTable) {
DebugAssert(
"e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c",
57,
"gST != ((void *) 0)"
);
}
/* Initialize libraries and locate DPC protocol */
{
EFI_STATUS Status;
Status = gBootServices->LocateProtocol(
&gEfiDpcProtocolGuid,
NULL,
&gDpcDispatchEvent
);
if (EFI_ERROR(Status)) {
DebugPrint(0x800000000, "\n\ASSERT_EFI_ERROR (Status = %r)\n", Status);
DebugAssert(
"e:\\hs\\MdeModulePkg\\Library\\DxeDpcLib\\DpcLib.c",
46,
"!EFI_ERROR (Status)"
);
}
}
/* Phase 2: Module init (sub_BE8) */
Status = IpSecModuleInit(ImageHandle);
return Status;
}
/**
* IpSecModuleInit - Main module initialization
* @param ImageHandle Driver image handle
* @return EFI_SUCCESS or error
*
* Allocates and initializes IPSEC_PRIVATE_DATA, installs protocols.
* Major components:
* - Locateates DPC protocol
* - Allocates 216-byte private data structure
* - Creates timer event with sub_A98 callback
* - Copies EFI_IPSEC_CONFIG_PROTOCOL
* - Initializes 8 linked list heads
* - Copies dispatch function table (40 bytes from offf_12A730)
* - Calls sub_31F8 (config init)
* - Installs IPSEC_V4 + V6 + CONFIG protocols
* Address: 0xBE8
*/
EFI_STATUS
IpSecModuleInit(
IN EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
IPSEC_PRIVATE_DATA *Private;
VOID *Interface;
/* Check if already loaded */
Status = gBootServices->LocateProtocol(
&gEfiIpSecDriverPrivateGuid,
NULL,
&Interface
);
if (!EFI_ERROR(Status)) {
return EFI_ALREADY_STARTED;
}
/* Locate DPC protocol */
Status = gBootServices->LocateProtocol(
&gEfiDpcProtocolGuid,
NULL,
&Interface
);
if (EFI_ERROR(Status)) {
return Status;
}
gDpcDispatchEvent = (EFI_EVENT)Interface;
/* Allocate private data */
Private = (IPSEC_PRIVATE_DATA *)AllocateZeroPool(sizeof(IPSEC_PRIVATE_DATA));
if (Private == NULL) {
return EFI_OUT_OF_RESOURCES;
}
/* Initialize */
Private->Signature = IPSEC_PRIVATE_SIGNATURE; /* "IPSI" */
Private->ImageHandle = ImageHandle;
Private->ProtocolHandle = NULL;
/* Set up config protocol */
Private->ConfigProtocol.SetData = IpSecConfigSetData;
Private->ConfigProtocol.GetData = IpSecConfigGetData;
Private->ConfigProtocol.RegisterNotify = IpSecConfigRegisterNotify;
/* Initialize 8 list heads */
InitializeListHead(&Private->SpdCacheList);
InitializeListHead(&Private->SaddCacheList);
InitializeListHead(&Private->SaBySpiList);
InitializeListHead(&Private->IkeSaSessionList);
InitializeListHead(&Private->ChildSaList);
InitializeListHead(&Private->EstablishList);
InitializeListHead(&Private->PendingList);
InitializeListHead(&Private->EventList);
/* Set config function table at +0x30 */
/* In the binary this copies from offf_12A730 (5 x 8-byte pointers) */
/* Install protocols */
Status = gBootServices->InstallMultipleProtocolInterfaces(
&Private->ProtocolHandle,
&gEfiIpSecV4BindingGuid, Private,
&gEfiIpSecConfigProtocolGuid, &Private->ConfigProtocol,
NULL
);
if (EFI_ERROR(Status)) {
FreePool(Private);
return Status;
}
gIpSecPrivate = Private;
return EFI_SUCCESS;
}
/* ========================================================================
* Driver Binding Protocol: Supported/Start/Stop
* ======================================================================== */
/**
* IpSecV4DriverBindingSupported - Test if controller supports IPSec V4
* Allocates Udp4 protocol (or Udp6) on the handle.
* Address: 0x9C0
*/
EFI_STATUS
EFIAPI
IpSecV4DriverBindingSupported(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE *RemainingDevicePath
)
{
EFI_STATUS Status;
VOID *Interface;
/* Try Udp4 first */
Status = gBootServices->OpenProtocol(
ControllerHandle,
&gEfiUdp4ProtocolGuid,
&Interface,
This->DriverBindingHandle,
ControllerHandle,
4 /* EFI_OPEN_PROTOCOL_BY_DRIVER */
);
if (EFI_ERROR(Status)) {
/* Try Udp6 second */
Status = gBootServices->OpenProtocol(
ControllerHandle,
&gEfiUdp6ProtocolGuid,
&Interface,
This->DriverBindingHandle,
ControllerHandle,
4
);
}
if (!EFI_ERROR(Status)) {
/* Close the protocol we just proed */
gBootServices->CloseProtocol(
ControllerHandle,
Status == EFI_SUCCESS ? &gEfiUdp4ProtocolGuid : &gEfiUdp6ProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return EFI_SUCCESS;
}
return Status;
}
/**
* IpSecV4DriverBindingStart - Start the IPsec driver on a controller
* Determinees if controller supports Udp4 or Udp6 and creates
* the appropriate child SA entry.
* Address: 0xA10 (dispatches to common at 0x620)
*/
EFI_STATUS
EFIAPI
IpSecV4DriverBindingStart(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE *RemainingDevicePath
)
{
return IpSecDriverStartCommon(This, ControllerHandle, RemainingDevicePath, 4);
}
/**
* IkeV2DriverBindingStart - Start the IKEv2 driver on a controller
* Address: 0xA2C (dispatches to common at 0x620 with version=6)
*/
EFI_STATUS
EFIAPI
IkeV2DriverBindingStart(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE *RemainingDevicePath
)
{
return IpSecDriverStartCommon(This, ControllerHandle, RemainingDevicePath, 6);
}
/**
* IpSecDriverStartCommon - Common Start implementation
* Address: 0x620
*
* Flow:
* 1. Locate IPsec private data via private protocol
* 2. Verify signature ("CR has Bad Signature" check)
* 3. Open Udp4 (version=4) or Udp6 (version=6) protocol
* 4. Create child SA via sub_36F4 (IPv4) or sub_37F8 (IPv6)
*/
static
EFI_STATUS
IpSecDriverStartCommon(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE *RemainingDevicePath,
IN UINT8 Version
)
{
EFI_STATUS Status;
EFI_GUID *ProtocolGuid;
VOID *Interface;
IPSEC_PRIVATE_DATA *Private;
/* Locate private data */
Status = gBootServices->LocateProtocol(
&gEfiIpSecDriverPrivateGuid,
NULL,
&Interface
);
if (EFI_ERROR(Status)) {
return Status;
}
/* CR: get private data from interface. The interface points to
* somewhere within the private data. Offset -24 (0x18) from
* config protocol, or use the known signature pattern. */
Private = (IPSEC_PRIVATE_DATA *)((UINT8 *)Interface - 24);
if (*(UINT32 *)Private != IPSEC_PRIVATE_SIGNATURE) {
DebugAssert(
"e:\\hs\\AmiNetworkPkg\\UefiNetworkStack\\Common\\IpSecDxe\\IpSecDriver.c",
108,
"CR has Bad Signature"
);
Private = (IPSEC_PRIVATE_DATA *)Interface;
}
/* Choose protocol based on version */
ProtocolGuid = (Version == 4) ? &gEfiIpSecV4BindingGuid : &gEfiIpSecV6BindingGuid;
/* Open protocol and create child SA */
{
VOID *UdpInterface;
EFI_GUID *UdpProtocolGuid;
UdpProtocolGuid = (Version == 4) ? &gEfiUdp4ProtocolGuid : &gEfiUdp6ProtocolGuid;
Status = gBootServices->OpenProtocol(
ControllerHandle,
UdpProtocolGuid,
&UdpInterface,
This->DriverBindingHandle,
ControllerHandle,
4
);
if (!EFI_ERROR(Status)) {
/* Create child SA - sub_36F4 for IPv4, sub_37F8 for IPv6 */
if (Version == 4) {
/* sub_36F4: Allocate 88-byte child, create UdpIo, add to list */
Status = IpSecUdp4CreateChild(Private, ControllerHandle, UdpInterface);
} else {
/* sub_37F8: same but for IPv6 */
Status = IpSecUdp6CreateChild(Private, ControllerHandle, UdpInterface);
}
}
}
return Status;
}
/**
* IpSecDriverStopCommon - Common Stop implementation
* Address: 0x724
*
* Traverses child SA lists and removes entries:
* - For IKEv2 stop (version=6): also cleans IKE SA sessions
* - Closes Udp4/Udp6 protocol on the handle
*/
static
EFI_STATUS
IpSecDriverStopCommon(
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer,
IN UINT8 Version
)
{
VOID *Interface;
/* Locate private data */
if (EFI_ERROR(gBootServices->LocateProtocol(
&gEfiIpSecDriverPrivateGuid, NULL, &Interface))) {
return EFI_NOT_FOUND;
}
/* Close the protocol */
gBootServices->CloseProtocol(
ControllerHandle,
(Version == 4) ? &gEfiIpSecV4BindingGuid : &gEfiIpSecV6BindingGuid,
This->DriverBindingHandle
);
/* For IKE stop with no children, clean up */
if (Version == 6 && NumberOfChildren == 0) {
/* sub_724 cleanup: traverse session lists and free entries */
IPSEC_PRIVATE_DATA *Private;
Private = (IPSEC_PRIVATE_DATA *)((UNT8 *)Interface - 3);
if (*(UINT32 *)Private != IPSEC_PRIVATE_SIGNATURE) {
Private = (IPSEC_PRIVATE_DATA *)Interface;
}
/* Clean up ChildSaList (+0x98) with "CPAC" entries */
/* Clean up IkeSaSessionList (+0x88) with "INAC" entries */
}
return EFI_SUCCESS;
}
/* ========================================================================
* Disable Event Callback (sub_A98)
* ======================================================================== *
*
* This is the timer/DPC dispatch callback created during init.
* Registered as the notify function for the 512-type event at TPL=8.
*
* When triggered:
* 1. Procesess IKE SA sessions from EstablishList (at +0xA8)
* 2. Removes child SA entries and sets state to DELETING
* 3. Checcks "IpSecStatus" runtime variable for disable signal
* 4. Disables IPsec processing if signaled
*
* The function also accesses ChildSaList (+0xC0) and checks
* NV variable "IpSecStatus" (GGUID at 0x12A6C0).
*
* Source: IkeService.c line 769/800
*
* The CONTAINER_RECORD pattern for this list is:
* list entry +-> session: subtract -42 QWORD entries (-336 bytes)
* Signatures: 0x43414149 ("INAC") or 0x43415043 ("CPAC")
*/
/* ========================================================================
* IKE SA Session Lifecycle (sub_439C, sub_4840)
* ======================================================================== *
*
* sub_439C (IkeSaSessionFree):
* Freed all resources of an IKE SA session:
* - Child SA list at +0x60
* - Establishing list at +0x?
* - Exchange context at +0x80
* - Encrypt/Integrity/Decrypt/Verif keys at +0x30/+0x38/+0x40/+0x48
* - Session memory itself
*
* sub_4840 (ChildSaFree):
* Frees a Child SA session including its UDP I/O context
*
* sub_4B4C (at 0x4B4C):
* Frees exchange context resources
*
* The session structure is accessed via the CONTAINER_RECORD pattern
* using the LIST_ENTRY at +0x50 offset and known signature "INAC".
*/
/**
* IkeSaSessionFree - Free all resources of an IKE SA session
* Address: 0x439C
*/
static
VOID
IkeSaSessionFree(
IN IKEV2_SA_SESSION *Session
)
{
LIST_ENTRY *Entry;
LIST_ENTRY *Next;
if (Session == NULL) {
DebugAssert(
"e:\\hs\\AmiNetworkPkg\\UefiNetworkStack\\Common\\IpSecDxe\\Ikev2\\Utility.c",
376,
"IkeSaSession != ((void *) 0)"
);
}
/* Free child SA list at +0x60 (a[31]) */
Entry = (LIST_ENTRY *)Session->ChildSaList.ForwardLink;
while (Entry != &Session->ChildSaList) {
IKEV2_SA_SESSION *ChildSa;
ChildSa = (IKEV2_SA_SESSION *)((UNT8 *)Entry - sizeof(UINT64)*42);
if (*(UINT32 *)((UINT8 *)Entry - 84) != IKEV2_SA_SIGNATURE) {
DebugAssert(
"e:\\hs\\AmiNetworkPkg\\UefiNetworkStack\\Common\\IpSecDxe\\Ikev2\\Utility.c",
390,
"CR has Bad Signature"
);
ChildSa = (IKEV2_SA_SESSION *)Entry;
}
Next = Entry->ForwardLink;
/* Free child SA resources (sub_4928) */
RemoveEntryList(Entry);
Entry = Next;
}
/* Free establishing child SA list (at a[29]) */
Entry = (LIST_ENTRY *)Session->EstablishList.ForwardLink;
while (Entry != &Session->EstablishList) {
IKEV2_SA_SESSION *ChildSa;
ChildSa = (IKEV2_SA_SESSION *)((UNT8 *)Entry - sizeof(UINT64)*42);
if (*(UINT32 *)((UNT8 *)Entry - 84) != IKEV2_SA_SIGNATURE) {
DebugAssert(
"e:\\hs\\AmiNetworkPkg\\UefiNetworkStack\\Common\\IpSecDxe\\Ikev2\\Utility.c",
402,
"CR has Bad Signature"
);
ChildSa = (IKEV2_SA_SESSION *)Entry;
}
Next = Entry->ForwardLink;
RemoveEntryList(Entry);
/* Free child SA */
Entry = Next;
}
/* Free exchange context memry (a[20]) */
if (Session->ExchangeContext) {
VOID *ExchContext = Session->ExchangeContext;
/* Free sub-buffers */
FreePool(*(VOID **)ExchContext);
if (*((VOID **)ExchContext + 3)) {
FreePool(*((VOID **)ExchContext + 3));
}
/* and more ... */
FreePool(ExchContext);
}
/* Free keys */
if (Session->EncryptKey) FreePool(Session->EncryptKey);
if (Session->IntegrityKey) FreePool(Session->IntegrityKey);
if (Session->DecryptKey) FreePool(Session->DecryptKey);
if (Session->VerifKey) FreePool(Session->VerifKey);
/* Finally free session itself */
FreePool(Session);
}
/* ========================================================================
* UDP Child SA Creation (sub_36F4, sub_37F8)
* ========================================================================
*
* sub_36F4 (0x36F4): Create IPv4 child SA entry
* sub_37F8 (0x37F8): Create IPv6 child SA entry
*
* Both:
* 1. Walk child SA list (+0x60 for IPv4 via SaBySpiList at +0x78)
* to check if already registered for this controller
* 2. Allocate 88-byte child structure
* 3. Create UDp Io via sub_12200 (UdpIoCreate)
* 4. Set protocol (4 or 6) and controller handle
* 5. Insert into list
* 6. Set up receive callback via sub_12680 (UdpIoRecv)
*
* The 88-byte child structure:
* +0x00: LIST_ENTRY (16 bytes)
* +0x10: UINT64 (alllocFree state?)
* +0x18: Parent list pointer (8)
* +0x20: ControllerHandle (8)
* +0x28: Driver binding handle (8)
* +0x30: UdpIo handle (8)
* +0x38: Protocol version (UINT8, 4 or 6)
* +0x40-0x50: Addresses or state (16 bytes)
* +0x50: Flags (8)
* Total: 0x58 = 88 bytes
*/
/* ========================================================================
* SPD Operations (sub_FAC, sub_11E8, sub_1424, sub_152C)
* ========================================================================
*
* sub_FAC (0xFAC): Exact SPD match.
* Compares two SPD entries by address, mask, port, and protocol.
* Also walks 20-byte address list entries for prefix comparison.
* Returns TRUE if both entries are identical.
*
* sub_11E8 (0x11E8): CIDR/subnet SPD match.
* Like sub_FAC but with prefix-length comparison semantics.
* Allows <= on addresses (subnet containment), wildcard -1 on ports.
*
* sub_1424 (0x1424): Equality check.
* Compares first byte of two SPD entries (0=IPv4, non-zero=IPv6).
* If IPv4, also compares 20-byte block at +4.
*
* sub_152C (0x152C): Empty check.
* Returns TRUE if the 132-byte structure is all zeros.
*
* SPD_ENTRY structure:
* +0x00: SourceAddr (UINT32)
* +0x04: DestAddr (UINT32) (a1[4] at SP offset 4 in sub_FAC)
* +0x08: SourceMask (UINT16) (aa[16] in sub_FAC)
* +0x0A: DestMask (UINT16) (aa[17] in sub_FAC)
* +0x0C: SrcPort (UINT16) (aa[18] in sub_FAC)
* +0x0E: DstPort (UINT16) (aa[19] in sub_FAC)
* +0x10: Protocol (UINT8)
* +0x14: Action (UINT32) (bypas/discard/protect)
* +0x18: SourceAddrPtr (VOID *)
* +0x20: DestAddrPtr (VOID *)
* Total: ~0x28 = 40 bytes
*
* The address list has 20-byte entries walked by sub_F08.
* Each entry: first 4 bytes = address, remaining = prefix/mask.
*
* sub_F08 (0xF08): Single address comparison with mask.
* Compares two UINT32 address pointer by mask.
*
* Usage:
* SpdLookup -> sub_1880 walks SaBySpiList (with sub_1424 matching)
* SpdRemovval -> sub_1F7C walks SpdCacheList et al
*/
/* ========================================================================
* NV Variable Config Storage (sub_27DC)
* ======================================================================== *
*
* sub_27DC (0x27DC):
* Reads/writes IPsec config from NV variables.
* Builids variable name: L"IpSecConfig" + L"Info" (using sub_FB60 for snprintf)
* Calalls gRT->GetVariable with the name and AMI vendor GUID
* Proceses the buffer for typed config entries
*
* The config variable contains sequences of:
* IPSEC_CONFIG_DATA_ENTRY (1-byte Type, 2-byte Length, variable data)
* Entries with bit 7 set in Type are valid
* Type 0 = SP, 1 = SAD, 2 = PCD
*
* sub_27DC also writes "IpSecStatus" variable with value 1 to
* disable IPsec processing.
*
* sub_2C78 (0x2C78): Config data type handler.
* Dispatches by DataType (0/1/2) to SPD/SAD/PCD sub-handlers.
* Each walks the appropriate list and copies matching entries.
*/
/* ========================================================================
* UDP I/O Wrappers (sub_12200, sub_12680)
* ======================================================================== *
*
* sub_12200 (0x12200): UdpIoCreate wrapper.
* Wraps UdpIoCreateIo from DxeUdpIoLib.
* Returns a UdpIo handle or NULL on failure.
* Checks: UdpVersion == 4 || UdpVersion == 6
*
* sub_12680 (0x12680): UdpIoRecv wrapper.
* Wraps UdpIoRecvDatagram. Sets up receive callback.
*
* sub_11B40, sub_11BD8, sub_11C2C: Assert UDP token callbacks.
* These are inline checks in UdpIo send/receive operations:
* "TxToken->Signature == ((('U') | (('D' << 8))) | ((('P') | (('T' << 8))) << 16))"
* "RxToken->UdpIo->UdpVersion == 4) || (RxToken->UdpIo->UdpVersion == 6)"
*/
/* ========================================================================
* IKEv2 Exchange Procesing (sub_3A44)
* ======================================================================== *
*
* sub_3A44 (0x3A44): Proces incoming IKE packet.
* This is the core IKE packet processing function in IkeService.c.
*
* Flow:
* 1. Get private data from exchange context via CR pattern:
* a4->24 is exchange context pointer
* a4->4 == 4 means IPv4 child SA (subtract -96)
* a4->4 == 6 means IPv6 child SA (subtract -120)
* 2. Check if (a3 >= 0) && (v9->40 != 1) && port == 500
* 3. Allocate packet context via sub_6E78
* 4. If successful, copy header and payload
* 5. Check IKE version (packet[0x17] & 0xF0 == 0x20 = IKEv2)
* 6. Dispatc via function pointer table at off_0xE3360:
* ((packet[17] >> 4) - 1) as index into table
* Table entries at 0xE8360, 0xE8368, etc.
* 7. Proces payload (sub_34C0 for SPD/SA matching)
*
* The IKE packet header (28 bytes minimum):
* +0x00: InitiatorSPI (UINT64
* +0x08: ResponderSPI (UINT64)
* +0x10: NextPayload (UINT8)
* +0x11: Version (UINT8) - high nibble = major
* +0x12: ExchangeType (UINT8)
* +0x13: Flags (UINT8)
* +0x14: MessageID (UINT32)
* +0x18: Length (UINT32)
*/
/* ========================================================================
* Static Configuration Templates
* ======================================================================== *
*
* The allocaated in the .rdata or .data section and copied during init.
*
* off_12A7B8: EFI_IPSEC_CONFIG_PROTOCOL template (24 bytes)
* SetData -> sub_3C44 (0x3C44)
* GetData -> sub_???? (probably 0x33EC)
* RegisterNotify -> sub_6378 (0x6378)
*
* off_12A730: Config function table (40 bytes = 5 pointers)
* Function pointers for config data operations
*
* off_12A6A0: Three list heads for config chains
*
* gIpSecV4DriverBinding: at 0x12A6D0
* gIkeV2DriverBinding: at 0x12A700
* gIpSecComponentName2: at 0x12A7D0
* gIpSecComponentName: at 0x12A7E8
* gDisableEvent: at 0x12A7C0
* gDpcDispatchEvent: at 0x12D080
*/