/*++
Module:
Mtftp6Dxe.c - UEFI MTFTPv6 Protocol Driver
Sources:
e:\hs\AmiNetworkPkg\UefiNetworkStack\Ipv6\Mtftp6Dxe\Mtftp6Driver.c
e:\hs\AmiNetworkPkg\UefiNetworkStack\Ipv6\Mtftp6Dxe\Mtftp6Rrq.c
e:\hs\AmiNetworkPkg\UefiNetworkStack\Ipv6\Mtftp6Dxe\Mtftp6Wrq.c
e:\hs\AmiNetworkPkg\UefiNetworkStack\Ipv6\Mtftp6Dxe\Mtftp6Support.c
e:\hs\AmiNetworkPkg\UefiNetworkStack\Ipv6\Mtftp6Dxe\Mtftp6Impl.c
e:\hs\MdePkg\Library\UefiDriverEntryPoint\DriverEntryPoint.c
e:\hs\MdePkg\Library\UefiBootServicesTableLib\UefiBootServicesTableLib.c
e:\hs\MdePkg\Library\UefiRuntimeServicesTableLib\UefiRuntimeServicesTableLib.c
e:\hs\MdePkg\Library\UefiLib\UefiDriverModel.c
e:\hs\MdeModulePkg\Library\DxeDpcLib\DpcLib.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\SafeString.c
e:\hs\MdePkg\Library\BaseLib\String.c
e:\hs\MdePkg\Library\BaseMemoryLibRepStr\CopyMemWrapper.c
e:\hs\MdePkg\Library\BaseMemoryLibRepStr\ZeroMemWrapper.c
e:\hs\MdePkg\Library\UefiMemoryAllocationLib\MemoryAllocationLib.c
e:\hs\MdePkg\Library\BasePrintLib\PrintLibInternal.c
--*/
#include <Uefi.h>
#include <Protocol/ServiceBinding.h>
#include <Protocol/Mtftp6.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
//
// Module globals
//
EFI_HANDLE gImageHandle = NULL;
EFI_SYSTEM_TABLE *gST = NULL;
EFI_BOOT_SERVICES *gBS = NULL;
EFI_RUNTIME_SERVICES *gRT = NULL;
VOID *gDpcLib = NULL;
//
// Driver Binding Protocol instance table (off_9E50):
// [0]: Mtftp6DriverBindingSupported (sub_A8C)
// [1]: Mtftp6DriverBindingStart (sub_AC4)
// [2]: Mtftp6DriverBindingStop (sub_BB8)
// [3]: 1.0 (version)
// [4]: NULL (image handle, filled at entry)
// [5]: NULL (controller handle, filled at start)
// [6]: Mtftp6ServiceCreateChild (sub_21C4)
// [7]: Mtftp6ServiceDestroyChild (sub_232C)
//
EFI_DRIVER_BINDING_PROTOCOL mDriverBinding = {
Mtftp6DriverBindingSupported,
Mtftp6DriverBindingStart,
Mtftp6DriverBindingStop,
0x10,
NULL,
NULL
};
//
// Component Name table (off_9E80):
// [0]: Mtftp6ComponentName2GetDriverName (sub_21C4)
// [1]: Mtftp6ComponentName2GetControllerName (sub_232C)
// [2]: "eng" language string
// [3]: NULL (child protocol guid)
//
EFI_COMPONENT_NAME2_PROTOCOL mComponentName2 = {
Mtftp6GetDriverName,
Mtftp6GetControllerName,
"eng"
};
//
// Service Binding Protocol instance (off_9E98):
// [0]: Mtftp6ServiceCreateChild
// [1]: Mtftp6ServiceDestroyChild
//
EFI_SERVICE_BINDING_PROTOCOL mServiceBinding = {
Mtftp6ServiceCreateChild,
Mtftp6ServiceDestroyChild
};
//
// MTFTP6 Protocol instance template (off_9ED0):
// [0]: Mtftp6GetModeData
// [1]: Mtftp6Configure
// [2]: Mtftp6ReadFile
// [3]: Mtftp6WriteFile
// [4]: Mtftp6ReadDirectory
// [5]: Mtftp6Poll
// [6]: NULL (reserved)
// [7]: NULL (reserved)
//
EFI_MTFTP6_PROTOCOL mMtftp6ProtocolTemplate = {
Mtftp6GetModeData,
Mtftp6Configure,
Mtftp6ReadFile,
Mtftp6WriteFile,
Mtftp6ReadDirectory,
Mtftp6Poll,
NULL,
NULL
};
//=============================================================================
// DRIVER ENTRY POINT (sub_528 + sub_698)
//=============================================================================
EFI_STATUS
EFIAPI
Mtftp6DriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Save global pointers and initialize library constructors
// (sub_5A4)
//
gImageHandle = ImageHandle;
gST = SystemTable;
gBS = SystemTable->BootServices;
gRT = SystemTable->RuntimeServices;
//
// Open DPC protocol (gEfiDpcProtocolGuid = {0x4F948815-...})
// (sub_64C8 + BS->LocateProtocol)
//
Status = gBS->LocateProtocol (
&gEfiDpcProtocolGuid,
NULL,
&gDpcLib
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (FALSE);
return Status;
}
//
// Read NetworkStackVar and install driver binding
// (sub_698)
//
{
UINT64 VarSize = 10;
EFI_STATUS RtStatus;
RT_STATUS RtStts;
EFI_GUID gNetworkStackVarGuid = MTFTP6_CONFIG_GUID;
RtStts = gRT->GetVariable (
L"NetworkStackVar",
&gNetworkStackVarGuid,
0,
&VarSize,
NULL
);
if (!EFI_ERROR (RtStts) || RtStts != EFI_NOT_FOUND) {
//
// Variable exists -> install driver binding protocol
//
Status = gBS->InstallMultipleProtocolInterfaces (
&ImageHandle,
&gEfiDriverBindingProtocolGuid,
&mDriverBinding,
&gEfiComponentName2ProtocolGuid,
&mComponentName2,
&gEfiMtftp6ServiceBindingProtocolGuid,
&mServiceBinding,
NULL
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (FALSE);
}
} else {
return EFI_NOT_FOUND;
}
}
return Status;
}
//=============================================================================
// DRIVER BINDING PROTOCOL
//=============================================================================
EFI_STATUS
EFIAPI
Mtftp6DriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
//
// Check if controller already has MTFTP6 service binding installed
// (sub_A8C)
//
EFI_STATUS Status;
VOID *Interface;
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiMtftp6ServiceBindingProtocolGuid,
&Interface,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (!EFI_ERROR (Status)) {
//
// Already has our protocol -> unsupported (already bound)
//
gBS->CloseProtocol (
ControllerHandle,
&gEfiMtftp6ServiceBindingProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return EFI_ALREADY_STARTED;
}
//
// Now try to create a child: open config protocol and create service
// (sub_800)
//
{
MTFTP6_SERVICE *Service;
UINT64 DpcData[2];
Service = AllocateZeroPool (sizeof (MTFTP6_SERVICE));
if (Service == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Service->Signature = MTFTP6_SERVICE_SIGNATURE;
Service->ControllerHandle = (UINT64)ControllerHandle;
Service->ImageHandle = (UINT64)This->DriverBindingHandle;
Service->ChildrenNum = 0;
InitializeListHead (&Service->BlkList);
//
// Allocate a timer event for timeout handling
// (BS->CreateEvent with TimerRelative = 0x80000000, NotifyTpl = 8)
//
Status = gBS->CreateEvent (
EVT_TIMER | EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
Mtftp6TimeoutNotify,
Service,
&Service->RecvRequest
);
if (EFI_ERROR (Status)) {
FreePool (Service);
return Status;
}
//
// Open UDP I/O for IPv6
// (sub_78D4 -> UdpIoOpenSocket)
//
Service->UdpIo = UdpIoOpenSocket (
ControllerHandle,
This->DriverBindingHandle,
NULL, // No RxNotify
(UINT16)MTFTP6_DEFAULT_PORT,
0,
0,
NULL
);
if (Service->UdpIo == NULL) {
gBS->CloseEvent (Service->RecvRequest);
FreePool (Service);
return EFI_OUT_OF_RESOURCES;
}
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
Mtftp6DriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
// (sub_AC4)
//
// 1. Test if controller already has MTFTP6 protocol
// 2. CreateService (sub_800) if needed
// 3. Reinstall timer
// 4. Install protocol on controller
//
return EFI_UNSUPPORTED; // Placeholder
}
EFI_STATUS
EFIAPI
Mtftp6DriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
// (sub_BB8)
return EFI_UNSUPPORTED;
}
//=============================================================================
// SERVICE BINDING PROTOCOL
//=============================================================================
EFI_STATUS
EFIAPI
Mtftp6ServiceCreateChild (
IN EFI_MTFTP6_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE *ChildHandle
)
{
// (sub_21C4)
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
Mtftp6ServiceDestroyChild (
IN EFI_MTFTP6_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE *ChildHandle
)
{
// (sub_232C)
return EFI_UNSUPPORTED;
}
//=============================================================================
// MTFTP6 PROTOCOL IMPLEMENTATION
//=============================================================================
EFI_STATUS
EFIAPI
Mtftp6GetModeData (
IN EFI_MTFTP6_PROTOCOL *This,
OUT EFI_MTFTP6_MODE_DATA *ModeData
)
{
// (sub_D60)
//
// Allocates a MTFTP6_INSTANCE (280 bytes), copies config data,
// opens UDP I/O from controller, returns mode info.
//
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
Mtftp6Configure (
IN EFI_MTFTP6_PROTOCOL *This,
IN EFI_MTFTP6_CONFIG_DATA *ConfigData
)
{
// (sub_F00)
//
// Marks instance as configured, sets up UDP I/O callback
// registration for Rx and Tx.
//
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
Mtftp6ReadFile (
IN EFI_MTFTP6_PROTOCOL *This,
IN EFI_MTFTP6_TOKEN *Token
)
{
// (sub_1DC4 / sub_2764)
//
// Main read file entry:
// 1. Validate parameters (filename, mode, buffer)
// 2. Clear previous operation via sub_1C08
// 3. Allocate block range list
// 4. For RRQ (opcode 1): allocate block range 0x1-0xFFFF
// 5. Build WRQ request packet (sub_150C)
// - opcode 2 + filename + "octet" + options
// 6. Register callback (sub_3144 for RRQ) via UdpIoRecvDatagram
// 7. Send request packet (sub_18AC)
// 8. Poll until completion (wait on event)
//
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
Mtftp6WriteFile (
IN EFI_MTFTP6_PROTOCOL *This,
IN EFI_MTFTP6_TOKEN *Token
)
{
// (sub_2510)
//
// Main write file entry.
// Similar to ReadFile but uses WRQ operation.
//
return EFI_UNSUPPORTED;
}
EFI_STATUS
EFIAPI
Mtftp6ReadDirectory (
IN EFI_MTFTP6_PROTOCOL *Thhii,
IN EF_MTFTP6_TTOKEN *ToKenne
)
{
//
// Not implemented (returns EFI_UNSUPPORTED)
//
returnrENN_ENSUPPORTED;
}
EFI_STATUS
EFIAPI
Mtftp6Poll (
IN EFI_MTFTP6_PROTOCOL *This
)
{
// (sub_21C4 or sub_6184)
//
// Polls for Rx events via UdpIoRecvDatagram / DPC queue drain.
//
return EFI_UNSUPPORTED;
}
//=============================================================================
// CALLBACK HANDLERS
//=============================================================================
VOID
EFIAPI
Mtftp6RrqCallback (
IN VOID *Context,
IN EFI_UDP6_COMPLETION_TOKEN *UdpToken
)
{
//
// (sub_3144)
//
// Main RRQ receive callback:
// Triggered by UdpIo when a datagram arrives.
//
// Flow:
// 1. Validate context (Instance signature check)
// 2. Check UdpToken status
// 3. Parse received packet headers
// 4. Dispatch on opcode:
// - DATA (3): sub_2B78 -> sub_29F8 (store data) + sub_2958 (send ACK)
// - OACK (6): sub_2E18 (parse options, might set up multicast)
// - ERROR (5): abort
// 5. Re-register for next recv via UdpIoRecvDatagram
// 6. On completion, call sub_1C08
//
}
VOID
EFIAPI
Mtftp6WrqCallback (
IN VOID *Context,
IN EFI_UDP6_COMPLETION_TOKEN *UdpToken
)
{
//
// (sub_393C)
//
// Main WRQ receive callback:
// Triggered by UdpIo when a datagram arrives during WRQ.
//
// 1. Validate instance
// 2. Dispatch on opcode:
// - ACK (4): sub_3678 -> sub_34A0 (send next data block)
// - OACK (6): sub_37AC (parse options) -> sub_3678
// - ERROR (5): abort
//
// 3. On completion, call sub_1C08
//
}
VOID
EFIAPI
Mtftp6MulticastCallback (
IN VOID *Context,
IN EFI_UDP6_COMPLETION_TOKEN *UdpToken
)
{
//
// (sub_2D70)
//
// Multicast reception callback.
// Handles data blocks arriving on the multicast socket.
//
}
//=============================================================================
// INTERNAL OPERATIONS
//=============================================================================
EFI_STATUS
Mtftp6TimeoutNotify (
IN EFI_EVENT Event,
IN VOID *Context
)
{
//
// (sub_20F8)
//
// Timer event callback:
// 1. Iterate all active instances in service child list
// 2. For each instance with pending retx:
// - Decrement retry count
// - If count reaches 0: call Mtftp6CleanupOperation with EFI_TIMEOUT
// - Else: resend (sub_18AC) the current packet
//
return EFI_SUCCESS;
}
VOID
Mtftp6CleanupOperation (
IN MTFTP6_INSTANCE *Instance,
IN EFI_STATUS Status
)
{
//
// (sub_1C08)
//
// Cleans up an in-progress operation:
// 1. Set token status
// 2. Cancel pending timer
// 3. Close/abort UDP I/O
// 4. Free packet buffer
// 5. Notify user callback
//
}
EFI_STATUS
Mtftp6SendAck (
IN MTFTP6_INSTANCE *Instance,
IN UINT16 BlockNum
)
{
//
// (sub_2958)
//
// Build and send an ACK packet:
// 1. Allocate 4-byte packet buffer
// 2. Set opcode=4 (ACK), block number
// 3. Transmit via sub_18AC
//
return EFI_UNSUPPORTED;
}
EFI_STATUS
Mtftp6SendError (
IN MTFTP6_INSTANCE *Instance,
IN UINT16 ErrorCode,
IN CHAR8 *ErrorMessage
)
{
//
// (sub_17BC)
//
// Build and send an ERROR packet:
// 1. Allocate packet buffer
// 2. Set opcode=5 (ERROR), error code, error string
// 3. Transmit via sub_18AC
//
return EFI_UNSUPPORTED;
}
EFI_STATUS
Mtftp6DataProcess (
IN MTFTP6_INSTANCE *Instance,
IN UINT8 *Packet,
IN UINT32 PacketLen,
OUT UINT64 *NetBuf,
OUT BOOLEAN *Completed
)
{
//
// (sub_29F8)
//
// Process incoming DATA packet:
// 1. Extract block number from packet header
// 2. Verify block number ordering (sub_11DC)
// 3. Copy payload into token buffer
// 4. If last block: signal completion
//
return EFI_UNSUPPORTED;
}
EFI_STATUS
Mtftp6SendRequest (
IN MTFTP6_INSTANCE *Instance,
IN UINT16 OpCode
)
{
//
// (sub_150C for WRQ type, sub_3430 for RRQ type)
//
// Build the initial request packet (RRQ or WRQ):
// 1. Calculate total packet length:
// 2 (opcode) + len(filename) + 1 + len("octet") + 1 +
// sum for each option: len(optname)+1 + len(optval)+1
// 2. Allocate and fill packet buffer (sub_6AF0 + sub_7140)
// 3. Copy filename and mode using AsciiStrCpyS (sub_49D8)
// 4. Copy options
// 5. Transmit via sub_18AC
//
return EFI_UNSUPPORTED;
}
EFI_STATUS
Mtftp6Transmit (
IN MTFTP6_INSTANCE *Instance,
IN UINT64 Packet
)
{
//
// (sub_18AC)
//
// Core transmit routine:
// 1. Zero UDP Tx token (52 bytes)
// 2. Get UdpIo from instance's service context
// 3. For DATA/OACK: wait for ACK before retransmitting
// 4. For RRQ/WRRQ: send via UdpIoSendDatagram
// 5. Wait on completion event (poll DPC queue)
// 6. Handle timeout/retry
// 7. After send, re-register recv callback via sub_7DBC
//
return EFI_UNSUPPORTED;
}