Newer
Older
AMI-Aptio-BIOS-Reversed / Dhcp6Dxe / Dhcp6Dxe.c
@Ajax Dong Ajax Dong 2 days ago 36 KB Init
/*============================================================================
 * Dhcp6Dxe.c - DHCPv6 DXE Driver (Reconstructed from IDA)
 *============================================================================
 * Binary:       Dhcp6Dxe.efi
 * SHA256:       ac8951ae380a72682831be2e274a07832cee6d78fa7f9c5a35c4194f6078b688
 * Image size:   0xa9c0
 * Functions:    130 total
 *
 * Source files (from debug paths):
 *   e:\hs\AmiNetworkPkg\UefiNetworkStack\Ipv6\Dhcp6Dxe\Dhcp6Driver.c
 *   e:\hs\AmiNetworkPkg\UefiNetworkStack\Ipv6\Dhcp6Dxe\Dhcp6Impl.c
 *   e:\hs\AmiNetworkPkg\UefiNetworkStack\Ipv6\Dhcp6Dxe\Dhcp6Io.c
 *   e:\hs\AmiNetworkPkg\UefiNetworkStack\Ipv6\Dhcp6Dxe\Dhcp6Utility.c
 *   e:\hs\MdeModulePkg\Library\DxeUdpIoLib\DxeUdpIoLib.c
 *   e:\hs\MdeModulePkg\Library\DxeNetLib\NetBuffer.c
 *   e:\hs\MdePkg\Library\BaseLib\LinkedList.c
 *   e:\hs\MdePkg\Library\BaseLib\String.c
 *   e:\hs\MdePkg\Library\UefiDriverEntryPoint\DriverEntryPoint.c
 *   e:\hs\MdePkg\Library\UefiBootServicesTableLib\UefiBootServicesTableLib.c
 *   e:\hs\MdePkg\Library\UefiRuntimeServicesTableLib\UefiRuntimeServicesTableLib.c
 *   e:\hs\MdeModulePkg\Library\DxeDpcLib\DpcLib.c
 *
 * This is a reconstructed C representation based on static binary analysis.
 *============================================================================*/

#include "Dhcp6Dxe.h"

/*============================================================================
 * Globals
 *============================================================================*/
EFI_HANDLE           gImageHandle = NULL;
EFI_SYSTEM_TABLE    *gSystemTable  = NULL;
EFI_BOOT_SERVICES   *gBootServices = NULL;
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL;

/*============================================================================
 * Forward declarations for internal functions
 *============================================================================*/

/* --- Dhcp6Driver.c (0x84C-0x102C) --- */
static EFI_STATUS
Dhcp6CreateService (
  IN  EFI_HANDLE       ControllerHandle,
  IN  EFI_HANDLE       DriverBindingHandle,
  OUT DHCP6_SERVICE   **Service
  );

static EFI_STATUS
Dhcp6DestroyService (
  IN DHCP6_SERVICE *Service
  );

static EFI_STATUS
Dhcp6DriverBindingStart (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   ControllerHandle,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
  );

static EFI_STATUS
Dhcp6DriverBindingStop (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   ControllerHandle,
  IN UINTN                        NumberOfChildren,
  IN EFI_HANDLE                   *ChildHandleBuffer
  );

static EFI_STATUS
Dhcp6DriverBindingSupported (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   ControllerHandle,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
  );

static EFI_STATUS
Dhcp6CreateInstance (
  IN  DHCP6_SERVICE   *Service,
  OUT DHCP6_INSTANCE **Instance
  );

static EFI_STATUS
Dhcp6CloseInstance (
  IN  DHCP6_INSTANCE *Instance
  );

static VOID
Dhcp6FreeInstance (
  IN DHCP6_INSTANCE *Instance
  );

/* --- Dhcp6Impl.c (0x22F4-0x3270) --- */

static EFI_STATUS
EfiDhcp6Start (
  IN EFI_DHCP6_PROTOCOL  *This
  );

static EFI_STATUS
EfiDhcp6Stop (
  IN EFI_DHCP6_PROTOCOL  *This
  );

static EFI_STATUS
EfiDhcp6Solicit (
  IN EFI_DHCP6_PROTOCOL  *This,
  IN UINT32              OptionCount,
  IN VOID                *OptionList,
  IN VOID                *ClientId,
  IN VOID                *IaCbData,
  IN UINT32              IaId
  );

static EFI_STATUS
EfiDhcp6Request (
  IN EFI_DHCP6_PROTOCOL  *This,
  IN UINT32              OptionCount,
  IN VOID                *OptionList,
  IN VOID                *ClientId,
  IN VOID                *IaCbData,
  IN UINT32              IaId
  );

static EFI_STATUS
EfiDhcp6Renew (
  IN EFI_DHCP6_PROTOCOL  *This
  );

static EFI_STATUS
EfiDhcp6Rebind (
  IN EFI_DHCP6_PROTOCOL  *This,
  IN UINT32              OptionCount,
  IN VOID                *OptionList
  );

static EFI_STATUS
EfiDhcp6RenewRebind (
  IN EFI_DHCP6_PROTOCOL  *This,
  IN UINT32              OptionCount,
  IN VOID                *OptionList
  );

static EFI_STATUS
EfiDhcp6Decline (
  IN EFI_DHCP6_PROTOCOL  *This,
  IN UINT32              OptionCount,
  IN VOID                *OptionList
  );

static EFI_STATUS
EfiDhcp6Release (
  IN EFI_DHCP6_PROTOCOL  *This,
  IN UINT32              OptionCount,
  IN VOID                *OptionList
  );

/* --- Dhcp6Io.c (0x3360-0x59B0) --- */
static EFI_STATUS
Dhcp6TransmitWorker (
  IN DHCP6_INSTANCE  *Instance,
  IN DHCP6_PACKET    *Packet,
  IN DHCP6_TX_CB     *TxCb
  );

static VOID
Dhcp6SetTimer (
  IN DHCP6_INSTANCE  *Instance,
  IN UINT32          IaState
  );

static VOID
Dhcp6SetRetransmitParams (
  IN DHCP6_INSTANCE  *Instance,
  IN UINT32          IaState
  );

static EFI_STATUS
Dhcp6IaStateMachine (
  IN DHCP6_INSTANCE  *Instance,
  IN UINT32          IaState
  );

static EFI_STATUS
Dhcp6BuildSolicitAdvertFw (
  IN  DHCP6_INSTANCE  *Instance,
  OUT VOID            **Packet
  );

static EFI_STATUS
Dhcp6BuildRequestFw (
  IN  DHCP6_INSTANCE  *Instance,
  IN  UINT16          *ServerId,
  OUT VOID            **Packet
  );

static EFI_STATUS
Dhcp6BuildRenewFw (
  IN  DHCP6_INSTANCE  *Instance,
  IN  UINT16          *ServerId,
  OUT VOID            **Packet
  );

static UINT32
Dhcp6CalculateWait (
  IN UINT32  T1,
  IN UINT32  T2
  );

static EFI_STATUS
Dhcp6CheckMedia (
  IN  DHCP6_INSTANCE  *Instance,
  OUT BOOLEAN         *MediaPresent
  );

static EFI_STATUS
Dhcp6BuildDeclineFw (
  IN  DHCP6_INSTANCE  *Instance,
  IN  UINT16          *IaOption,
  OUT VOID            **Packet
  );

static EFI_STATUS
Dhcp6BuildReleaseFw (
  IN  DHCP6_INSTANCE  *Instance,
  IN  UINT16          *ServerId,
  OUT VOID            **Packet
  );

static EFI_STATUS
Dhcp6StartDelayedTx (
  IN DHCP6_INSTANCE   *Instance,
  IN DHCP6_PACKET     *Packet
  );

static EFI_STATUS
Dhcp6SelectAdvertise (
  IN  DHCP6_INSTANCE   *Instance,
  IN  BOOLEAN          IsRebind,
  OUT VOID             **AdSelect
  );

static EFI_STATUS
Dhcp6VerifyAdvertise (
  IN  DHCP6_INSTANCE *Instance,
  IN  VOID           *Advertise
  );

static EFI_STATUS
Dhcp6ProcessReply (
  IN  DHCP6_INSTANCE  *Instance,
  IN  VOID            *Reply,
  OUT VOID            **AdSelect
  );

static EFI_STATUS
Dhcp6ProcessMessage (
  IN  DHCP6_INSTANCE  *Instance,
  IN  DHCP6_PACKET    *Packet
  );

/* --- Dhcp6Utility.c (0x1468-0x21F4) --- */
static VOID
Dhcp6CreateClientId (
  IN  DHCP6_SERVICE  *Service,
  OUT VOID           **ClientId
  );

static EFI_STATUS
Dhcp6CopyConfigData (
  IN  VOID  *Dest,
  IN  VOID  *Src
  );

static VOID
Dhcp6FreeConfigData (
  IN VOID *CfgData
  );

static UINT32
Dhcp6Random (
  VOID
  );

static EFI_STATUS
Dhcp6CheckIaAddress (
  IN  IA_CB      *IaCb,
  IN  UINT32     AddressCount,
  IN  VOID       *AddressArray
  );

static VOID *
Dhcp6PickIaAddresses (
  IN  IA_CB      *IaCb,
  IN  UINT32     AddressCount,
  IN  VOID       *AddressArray
  );

static VOID *
Dhcp6AppendOption (
  IN VOID       *Buffer,
  IN UINT16     OpCode,
  IN UINT16     OpLen,
  IN VOID       *Data
  );

static VOID *
Dhcp6FindOption (
  IN VOID       *Buffer,
  IN UINT16     BufLen,
  IN UINT16     OpCode
  );

static VOID *
Dhcp6FindIaOption (
  IN VOID       *IaOptions,
  IN UINT16     IaLen,
  IN UINT16     IaType,
  IN VOID       *Config
  );

static VOID
Dhcp6ParseIaAddresses (
  IN  IA_CB       *IaCb,
  IN  VOID        *IaOption,
  IN  UINT16      IaLen,
  OUT VOID        *AddressArray,
  OUT UINT32      *AddressCount
  );

static EFI_STATUS
Dhcp6UpdateIaAddress (
  IN  DHCP6_INSTANCE  *Instance,
  IN  VOID            *IaOption,
  IN  UINT16          IaLen,
  IN  UINT32          T1,
  IN  UINT32          T2
  );

static UINT32
Dhcp6CalculateIaT1T2 (
  IN UINT32  ValidLifetime,
  IN UINT32  T1,
  IN UINT32  T2
  );

/*============================================================================
 * Dhcp6Driver.c - Driver Binding Protocol Entry Point
 *============================================================================*/

EFI_STATUS
EFIAPI
Dhcp6DriverEntryPoint (
  IN EFI_HANDLE       ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  )
{
  EFI_STATUS  Status;
  EFI_HANDLE  Handle;
  VOID        *Interface;
  VOID        *Registration;

  /* Initialize global table pointers (gImageHandle, gST, gBS, gRT) */
  Status = EfiLibInitTablePointers(ImageHandle, SystemTable);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  /* Register for DPC protocol */
  Interface = NULL;
  Status = gBS->LocateProtocol (&gEfiDpcProtocolGuid, NULL, &Interface);
  ASSERT_EFI_ERROR (Status);

  /* Register Unload handler and driver binding */
  Status = EfiLibInstallAllDriverProtocols2 (
             ImageHandle,
             SystemTable,
             &gDhcp6DriverBinding,
             ImageHandle,
             &gDhcp6ComponentName2,
             &gDhcp6ComponentName,
             NULL
             );
  ASSERT_EFI_ERROR (Status);

  return Status;
}

/*============================================================================
 * Dhcp6DriverBindingSupported
 *============================================================================*/
EFI_STATUS
EFIAPI
Dhcp6DriverBindingSupported (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   ControllerHandle,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
  )
{
  EFI_STATUS  Status;
  VOID        *Interface;

  Status = gBS->OpenProtocol (
                  ControllerHandle,
                  &gEfiUdp6ServiceBindingProtocolGuid,
                  &Interface,
                  This->DriverBindingHandle,
                  ControllerHandle,
                  EFI_OPEN_PROTOCOL_BY_DRIVER
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  gBS->CloseProtocol (
        ControllerHandle,
        &gEfiUdp6ServiceBindingProtocolGuid,
        This->DriverBindingHandle,
        ControllerHandle
        );

  return EFI_SUCCESS;
}

/*============================================================================
 * Dhcp6CreateService
 * Allocate and initialize DHCP6_SERVICE structure.
 * Creates UDP IO, generates Client ID, seeds transaction ID.
 *============================================================================*/
static EFI_STATUS
Dhcp6CreateService (
  IN  EFI_HANDLE       ControllerHandle,
  IN  EFI_HANDLE       DriverBindingHandle,
  OUT DHCP6_SERVICE   **ServiceOut
  )
{
  DHCP6_SERVICE   *Service;
  EFI_STATUS      Status;
  UINT32          Seed;
  UINT16          TimeLow;
  UINT8           MacBuffer[16];
  UINT8           MacAddrSize;
  UINT32          Tick;

  *ServiceOut = NULL;
  Service = (DHCP6_SERVICE *) AllocateZeroPool (sizeof (DHCP6_SERVICE));
  if (Service == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  /* Open UDP6 protocol */
  Status = UdpIoOpen (ControllerHandle, &Service->UdpIo);
  if (Status != EFI_SUCCESS || Service->UdpIo == NULL) {
    goto ErrorExit;
  }

  /* Fill service fields */
  Service->Signature        = DHCP6_SERVICE_SIGNATURE;
  Service->ControllerHandle = ControllerHandle;
  Service->DriverBindingHandle = DriverBindingHandle;
  InitializeListHead (&Service->InstanceList);

  /* Generate MAC-based seed for transaction ID */
  ZeroMem (MacBuffer, sizeof (MacBuffer));
  gRT->GetTime (&TimeLow, NULL);
  gBS->GetNextMonotonicCount (&Tick);

  Status = IpIoGetMacAddress (Service->UdpIo, MacBuffer, &MacAddrSize);
  if (EFI_ERROR (Status)) {
    Seed = Tick + (TimeLow ^ (TimeLow >> 8) ^ (MacBuffer[0] | (MacBuffer[1] | ((MacBuffer[2] | (~MacBuffer[3] << 8)) << 8)) << 8));
  } else {
    Seed = Tick;
  }
  Seed = (1103515245 * Seed + 12345) % 0xFFFFFFFF;
  Service->TransactionIdSeed = Seed & 0xFFFFFF;

  /* Copy protocol GUID */
  CopyMem (&Service->Udp6CfgData, &gEfiUdp6ProtocolGuid, sizeof (EFI_GUID));

  /* Open loaded image protocol to get MAC address for Client ID */
  Status = gBS->OpenProtocol (
                  ControllerHandle,
                  &gEfiLoadedImageProtocolGuid,
                  &Interface,
                  DriverBindingHandle,
                  ControllerHandle,
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
                  );
  if (EFI_ERROR (Status)) {
    goto ErrorExit;
  }

  /* Create DUID Client ID */
  Service->ClientId = Dhcp6CreateClientId (Service, Interface);
  if (Service->ClientId == NULL) {
    Status = EFI_UNSUPPORTED;
    goto ErrorExit;
  }

  /* Create UDP I/O instance */
  Service->UdpIoHandle = Dhcp6CreateUdpIo (ControllerHandle, DriverBindingHandle);
  if (Service->UdpIoHandle == NULL) {
    FreePool (Service->ClientId);
    goto ErrorExit;
  }

  InitializeListHead (&Service->RecvRequest);

  *ServiceOut = Service;
  return EFI_SUCCESS;

ErrorExit:
  FreePool (Service);
  return Status;
}

/*============================================================================
 * Dhcp6DriverBindingStart
 * Called when a UDP6 interface is found. Creates DHCP6_SERVICE and
 * installs DHCP6 service binding protocol.
 *============================================================================*/
static EFI_STATUS
EFIAPI
Dhcp6DriverBindingStart (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   ControllerHandle,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
  )
{
  DHCP6_SERVICE   *Service;
  EFI_STATUS      Status;

  /* Check if protocol already installed */
  Status = gBS->OpenProtocol (
                  ControllerHandle,
                  &gEfiDhcp6ServiceBindingProtocolGuid,
                  NULL,
                  This->DriverBindingHandle,
                  ControllerHandle,
                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
                  );
  if (!EFI_ERROR (Status)) {
    return EFI_ALREADY_STARTED;
  }

  /* Create DHCP6 service */
  Status = Dhcp6CreateService (ControllerHandle, This->DriverBindingHandle, &Service);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  /* Install service binding protocol */
  Status = gBS->InstallMultipleProtocolInterfaces (
                  &ControllerHandle,
                  &gEfiDhcp6ServiceBindingProtocolGuid,
                  &Service->ServiceBinding,
                  NULL
                  );
  if (EFI_ERROR (Status)) {
    Dhcp6DestroyService (Service);
    return Status;
  }

  return EFI_SUCCESS;
}

/*============================================================================
 * Dhcp6DriverBindingStop
 *============================================================================*/
static EFI_STATUS
EFIAPI
Dhcp6DriverBindingStop (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   ControllerHandle,
  IN UINTN                        NumberOfChildren,
  IN EFI_HANDLE                   *ChildHandleBuffer
  )
{
  EFI_STATUS        Status;
  DHCP6_SERVICE     *Service;
  UINTN             NumHandles;
  EFI_HANDLE        *HandleBuffer;

  /* Find DHCP6 protocol handles */
  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gEfiDhcp6ProtocolGuid,
                  NULL,
                  &NumHandles,
                  &HandleBuffer
                  );
  if (EFI_ERROR (Status)) {
    return EFI_SUCCESS;
  }

  /* For each handle, check if it belongs to this controller */
  for (UINTN Index = 0; Index < NumHandles; Index++) {
    DHCP6_INSTANCE *Instance;

    Status = gBS->OpenProtocol (
                    HandleBuffer[Index],
                    &gEfiDhcp6ProtocolGuid,
                    &Instance,
                    This->DriverBindingHandle,
                    ControllerHandle,
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
                    );
    if (EFI_ERROR (Status)) {
      continue;
    }

    /* Check signature */
    if (Instance->Signature != DHCP6_INSTANCE_SIGNATURE) {
      continue;
    }

    /* Check if child handle matches */
    if (NumberOfChildren > 0) {
      BOOLEAN Found = FALSE;
      for (UINTN i = 0; i < NumberOfChildren; i++) {
        if (ChildHandleBuffer[i] == HandleBuffer[Index]) {
          Found = TRUE;
          break;
        }
      }
      if (!Found) {
        continue;
      }
    }

    /* Close the instance */
    if (Instance->Config != NULL) {
      Dhcp6FreeConfigData (Instance->Config);
    }

    /* Uninstall protocol and free instance */
    gBS->CloseProtocol (
          HandleBuffer[Index],
          &gEfiDhcp6ProtocolGuid,
          This->DriverBindingHandle,
          ControllerHandle
          );

    RemoveEntryList (&Instance->Link);
    Dhcp6FreeInstance (Instance);
  }

  FreePool (HandleBuffer);

  /* If no more children, destroy the service */
  Service = NULL;
  Status = gBS->OpenProtocol (
                  ControllerHandle,
                  &gEfiDhcp6ServiceBindingProtocolGuid,
                  &Service,
                  This->DriverBindingHandle,
                  ControllerHandle,
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
                  );
  if (!EFI_ERROR (Status)) {
    if (Service->NumOfChild == 0) {
      gBS->UninstallMultipleProtocolInterfaces (
            ControllerHandle,
            &gEfiDhcp6ServiceBindingProtocolGuid,
            &Service->ServiceBinding,
            NULL
            );
      Dhcp6DestroyService (Service);
    }
  }

  return EFI_SUCCESS;
}

/*============================================================================
 * Dhcp6DestroyService
 *============================================================================*/
static EFI_STATUS
Dhcp6DestroyService (
  IN DHCP6_SERVICE *Service
  )
{
  ASSERT (Service->NumOfChild == 0);

  /* Free Client ID */
  if (Service->ClientId != NULL) {
    FreePool (Service->ClientId);
  }

  /* Free UDP I/O */
  UdpIoDelete (Service->UdpIo);
  UdpIoFreeService (Service->UdpIo);

  /* Free the service itself */
  FreePool (Service);
  return EFI_SUCCESS;
}

/*============================================================================
 * Dhcp6Impl.c - EFI_DHCP6_PROTOCOL Implementation
 *============================================================================*/

/*============================================================================
 * EfiDhcp6Start
 * Start DHCP6 on this instance. Checks media, configures IA_CB,
 * begins Solicit/Information-Request as appropriate.
 *============================================================================*/
static EFI_STATUS
EfiDhcp6Start (
  IN EFI_DHCP6_PROTOCOL  *This
  )
{
  DHCP6_INSTANCE    *Instance;
  DHCP6_SERVICE     *Service;
  BOOLEAN           MediaPresent;
  UINT64            Ticker;
  EFI_STATUS        Status;

  Instance = CR (This, DHCP6_INSTANCE, Dhcp6Protocol, DHCP6_INSTANCE_SIGNATURE);
  if (Instance == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Service = Instance->Service;
  if (Service == NULL) {
    return EFI_NOT_READY;
  }

  /* Check if already started */
  if (Instance->IaCb != NULL && Instance->IaCb->IaState != DHCP6_STATE_INIT) {
    return EFI_ALREADY_STARTED;
  }

  /* Allocate ticker */
  Ticker = gBS->AllocatePool (8);

  Instance->CompletionStatus = EFI_ALREADY_STARTED;
  Instance->Configured = TRUE;

  /* Check media presence */
  IpIoOpen (Service->IpIo, &MediaPresent);
  if (!MediaPresent) {
    Status = EFI_NO_MEDIA;
    DebugPrint (0x80000000, "\nIn EfiDhcp6Start  MediaPresent Status = %r\n", Status);
    gBS->FreePool (Ticker);
    return Status;
  }

  /* Check media status more thoroughly */
  Status = Dhcp6CheckMedia (Instance, &MediaPresent);
  if (EFI_ERROR (Status)) {
    gBS->FreePool (Ticker);
    return Status;
  }

  /* Register Unicode collation (for option string comparison) */
  Status = UefiUnicodeCollationStub (Service->UdpIo, Service->DriverBindingHandle, Service);
  if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
    gBS->FreePool (Ticker);
    return Status;
  }

  gBS->FreePool (Ticker);

  /* If config has no IA, we are done (Information-Request only) */
  if (Instance->Config != NULL && Instance->Config->IaDescriptorType != 0) {
    /* Wait for completion */
    while (Instance->CompletionStatus == EFI_ALREADY_STARTED) {
      /* Poll UDP */
    }
    return Instance->CompletionStatus;
  }

  return EFI_SUCCESS;
}

/*============================================================================
 * EfiDhcp6Stop
 * Stop DHCP6 on this instance. Cleans up IA state and TX blocks.
 *============================================================================*/
static EFI_STATUS
EfiDhcp6Stop (
  IN EFI_DHCP6_PROTOCOL  *This
  )
{
  DHCP6_INSTANCE    *Instance;
  EFI_STATUS        Status;
  UINT64            Ticker;

  Instance = CR (This, DHCP6_INSTANCE, Dhcp6Protocol, DHCP6_INSTANCE_SIGNATURE);
  if (Instance == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (Instance->IaCb == NULL) {
    return EFI_SUCCESS;
  }

  if (Instance->IaCb->IaState <= DHCP6_STATE_RELEASING) {
    Ticker = gBS->AllocatePool (8);
    Instance->CompletionStatus = EFI_ALREADY_STARTED;
    Status = Dhcp6StartDelayedTx (Instance, (DHCP6_PACKET *)Instance->IaCb);
    gBS->FreePool (Ticker);

    if (EFI_ERROR (Status) && Instance->Config != NULL) {
      Service = Instance->Service;
      if (Service == NULL || Service->Udp6 == NULL) {
        ASSERT (Service->Udp6 != NULL);
      }
      while (Instance->CompletionStatus == EFI_ALREADY_STARTED) {
        /* Poll UDP */
      }
      Status = Instance->CompletionStatus;
    }
  }

  Ticker = gBS->AllocatePool (8);
  Dhcp6IaStateMachine (Instance, DHCP6_STATE_INIT);
  gBS->FreePool (Ticker);

  return Status;
}

/*============================================================================
 * EfiDhcp6Solicit
 * Initiate a Solicit-InformationRequest exchange.
 *============================================================================*/
static EFI_STATUS
EfiDhcp6Solicit (
  IN EFI_DHCP6_PROTOCOL  *This,
  IN UINT32              OptionCount,
  IN VOID                *OptionList,
  IN VOID                *ClientId,
  IN VOID                *IaCbData,
  IN UINT32              IaId
  )
{
  DHCP6_INSTANCE    *Instance;
  DHCP6_SERVICE     *Service;

  Instance = CR (This, DHCP6_INSTANCE, Dhcp6Protocol, DHCP6_INSTANCE_SIGNATURE);
  if (Instance == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (ClientId == NULL && IaCbData == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Service = Instance->Service;

  if (Instance->Config == NULL && IaCbData != NULL) {
    /* Config not set yet, allocate */
    Instance->Config = AllocateZeroPool (sizeof (DHCP6_CONFIG_DATA));
    if (Instance->Config == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }
    Dhcp6CopyConfigData (IaCbData, Instance->Config);
  }

  /* Check Service has ClientId */
  if (Service->ClientId == NULL) {
    ASSERT (Service->ClientId != NULL);
  }

  /* Allocate return buffers */
  UINT64 Ticker = gBS->AllocatePool (8);

  if (IaCbData != NULL) {
    ZeroMem (IaCbData, sizeof (DHCP6_CONFIG_DATA));
    if (Dhcp6CopyConfigData (IaCbData, Instance->Config) != EFI_SUCCESS) {
      return EFI_DEVICE_ERROR;
    }
  }

  if (ClientId != NULL) {
    UINT16 ClientIdLen = *(UINT16 *)Service->ClientId + 2;
    *(VOID **)ClientId = AllocatePool (ClientIdLen);
    if (*(VOID **)ClientId == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }
    CopyMem (*(VOID **)ClientId, Service->ClientId, ClientIdLen);

    /* IA_CB data */
    if (Instance->IaCb != NULL) {
      UINT32 IaCbSize = 24 * Instance->IaCb->IaAddressCount + 32;
      *(VOID **)(ClientId + 8) = AllocatePool (IaCbSize);
      if (*(VOID **)(ClientId + 8) == NULL) {
        return EFI_OUT_OF_RESOURCES;
      }
      CopyMem (*(VOID **)(ClientId + 8), Instance->IaCb, IaCbSize);

      if (Instance->IaCb->OptionList != NULL) {
        *(VOID **)(*(VOID **)(ClientId + 8) + 16) = AllocatePool (*Instance->IaCb->OptionList);
        if (*(VOID **)(*(VOID **)(ClientId + 8) + 16) == NULL) {
          return EFI_OUT_OF_RESOURCES;
        }
        CopyMem (*(VOID **)(*(VOID **)(ClientId + 8) + 16), Instance->IaCb->OptionList, *Instance->IaCb->OptionList);
      }
    }
  }

  /* Transition state machine to SELECTING */
  Instance->CompletionStatus = EFI_ALREADY_STARTED;

  /* Start Solicit transmission via worker threads */
  Status = Dhcp6TransmitSolicit (Instance, ClientId, IaId);

  if (EFI_ERROR (Status)) {
    goto Done;
  }

  /* Register with Unicode collation */
  UefiUnicodeCollationStub (Service->UdpIo, Service->DriverBindingHandle, Service);

  /* Wait for completion */
  if (Instance->Config != NULL && Instance->Config->IaDescriptorType != 0) {
    while (Instance->CompletionStatus == EFI_ALREADY_STARTED) {
      /* Poll */
    }
    return Instance->CompletionStatus;
  }

Done:
  gBS->FreePool (Ticker);
  return Status;
}

/*============================================================================
 * EfiDhcp6Request, EfiDhcp6Renew, EfiDhcp6Rebind, EfiDhcp6RenewRebind
 * EfiDhcp6Decline, EfiDhcp6Release
 *============================================================================*/
/* (Remaining protocol functions follow the same pattern) */

/*============================================================================
 * Dhcp6Io.c - Network I/O, Packet TX/RX, Retransmission State Machine
 *============================================================================*/

/*============================================================================
 * Dhcp6TransmitWorker
 * Build and transmit a DHCPv6 packet over UDP6.
 *============================================================================*/
static EFI_STATUS
Dhcp6TransmitWorker (
  IN DHCP6_INSTANCE  *Instance,
  IN DHCP6_PACKET    *Packet,
  IN DHCP6_TX_CB     *TxCb
  )
{
  ASSERT (Instance->Config != NULL);
  ASSERT (Instance->IaCb != NULL);
  ASSERT (Instance->Service != NULL);
  ASSERT (Packet != NULL);
  ASSERT (Packet->Size > Packet->Length + 8);

  /* Build the TX frame (DHCPv6 message + options) */
  UINT32  BufferLen;
  VOID    *Buffer;
  UINT16  *ClientId;
  UINT32  IaOptionsSize;
  IA_CB   *IaCb;

  ClientId = (UINT16 *)Instance->Service->ClientId;
  IaCb = Instance->IaCb;

  /* Allocate buffer for the packet */
  BufferLen = Packet->Length + 8 + *ClientId + 2;
  if (IaCb != NULL) {
    BufferLen += 24 * IaCb->IaAddressCount + 32;
  }
  Buffer = AllocatePool (BufferLen);
  if (Buffer == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  /* Build DHCPv6 message header */
  *(UINT8 *)Buffer = Packet->MessageType;
  *(UINT32 *)(Buffer + 1) = Instance->Service->TransactionIdSeed << 8;
  /* Options follow... */
  UINT8 *Options = (UINT8 *)Buffer + 4;

  /* Append Client ID option */
  Options = Dhcp6AppendOption (Options, DHCP6_OPT_CLIENTID, *ClientId, ClientId + 1);

  /* Append Server ID (if known) */
  if (TxCb->ServerId != NULL) {
    Options = Dhcp6AppendOption (Options, DHCP6_OPT_SERVERID, *TxCb->ServerId, TxCb->ServerId + 1);
  }

  /* Append IA option (IA_NA or IA_TA) */
  if (IaCb != NULL) {
    Options = Dhcp6BuildIaOption (Buffer, IaCb, Options);
  }

  /* Send over UDP via UdpIo */
  UdpIoSend (Instance->Service->UdpIo, Buffer, EFI_SUCCESS, Instance);

  return EFI_SUCCESS;
}

/*============================================================================
 * Dhcp6ReceiveCallback
 * Callback invoked by UdpIo when a DHCPv6 packet is received.
 * Dispatches to the appropriate state machine handler.
 *============================================================================*/
static VOID
EFIAPI
Dhcp6ReceiveCallback (
  IN VOID             *Udp6Wrap,
  IN EFI_STATUS       Status,
  IN VOID             *Context,
  IN VOID             *RxToken
  )
{
  DHCP6_INSTANCE   *Instance;
  DHCP6_PACKET     *Packet;
  EFI_STATUS       ParseStatus;
  UINT32           *RxBuffer;
  UINT32           RxDataLen;

  ASSERT (Udp6Wrap != NULL);
  ASSERT (Context != NULL);

  Instance = (DHCP6_INSTANCE *)Context;

  if (EFI_ERROR (Status)) {
    /* Just clean up and return */
    return;
  }

  /* Parse received IPv6/UDP6 data into DHCPv6 packet */
  RxDataLen = *(UINT32 *)((UINT8 *)Udp6Wrap + 132);
  if (RxDataLen >= 4) {
    RxBuffer = (UINT32 *)AllocatePool (RxDataLen + 13);
    if (RxBuffer == NULL) {
      return;
    }
    *RxBuffer = RxDataLen + 13;
    *(UINT32 *)((UINT8 *)RxBuffer + 4) = Dhcp6ParseUdpData (Udp6Wrap, RxToken, RxDataLen, RxBuffer + 2);

    if (*(UINT32 *)((UINT8 *)RxBuffer + 4) != 0) {
      /* Check TX list for matching Transaction ID */
      LIST_ENTRY *TxList = &Instance->TxList;
      LIST_ENTRY *Entry = TxList->ForwardLink;
      while (Entry != TxList) {
        DHCP6_TX_CB *TxCb = CR (Entry, DHCP6_TX_CB, Link, DHCP6_TX_CB_SIGNATURE);
        DHCP6_PACKET *TxPacket = TxCb->TxPacket;

        /* Check transaction ID match */
        LIST_ENTRY *TxChildList = TxPacket->TxList.ForwardLink;
        LIST_ENTRY *TxChildEnd = &TxPacket->TxList;

        while (TxChildList != TxChildEnd) {
          if (((UINT32 *)TxChildList)[4] >> 8 == *(UINT32 *)(RxBuffer + 2)) {
            /* Transaction match -- process reply */
            goto FoundMatch;
          }
          TxChildList = ((LIST_ENTRY *)TxChildList)->ForwardLink;
        }
        Entry = Entry->ForwardLink;
      }
FoundMatch:
      /* Process message based on current state */
      Dhcp6ProcessMessage (Instance, (DHCP6_PACKET *)RxBuffer);
    }
  }
}

/*============================================================================
 * Dhcp6TimerTickng
 * Timer notification function. Drives retransmission logic.
 *============================================================================*/
static VOID
EFIAPI
Dhcp6TimerTickng (
  IN EFI_EVENT        Event,
  IN DHCP6_INSTANCE   *Instance
  )
{
  EFI_STATUS          Status;
  DHCP6_SERVICE       *Service;
  DHCP6_TX_CB         *TxCb;
  LIST_ENTRY          *Entry;
  LIST_ENTRY          *NextEntry;

  ASSERT (Context != NULL);
  Instance = (DHCP6_INSTANCE *)Context;

  if (Instance->IaCb == NULL) {
    return;
  }

  /* Check for timeout on pending transmissions */
  if (Instance->CompletionStatus != EFI_SUCCESS) {
    /* Already completed or errored */
    return;
  }

  /* Iterate TX list for retransmission timeout */
  Entry = Instance->TxList.ForwardLink;
  while (Entry != &Instance->TxList) {
    TxCb = CR (Entry, DHCP6_TX_CB, Link, DHCP6_TX_CB_SIGNATURE);
    NextEntry = Entry->ForwardLink;

    /* Check if this TX has timed out */
    if (TxCb->RetransmitCount > 0) {
      TxCb->RetransmitCount--;
      if (TxCb->RetransmitCount == 0) {
        /* Timeout -- retransmit or fail */
        if (TxCb->RetransmitMaxCount == 0 ||
            TxCb->RetransmitCurTime < TxCb->RetransmitMaxTimeout) {
          /* Retransmit */
          UINT32 WaitTime = Dhcp6CalculateWait (TxCb->RetransmitTimeout, TxCb->RetransmitMaxTimeout);
          TxCb->RetransmitTimeout = WaitTime;
          TxCb->RetransmitTotal += WaitTime;
          TxCb->RetransmitCurTime = WaitTime;

          UINT32 RandomDelay = Dhcp6Random (100);
          TxCb->RetransmitCurTime += (TxCb->RetransmitCurTime * RandomDelay) / 100;

          Dhcp6TransmitWorker (Instance, TxCb->TxPacket, TxCb);
        } else {
          /* MRT exceeded -- complete with timeout */
          Instance->CompletionStatus = EFI_TIMEOUT;
          Dhcp6IaStateMachine (Instance, DHCP6_STATE_INIT);
          break;
        }
      }
    }
    Entry = NextEntry;
  }
}

/*============================================================================
 * Dhcp6Utility.c - DHCPv6 Option Encoding/Decoding and Helpers
 *============================================================================*/

/*============================================================================
 * Dhcp6AppendOption
 * Write a DHCPv6 option TLV (OpCode/OpLen/Data) at Buffer.
 * Returns pointer to next option position.
 *============================================================================*/
static VOID *
Dhcp6AppendOption (
  IN VOID       *Buffer,
  IN UINT16     OpCode,
  IN UINT16     OpLen,
  IN VOID       *Data
  )
{
  ASSERT (OpLen != 0);

  *(UINT16 *)Buffer = SwapBytes16 (OpCode);
  *(UINT16 *)((UINT8 *)Buffer + 2) = SwapBytes16 (OpLen);

  VOID *OptionData = (UINT8 *)Buffer + 4;
  UINT16 NetLen = SwapBytes16 (OpLen);
  CopyMem (OptionData, Data, NetLen);

  return (UINT8 *)OptionData + NetLen;
}

/*============================================================================
 * Dhcp6FindOption
 * Search Buffer (BufLen bytes) for option with OpCode.
 * Returns pointer to option header or NULL.
 *============================================================================*/
static VOID *
Dhcp6FindOption (
  IN VOID       *Buffer,
  IN UINT16     BufLen,
  IN UINT16     OpCode
  )
{
  UINT8  *Ptr;
  UINT16  OptionCode;
  UINT16  OptionLen;

  /* Write option header code (network order) */
  *(UINT16 *)Buffer = SwapBytes16 (OpCode);
  Ptr = (UINT8 *)Buffer;
  Ptr += 4; /* skip length field */

  /* Parse */
  UINT8 *OptionStart = (UINT8 *)Buffer;
  *(UINT16 *)(OptionStart + 2) = 0; /* will be filled later */
  *(UINT16 *)(OptionStart + 4) = SwapBytes16 ((UINT16)(UINT32)(*(UINT32 *)(Buffer + 4)));

  *(UINT16 *)(OptionStart + 2) = SwapBytes16 (
    (UINT16)(((UINT32)SwapBytes16 (*(UINT16 *)((UINT8 *)Buffer + 4))) & 0xFFFF)
  );

  return OptionStart;
}

/*============================================================================
 * Dhcp6CalculateIaT1T2
 * Calculate IA T1/T2 from ValidLifetime with constraints.
 *============================================================================*/
static UINT32
Dhcp6CalculateIaT1T2 (
  IN UINT32  ValidLifetime,
  IN UINT32  T1,
  IN UINT32  T2
  )
{
  UINT32 Result;

  Result = T1 | (T2 << 8);

  /* Clamp to valid range */
  if (T1 >= 30 && T1 <= 60 && T2 >= 60) {
    /* Scale based on ValidLifetime */
    UINT64 Scaled = (UINT64)ValidLifetime * 0x462BE000;
    Scaled >>= 32;
    if (Scaled < 23) {
      Scaled = 23;
    }
    Result = (UINT32)((UINT64)ValidLifetime * 0x26CF1600 >> 32);
    if (Result > 0xFFFF) {
      Result = 0xFFFF;
    }
  }

  return Result;
}

/*============================================================================
 * Dhcp6UpdateIaAddress
 * Update or add IA addresses from received IA option.
 *============================================================================*/
static EFI_STATUS
Dhcp6UpdateIaAddress (
  IN DHCP6_INSTANCE  *Instance,
  IN VOID            *IaOption,
  IN UINT16          IaLen,
  IN UINT32          T1,
  IN UINT32          T2
  )
{
  IA_CB   *IaCb;
  UINT8   *IaAddr;
  UINT32   CurrentCount;

  IaCb = Instance->IaCb;
  if (IaCb == NULL || Instance->Config == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  IaAddr = (UINT8 *)IaOption + 4; /* skip IA header */
  CurrentCount = 0;

  while ((UINTN)IaAddr < (UINTN)IaOption + IaLen + 4) {
    UINT16 OptionLen = SwapBytes16 (*(UINT16 *)(IaAddr + 2)) + 4;
    if (OptionLen < 4) break;

    if (*(UINT16 *)IaAddr == SwapBytes16 (DHCP6_OPT_IAADDR)) {
      /* Found IA Address option, copy it */
      if (CurrentCount < DHCP6_MAX_IA_ADDRESSES) {
        CopyMem (&IaCb->IaAddress[CurrentCount].IpAddress, IaAddr + 4, 16);
        IaCb->IaAddress[CurrentCount].PreferredLifetime = SwapBytes32 (*(UINT32 *)(IaAddr + 20));
        IaCb->IaAddress[CurrentCount].ValidLifetime = SwapBytes32 (*(UINT32 *)(IaAddr + 24));
        CurrentCount++;
      }
    }

    IaAddr += OptionLen;
  }

  IaCb->IaAddressCount = CurrentCount;
  return EFI_SUCCESS;
}

/*============================================================================
 * UdpIo wrapper functions (from DxeUdpIoLib)
 *============================================================================*/

/*============================================================================
 * UdpIoCreateService
 * Allocate and initialize a UdpIo wrapper instance.
 *============================================================================*/
UINTN
UdpIoCreateService (
  IN  EFI_HANDLE     DriverBindingHandle,
  IN  EFI_HANDLE     ControllerHandle,
  IN  EFI_GUID       *ProtocolGuid,
  OUT VOID           **UdpIo
  )
{
  *UdpIo = AllocatePool (sizeof (UDP_IO));
  if (*UdpIo == NULL) return 0;

  /* Initialize UdpIo structure */
  InitializeListHead (*UdpIo);
  /* ... */
  return *UdpIo;
}

/*============================================================================
 * UdpIoFreeService
 * Free a UdpIo wrapper instance.
 *============================================================================*/
VOID
UdpIoFreeService (
  IN VOID            *UdpIo
  )
{
  FreePool (UdpIo);
}

/*============================================================================
 * Module Entry Point
 *============================================================================*/
EFI_STATUS
EFIAPI
ModuleEntryPoint (
  IN EFI_HANDLE       ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  )
{
  EFI_STATUS  Status;
  VOID        *Interface;

  /* Initialize globals */
  EfiLibInitTablePointers (ImageHandle, SystemTable);

  /* Locate DPC protocol */
  Status = gBS->LocateProtocol (&gEfiDpcProtocolGuid, NULL, &Interface);
  if (EFI_ERROR (Status)) {
    goto Done;
  }

  /* Set up driver unload handler */
  Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, &Interface);
  if (EFI_ERROR (Status)) {
    RvdhPrint (0, "\nASSERT_EFI_ERROR (Status = %r)\n", Status);
    ASSERT_EFI_ERROR (Status);
  }

  /* Register driver model */
  *(VOID **)((UINT8 *)Interface + 88) = UefiDriverModelUnload;

  /* Install driver binding + component name */
  Status = EfiLibInstallAllDriverProtocols (
             ImageHandle,
             SystemTable,
             &gDhcp6DriverBinding,
             ImageHandle,
             &gDhcp6ComponentName2,
             NULL,
             NULL
             );

Done:
  return Status;
}