/** @file
VlanConfigDxe.c - VLAN Configuration DXE Driver
This UEFI driver manages VLAN tag configuration on network interfaces
through the HII Configuration Framework. It implements:
- Driver Binding Protocol for managing network controller instances
- VLAN Config Protocol for VLAN tag CRUD operations
- HII Config Access Protocol for form-based configuration
- Component Name 2 Protocol for driver identification
Source layout (from debug strings):
VlanConfigImpl.c - HII form logic, callbacks, configuration extraction
VlanConfigDriver.c - Driver binding, entry point, VLAN protocol ops
Build path:
e:\hs\AmiNetworkPkg\UefiNetworkStack\Common\VlanConfigDxe\
Copyright (c) AMI, Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "VlanConfigDxe.h"
//
// ==========================================================================
// GUID Definitions
// ==========================================================================
//
///
/// VLAN Config Protocol GUID: { B3276D32-41FC-4260-7469-D90FAA23DC4C }
/// Matches the data at 0x7208 in .rdata
///
EFI_GUID gEfiVlanConfigProtocolGuid = {
0xB3276D32, 0x41FC, 0x4260, { 0x74, 0x69, 0xD9, 0x0F, 0xAA, 0x23, 0xDC, 0x4C }
};
///
/// Managed Network Protocol GUID: { C1539892-9836-5822-AB31-A01843B41A4D }
/// (as used in VlanConfigDriverBindingSupported)
///
EFI_GUID gEfiManagedNetworkProtocolGuid = {
0xC1539892, 0x9836, 0x5822, { 0xAB, 0x31, 0xA0, 0x18, 0x43, 0xB4, 0x1A, 0x4D }
};
///
/// Device Path Protocol GUID: { 09576E91-6D3F-11D2-8E39-00A0C969723B }
/// (standard UEFI Device Path Protocol GUID)
///
EFI_GUID gEfiDevicePathProtocolGuid = {
0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }
};
//
// Simple Network Protocol GUID: { A19832B9-AC25-11D3-9A2D-0090273FC14D }
// (standard UEFI SNP GUID)
//
EFI_GUID gEfiSimpleNetworkProtocolGuid = {
0xA19832B9, 0xAC25, 0x11D3, { 0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }
};
//
// HII Protocol GUIDS (standard UEFI)
//
EFI_GUID gEfiHiiStringProtocolGuid = {
0x0FD96974, 0x23AA, 0x4CDC, { 0xB9, 0xCB, 0x98, 0xD1, 0x77, 0x50, 0x32, 0x2A }
};
EFI_GUID gEfiHiiDatabaseProtocolGuid = {
0xEF9FC172, 0xA1B2, 0x4693, { 0xB3, 0x27, 0x6D, 0x32, 0xFC, 0x41, 0x60, 0x42 }
};
EFI_GUID gEfiHiiConfigRoutingProtocolGuid = {
0x587E72D7, 0xCC50, 0x4F79, { 0x82, 0x09, 0xCA, 0x29, 0x1F, 0xC1, 0xA1, 0x0F }
};
EFI_GUID gEfiHiiConfigAccessProtocolGuid = {
0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }
};
EFI_GUID gEfiComponentName2ProtocolGuid = {
0x6A7A5CFF, 0xE8D9, 0x4F70, { 0xBA, 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14 }
};
EFI_GUID gEfiDriverBindingProtocolGuid = {
0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }
};
//
// ==========================================================================
// Global Variables
// ==========================================================================
//
///
/// Image handle (global)
///
EFI_HANDLE gImageHandle = NULL;
EFI_SYSTEM_TABLE *gST = NULL;
EFI_BOOT_SERVICES *gBS = NULL;
EFI_RUNTIME_SERVICES *gRT = NULL;
///
/// HII Config Routing Protocol handle
///
EFI_HII_CONFIG_ROUTING_PROTOCOL *gHiiConfigRouting = NULL;
///
/// HII Database Protocol handle
///
EFI_HII_DATABASE_PROTOCOL *gHiiDatabase = NULL;
///
/// HII String Protocol handle
///
EFI_HII_STRING_PROTOCOL *gHiiString = NULL;
///
/// HII Config Access Protocol handle (lazy init)
///
EFI_HII_CONFIG_ACCESS_PROTOCOL *gHiiConfigAccess = NULL;
///
/// Default zero MAC address (6 bytes)
///
UINT8 mZeroMacAddress[6] = { 0, 0, 0, 0, 0, 0 };
///
/// Driver Binding Protocol instance
///
EFI_DRIVER_BINDING_PROTOCOL gVlanConfigDriverBinding = {
VlanConfigDriverBindingSupported,
VlanConfigDriverBindingStart,
VlanConfigDriverBindingStop,
0x10, // Version
NULL, // ImageHandle (filled at entry)
NULL // DriverBindingHandle (filled at entry)
};
///
/// Component Name 2 Protocol table
///
EFI_COMPONENT_NAME2_PROTOCOL gVlanConfigComponentName2 = {
VlanConfigComponentName2GetDriverName,
VlanConfigComponentName2GetControllerName,
(CHAR8 *)"eng;en"
};
///
/// HII Config Access Protocol instance
///
EFI_HII_CONFIG_ACCESS_PROTOCOL gVlanConfigHiiConfigAccess = {
VlanConfigExtractConfig,
VlanConfigRouteConfig,
VlanConfigCallback
};
///
/// VFR binary and string package references (defined in auto-generated files)
///
extern UINT8 mVlanConfigVfrBin[];
extern EFI_GUID gVlanConfigFormSetGuid;
//
// ==========================================================================
// Function Prototypes for Local Functions
// ==========================================================================
//
EFI_STATUS
VlanConfigInitPrivateData (
IN VLAN_CONFIG_PRIVATE_DATA *Private
);
VOID
VlanConfigCleanupPrivateData (
IN VLAN_CONFIG_PRIVATE_DATA *Private
);
EFI_STRING
VlanConfigConstructConfigRequest (
IN VLAN_CONFIG_PRIVATE_DATA *Private
);
BOOLEAN
VlanConfigValidateConfigHeader (
IN EFI_STRING ConfigHdr
);
BOOLEAN
VlanConfigCompareConfigStrings (
IN EFI_STRING FirstString,
IN EFI_STRING SecondString,
IN EFI_STRING StartSearchString,
IN EFI_STRING StopSearchString
);
EFI_STATUS
VlanConfigUpdateForm (
IN VLAN_CONFIG_PRIVATE_DATA *PrivateData
);
//
// ==========================================================================
// Library Wrappers
// ==========================================================================
//
/**
Wrapper for gBS->AllocatePool with zero fill.
@param[in] AllocationSize Size in bytes.
@return Pointer to the allocated buffer, NULL on failure.
**/
VOID *
VlanConfigAllocateZeroPool (
IN UINTN AllocationSize
)
{
VOID *Buffer;
Buffer = NULL;
if (gBS->AllocatePool (EfiBootServicesData, AllocationSize, &Buffer) != EFI_SUCCESS) {
return NULL;
}
if (AllocationSize > 0) {
ZeroMem (Buffer, AllocationSize);
}
return Buffer;
}
/**
Wrapper for gBS->FreePool.
@param[in] Buffer Pointer to buffer to free.
**/
VOID
VlanConfigFreePool (
IN VOID *Buffer
)
{
if (Buffer != NULL) {
gBS->FreePool (Buffer);
}
}
//
// ==========================================================================
// Module Entry Point
// ==========================================================================
//
/**
Entry point for the VLAN Config DXE driver.
Initializes global service pointer tables, locates HII protocol
interfaces, and installs the Driver Binding Protocol together
with the Component Name 2 Protocol.
@param[in] ImageHandle Image handle of this driver.
@param[in] SystemTable Pointer to the EFI System Table.
@retval EFI_SUCCESS The driver was initialized.
@retval EFI_UNSUPPORTED Required protocols were not found.
@retval other An error occurred during driver installation.
**/
EFI_STATUS
EFIAPI
VlanConfigDxeEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Initialize global service pointer tables
//
gImageHandle = ImageHandle;
gST = SystemTable;
gBS = SystemTable->BootServices;
gRT = SystemTable->RuntimeServices;
//
// Locate HII protocol interfaces (LocateProtocol with 0 registration)
//
Status = gBS->LocateProtocol (
&gEfiHiiStringProtocolGuid,
NULL,
(VOID **)&gHiiString
);
ASSERT_EFI_ERROR (Status);
Status = gBS->LocateProtocol (
&gEfiHiiDatabaseProtocolGuid,
NULL,
(VOID **)&gHiiDatabase
);
ASSERT_EFI_ERROR (Status);
Status = gBS->LocateProtocol (
&gEfiHiiConfigRoutingProtocolGuid,
NULL,
(VOID **)&gHiiConfigRouting
);
ASSERT_EFI_ERROR (Status);
//
// Locate HII Config Access Protocol (for NV data storage, optional)
//
gBS->LocateProtocol (
&gEfiHiiConfigAccessProtocolGuid,
NULL,
(VOID **)&gHiiConfigAccess
);
//
// Set up driver binding protocol handles
//
gVlanConfigDriverBinding.ImageHandle = ImageHandle;
gVlanConfigDriverBinding.DriverBindingHandle = ImageHandle;
//
// Install the Driver Binding and Component Name 2 protocols
//
Status = gBS->InstallMultipleProtocolInterfaces (
&gVlanConfigDriverBinding.DriverBindingHandle,
&gEfiDriverBindingProtocolGuid,
&gVlanConfigDriverBinding,
&gEfiComponentName2ProtocolGuid,
&gVlanConfigComponentName2,
NULL
);
ASSERT_EFI_ERROR (Status);
return Status;
}
//
// ==========================================================================
// Driver Binding Protocol
// ==========================================================================
//
/**
Tests whether the driver supports a given controller.
The driver claims support if:
1. The controller already has a VLAN Config Protocol installed
(returns EFI_ACCESS_DENIED to avoid duplicates).
2. The controller supports the Managed Network Protocol.
@param[in] This Pointer to the driver binding protocol.
@param[in] ControllerHandle Handle of the controller to test.
@param[in] RemainingDevicePath Optional pointer to the remaining device path.
@retval EFI_SUCCESS Supported (ManagedNetwork found).
@retval EFI_ACCESS_DENIED VLAN Config already installed.
@retval EFI_UNSUPPORTED Controller does not have ManagedNetwork.
**/
EFI_STATUS
EFIAPI
VlanConfigDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_VLAN_CONFIG_PROTOCOL *VlanConfig;
EFI_MANAGED_NETWORK_PROTOCOL *ManagedNetwork;
//
// Check if VLAN Config Protocol already exists on this controller.
// If so, report ACCESS_DENIED to avoid duplicate binding.
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiVlanConfigProtocolGuid,
(VOID **)&VlanConfig,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (!EFI_ERROR (Status)) {
gBS->CloseProtocol (
ControllerHandle,
&gEfiVlanConfigProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return EFI_ACCESS_DENIED;
}
//
// The controller must have Managed Network Protocol
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiManagedNetworkProtocolGuid,
(VOID **)&ManagedNetwork,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (!EFI_ERROR (Status)) {
gBS->CloseProtocol (
ControllerHandle,
&gEfiManagedNetworkProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
}
return Status;
}
/**
Starts the driver on a controller.
Opens Simple Network, Managed Network and Device Path protocols,
allocates and initializes private context (0x130 bytes), creates
HII form resources, and installs the VLAN Config Protocol.
@param[in] This Pointer to the driver binding protocol.
@param[in] ControllerHandle Handle of the controller to start.
@param[in] RemainingDevicePath Optional pointer to the remaining device path.
@retval EFI_SUCCESS The driver started successfully.
@retval EFI_OUT_OF_RESOURCES Memory allocation failed.
@retval other An error occurred.
**/
EFI_STATUS
EFIAPI
VlanConfigDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
VLAN_CONFIG_PRIVATE_DATA *Private;
EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork;
EFI_MANAGED_NETWORK_PROTOCOL *ManagedNetwork;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
UINTN HandleCount;
//
// Check if VLAN Config Protocol already exists on this controller
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiVlanConfigProtocolGuid,
(VOID **)&Private,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (!EFI_ERROR (Status)) {
return EFI_ACCESS_DENIED;
}
//
// Open Simple Network Protocol on the controller (GET_PROTOCOL)
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiSimpleNetworkProtocolGuid,
(VOID **)&SimpleNetwork,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Open Managed Network Protocol on the controller (BY_DRIVER)
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiManagedNetworkProtocolGuid,
(VOID **)&ManagedNetwork,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Open Device Path Protocol on the controller (BY_DRIVER)
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiDevicePathProtocolGuid,
(VOID **)&DevicePath,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
gBS->CloseProtocol (
ControllerHandle,
&gEfiManagedNetworkProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return Status;
}
//
// Allocate and initialize private data structure (0x130 bytes)
//
Private = (VLAN_CONFIG_PRIVATE_DATA *)VlanConfigAllocateZeroPool (sizeof (VLAN_CONFIG_PRIVATE_DATA));
if (Private == NULL) {
gBS->CloseProtocol (
ControllerHandle,
&gEfiManagedNetworkProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
gBS->CloseProtocol (
ControllerHandle,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return EFI_OUT_OF_RESOURCES;
}
//
// Initialize private data fields
//
Private->Signature = VLAN_CONFIG_PRIVATE_DATA_SIGNATURE;
Private->ControllerHandle = ControllerHandle;
Private->ImageHandle = This->ImageHandle;
Private->SimpleNetwork = SimpleNetwork;
Private->ManagedNetwork = ManagedNetwork;
Private->DevicePath = DevicePath;
//
// Initialize VLAN Config Protocol interface
//
Private->VlanConfigProtocol.Set = VlanConfigSet;
Private->VlanConfigProtocol.Find = VlanConfigFind;
Private->VlanConfigProtocol.Remove = VlanConfigRemove;
//
// Initialize the driver instance and create HII resources
//
Status = VlanConfigInitPrivateData (Private);
if (EFI_ERROR (Status)) {
VlanConfigCleanupPrivateData (Private);
VlanConfigFreePool (Private);
return Status;
}
//
// Install the VLAN Config Protocol on the controller handle
//
Status = gBS->InstallProtocolInterface (
&ControllerHandle,
&gEfiVlanConfigProtocolGuid,
EFI_NATIVE_INTERFACE,
Private
);
if (EFI_ERROR (Status)) {
VlanConfigCleanupPrivateData (Private);
VlanConfigFreePool (Private);
return Status;
}
return EFI_SUCCESS;
}
/**
Stops the driver on a controller.
Removes the VLAN Config Protocol, closes protocols opened by the
driver, frees HII resources and the private data structure.
@param[in] This Pointer to the driver binding protocol.
@param[in] ControllerHandle Handle of the controller to stop.
@param[in] NumberOfChildren Number of child handles.
@param[in] ChildHandleBuffer Array of child handles.
@retval EFI_SUCCESS The driver stopped on this controller.
**/
EFI_STATUS
EFIAPI
VlanConfigDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_STATUS Status;
VLAN_CONFIG_PRIVATE_DATA *Private;
EFI_VLAN_CONFIG_PROTOCOL *VlanConfig;
//
// Validate signature and get the private data
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiVlanConfigProtocolGuid,
(VOID **)&VlanConfig,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
Private = CR (VlanConfig, VLAN_CONFIG_PRIVATE_DATA, VlanConfigProtocol,
VLAN_CONFIG_PRIVATE_DATA_SIGNATURE);
//
// Clean up HII resources
//
VlanConfigCleanupPrivateData (Private);
//
// Uninstall the VLAN Config Protocol
//
Status = gBS->UninstallProtocolInterface (
ControllerHandle,
&gEfiVlanConfigProtocolGuid,
Private
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Close protocols opened by this driver
//
gBS->CloseProtocol (
ControllerHandle,
&gEfiManagedNetworkProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
gBS->CloseProtocol (
ControllerHandle,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
VlanConfigFreePool (Private);
return EFI_SUCCESS;
}
//
// ==========================================================================
// Driver Unload / Image Unload Handler
// ==========================================================================
//
/**
Unload handler for the VLAN Config DXE driver.
Enumerates all handles that have the VLAN Config Protocol installed
and stops the driver on each one, then uninstalls the driver binding
protocol.
@param[in] ImageHandle The driver's image handle.
@retval EFI_SUCCESS The driver was unloaded.
**/
EFI_STATUS
EFIAPI
VlanConfigDxeUnload (
IN EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE *HandleBuffer;
EFI_VLAN_CONFIG_PROTOCOL *VlanConfig;
UINTN Index;
//
// Locate all handles with VLAN Config Protocol
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiVlanConfigProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Stop the driver on each controller
//
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->OpenProtocol (
HandleBuffer[Index],
&gEfiVlanConfigProtocolGuid,
(VOID **)&VlanConfig,
ImageHandle,
HandleBuffer[Index],
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (!EFI_ERROR (Status)) {
VlanConfigDriverBindingStop (
&gVlanConfigDriverBinding,
HandleBuffer[Index],
0,
NULL
);
}
}
VlanConfigFreePool (HandleBuffer);
//
// Uninstall the driver binding and component name protocols
//
Status = gBS->UninstallMultipleProtocolInterfaces (
ImageHandle,
&gEfiDriverBindingProtocolGuid,
&gVlanConfigDriverBinding,
&gEfiComponentName2ProtocolGuid,
&gVlanConfigComponentName2,
NULL
);
return Status;
}
//
// ==========================================================================
// Private Data Initialization and Cleanup
// ==========================================================================
//
/**
Initializes the VLAN private data structure.
Creates HII resources: registers the formset with HII database,
populates the form with current VLAN configuration, and publishes
the HII Config Access Protocol on the controller handle.
@param[in] Private Pointer to the private context.
@retval EFI_SUCCESS Initialization succeeded.
@retval other An error occurred.
**/
EFI_STATUS
VlanConfigInitPrivateData (
IN VLAN_CONFIG_PRIVATE_DATA *Private
)
{
EFI_STATUS Status;
EFI_MAC_ADDRESS MacAddress;
UINTN MacSize;
CHAR16 MacString[64];
CHAR16 VlanConfigString[128];
CHAR16 *MacAddressString;
CHAR16 *MacStr;
//
// Extract current MAC address from SNP's mode data
//
MacSize = sizeof (EFI_MAC_ADDRESS);
CopyMem (&MacAddress, &Private->SimpleNetwork->Mode->CurrentAddress, MacSize);
MacStr = (CHAR16 *)VlanConfigAllocateZeroPool (64 * sizeof (CHAR16));
if (MacStr != NULL) {
UnicodeSPrint (
MacStr,
64 * sizeof (CHAR16),
L"MAC:%02x%02x%02x%02x%02x%02x",
((UINT8 *)&MacAddress)[0],
((UINT8 *)&MacAddress)[1],
((UINT8 *)&MacAddress)[2],
((UINT8 *)&MacAddress)[3],
((UINT8 *)&MacAddress)[4],
((UINT8 *)&MacAddress)[5]
);
}
//
// Register the formset with HII database
//
Private->HiiHandle = (EFI_HII_HANDLE)(UINTN)HiiAddPackages (
&gEfiVlanConfigProtocolGuid,
Private->ImageHandle,
(VOID *)mVlanConfigVfrBin,
NULL,
NULL
);
if (Private->HiiHandle == NULL) {
VlanConfigFreePool (MacStr);
return EFI_OUT_OF_RESOURCES;
}
//
// Install the HII Config Access Protocol on the controller handle
//
Status = gBS->InstallProtocolInterface (
&Private->ControllerHandle,
&gEfiHiiConfigAccessProtocolGuid,
EFI_NATIVE_INTERFACE,
&gVlanConfigHiiConfigAccess
);
ASSERT_EFI_ERROR (Status);
//
// Build the form title: "VLAN Configuration (MAC:...)"
//
if (MacStr != NULL) {
UnicodeSPrint (
VlanConfigString,
sizeof (VlanConfigString),
L"VLAN Configuration (%s)",
MacStr
);
HiiSetString (Private->HiiHandle, 0, VlanConfigString, NULL);
VlanConfigFreePool (MacStr);
}
//
// Populate the VLAN list on the form
//
Status = VlanConfigUpdateForm (Private);
return Status;
}
/**
Cleans up resources associated with a VLAN private context.
Frees HII resources (packages, strings), closes protocols,
and zeros out private data fields.
@param[in] Private Pointer to the private context.
**/
VOID
VlanConfigCleanupPrivateData (
IN VLAN_CONFIG_PRIVATE_DATA *Private
)
{
//
// Remove HII Config Access Protocol from the controller
//
if (Private->ControllerHandle != NULL) {
gBS->CloseProtocol (
Private->ControllerHandle,
&gEfiManagedNetworkProtocolGuid,
Private->ImageHandle,
Private->ControllerHandle
);
gBS->CloseProtocol (
Private->ControllerHandle,
&gEfiDevicePathProtocolGuid,
Private->ImageHandle,
Private->ControllerHandle
);
}
//
// Remove HII packages (strings and forms)
//
if (Private->HiiHandle != NULL) {
HiiRemovePackages (Private->HiiHandle);
}
}
//
// ==========================================================================
// VLAN Config Protocol Implementation
// ==========================================================================
//
/**
Creates a VLAN tag on the network controller.
Delegates to the Managed Network Protocol's VlanConfig function.
@param[in] This Pointer to the VLAN Config Protocol.
@param[in] VlanId VLAN ID (0-4094).
@param[in] Priority VLAN priority (0-7).
@retval EFI_SUCCESS The VLAN tag was created.
@retval other The Managed Network Protocol returned an error.
**/
EFI_STATUS
EFIAPI
VlanConfigSet (
IN EFI_VLAN_CONFIG_PROTOCOL *This,
IN UINT16 VlanId,
IN UINT8 Priority
)
{
VLAN_CONFIG_PRIVATE_DATA *Private;
Private = CR (This, VLAN_CONFIG_PRIVATE_DATA, VlanConfigProtocol,
VLAN_CONFIG_PRIVATE_DATA_SIGNATURE);
return Private->ManagedNetwork->VlanConfig (
Private->ManagedNetwork,
VlanId,
Priority
);
}
/**
Checks if a VLAN ID exists on the network controller.
@param[in] This Pointer to the VLAN Config Protocol.
@param[in] VlanId VLAN ID to find.
@retval EFI_SUCCESS The VLAN ID exists.
@retval EFI_NOT_FOUND The VLAN ID was not found.
**/
EFI_STATUS
EFIAPI
VlanConfigFind (
IN EFI_VLAN_CONFIG_PROTOCOL *This,
IN UINT16 VlanId
)
{
VLAN_CONFIG_PRIVATE_DATA *Private;
Private = CR (This, VLAN_CONFIG_PRIVATE_DATA, VlanConfigProtocol,
VLAN_CONFIG_PRIVATE_DATA_SIGNATURE);
if (Private->ManagedNetwork != NULL) {
return Private->ManagedNetwork->VlanConfig (
Private->ManagedNetwork,
VlanId,
0
);
}
return EFI_NOT_FOUND;
}
/**
Removes a VLAN tag from the network controller.
@param[in] This Pointer to the VLAN Config Protocol.
@param[in] VlanId VLAN ID to remove.
@retval EFI_SUCCESS The VLAN tag was removed.
**/
EFI_STATUS
EFIAPI
VlanConfigRemove (
IN EFI_VLAN_CONFIG_PROTOCOL *This,
IN UINT16 VlanId
)
{
VLAN_CONFIG_PRIVATE_DATA *Private;
Private = CR (This, VLAN_CONFIG_PRIVATE_DATA, VlanConfigProtocol,
VLAN_CONFIG_PRIVATE_DATA_SIGNATURE);
return Private->ManagedNetwork->VlanConfig (
Private->ManagedNetwork,
VlanId,
0
);
}
//
// ==========================================================================
// HII Form Population
// ==========================================================================
//
/**
Updates the HII form with the current set of VLAN entries.
Queries the Managed Network driver for installed VLAN tags
and populates the ordered list in the HII form as text op-codes.
@param[in] PrivateData Pointer to the VLAN private context.
@retval EFI_SUCCESS Form updated.
**/
EFI_STATUS
VlanConfigUpdateForm (
IN VLAN_CONFIG_PRIVATE_DATA *PrivateData
)
{
VOID *StartOpCodeHandle;
VOID *EndOpCodeHandle;
EFI_IFR_GUID_LABEL *StartLabel;
EFI_IFR_GUID_LABEL *EndLabel;
VLAN_CONFIGURATION *VlanConfig;
UINTN VlanCount;
UINTN Index;
EFI_STRING_ID StringId;
CHAR16 VlanString[64];
CHAR16 PriorityString[32];
CHAR16 Padding[64];
UINTN PaddingLen;
UINTN VlanListCount;
UINT16 *VlanIdList;
//
// Query VLAN list from Managed Network
// PrivateData->ManagedNetwork->VlanConfig (GET)
//
PrivateData->NumberOfVlan = 0;
//
// Get current VLAN count and list
//
VlanListCount = 0;
VlanIdList = NULL;
//
// Create op-code handles for the form
//
StartOpCodeHandle = HiiAllocateOpCodeHandle ();
ASSERT (StartOpCodeHandle != NULL);
EndOpCodeHandle = HiiAllocateOpCodeHandle ();
ASSERT (EndOpCodeHandle != NULL);
//
// Create start label
//
StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
StartOpCodeHandle,
&gEfiIfrTianoGuid,
NULL,
sizeof (EFI_IFR_GUID_LABEL)
);
StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
StartLabel->LabelNumber = LABEL_START;
//
// Create end label
//
EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
EndOpCodeHandle,
&gEfiIfrTianoGuid,
NULL,
sizeof (EFI_IFR_GUID_LABEL)
);
EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
EndLabel->LabelNumber = LABEL_END;
//
// Cap VLAN count for form display (max 100)
//
VlanCount = PrivateData->NumberOfVlan;
if (VlanCount > VLAN_MAX_COUNT) {
VlanCount = VLAN_MAX_COUNT;
}
//
// Build form entries for each existing VLAN
//
if (VlanCount > 0) {
ZeroMem (VlanString, sizeof (VlanString));
ZeroMem (PriorityString, sizeof (PriorityString));
for (Index = 0; Index < VlanCount; Index++) {
//
// Build string: " VLAN ID: %d"
//
UnicodeSPrint (
VlanString,
sizeof (VlanString),
L" VLAN ID: %d",
PrivateData->VlanIdList[Index]
);
//
// Pad to align priority text
//
PaddingLen = 2 * (4 - (StrLen (VlanString) - 6));
SetMem16 (Padding, PaddingLen, 0x0020); // spaces
//
// Build priority sub-string
//
UnicodeSPrint (
PriorityString,
sizeof (PriorityString),
L", Priority: %d",
0 // Priority not stored per-VLAN in min implementation
);
//
// Create new string in HII database
//
StringId = HiiSetString (PrivateData->HiiHandle, 0, VlanString, NULL);
ASSERT (StringId != 0);
//
// Create the text op-code for this VLAN entry
//
HiiCreateTextOpCode (
StartOpCodeHandle,
StringId,
0,
0,
(UINT16)(sizeof (VLAN_CONFIGURATION) - 2 - 2 * (UINT16)Index)
);
}
}
//
// Update the form
//
HiiUpdateForm (
PrivateData->HiiHandle,
&gEfiVlanConfigProtocolGuid,
VLAN_CONFIG_FORM_ID,
StartOpCodeHandle,
EndOpCodeHandle
);
//
// Clean up op-code handles
//
if (StartOpCodeHandle != NULL) {
if (*(UINTN *)StartOpCodeHandle != 0) {
VlanConfigFreePool (*(VOID **)StartOpCodeHandle);
}
VlanConfigFreePool (StartOpCodeHandle);
}
if (EndOpCodeHandle != NULL) {
if (*(UINTN *)EndOpCodeHandle != 0) {
VlanConfigFreePool (*(VOID **)EndOpCodeHandle);
}
VlanConfigFreePool (EndOpCodeHandle);
}
return EFI_SUCCESS;
}
//
// ==========================================================================
// HII Config Access Protocol
// ==========================================================================
//
/**
Extract configuration from the driver's form.
Builds the config request string and delegates to the HII Config Routing
protocol for extraction. Supports both initial (Request=NULL) and
subsequent requests.
@param[in] This Pointer to the HII Config Access Protocol.
@param[in] Request Configuration request string (or NULL for initial).
@param[out] Progress Pointer to the progress string.
@param[out] Results Pointer to the configuration results.
@retval EFI_SUCCESS Configuration extracted successfully.
@retval EFI_NOT_FOUND Config request header was invalid.
**/
EFI_STATUS
EFIAPI
VlanConfigExtractConfig (
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN CONST EFI_STRING Request,
OUT EFI_STRING *Progress,
OUT EFI_STRING *Results
)
{
VLAN_CONFIG_PRIVATE_DATA *Private;
EFI_STATUS Status;
EFI_STRING ConfigRequest;
BOOLEAN AllocatedRequest;
if (Progress == NULL || Results == NULL) {
return EFI_INVALID_PARAMETER;
}
*Progress = Request;
*Results = NULL;
//
// Validate the config request string if provided
//
if (Request != NULL && !VlanConfigValidateConfigHeader (Request)) {
return EFI_NOT_FOUND;
}
AllocatedRequest = FALSE;
//
// If no request string, build a complete request for VLAN_CONFIGURATION_SIZE
//
if (Request == NULL || !StrStr (Request, L"OFFSET")) {
ConfigRequest = VlanConfigConstructConfigRequest (Private);
AllocatedRequest = TRUE;
} else {
ConfigRequest = (EFI_STRING)Request;
}
//
// Ensure HII Config Routing protocol is loaded
//
if (gHiiConfigRouting == NULL) {
gBS->LocateProtocol (
&gEfiHiiConfigRoutingProtocolGuid,
NULL,
(VOID **)&gHiiConfigRouting
);
ASSERT (gHiiConfigRouting != NULL);
}
//
// Extract configuration via ConfigRouting
//
Private = CR (This, VLAN_CONFIG_PRIVATE_DATA, VlanConfigProtocol,
VLAN_CONFIG_PRIVATE_DATA_SIGNATURE);
Status = gHiiConfigRouting->ExtractConfig (
gHiiConfigRouting,
ConfigRequest,
Progress,
Results
);
//
*Progress = Request + 2 * StrLen (Request);
if (AllocatedRequest) {
VlanConfigFreePool (ConfigRequest);
}
return Status;
}
/**
Route configuration to the driver's NV storage.
Validates the config header and advances progress to string end.
@param[in] This Pointer to the HII Config Access Protocol.
@param[in] Configuration Configuration string.
@param[out] Progress Pointer to the progress string.
@retval EFI_SUCCESS Configuration routed successfully.
@retval EFI_NOT_FOUND Invalid config header.
**/
EFI_STATUS
EFIAPI
VlanConfigRouteConfig (
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN CONST EFI_STRING Configuration,
OUT EFI_STRING *Progress
)
{
if (Configuration == NULL || Progress == NULL) {
return EFI_INVALID_PARAMETER;
}
*Progress = Configuration;
//
// Validate the config header
//
if (!VlanConfigValidateConfigHeader (Configuration)) {
return EFI_NOT_FOUND;
}
//
// Route to end for progress reporting
//
*Progress = Configuration + 2 * StrLen (Configuration);
return EFI_SUCCESS;
}
/**
HII Callback for form actions.
Handles:
- REFRESH (QuestionId == 0): Reloads VLAN list from controller
- CHANGING (Action - 3 <= 1): Refresh on form entry/exit
- CHANGED QuestionId=0x1000: Create VLAN from form data
- CHANGED QuestionId=0x2000: Delete selected VLANs
- CHANGED QuestionId=0x3000: Exit form
@param[in] This Pointer to the HII Config Access Protocol.
@param[in] Action The action to perform.
@param[in] QuestionId The question ID.
@param[in] Type The type of the value.
@param[in] Value The value.
@param[out] ActionRequest The action request.
@retval EFI_SUCCESS The callback processed.
@retval EFI_UNSUPPORTED The action is unsupported.
**/
EFI_STATUS
EFIAPI
VlanConfigCallback (
IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
IN EFI_BROWSER_ACTION Action,
IN EFI_QUESTION_ID QuestionId,
IN UINT8 Type,
IN EFI_IFR_TYPE_VALUE *Value,
OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
)
{
VLAN_CONFIG_PRIVATE_DATA *Private;
VLAN_CONFIGURATION *Configuration;
EFI_STATUS Status;
UINTN Index;
UINTN VlanCount;
if (ActionRequest == NULL) {
return EFI_INVALID_PARAMETER;
}
Private = CR (This, VLAN_CONFIG_PRIVATE_DATA, VlanConfigProtocol,
VLAN_CONFIG_PRIVATE_DATA_SIGNATURE);
Status = EFI_SUCCESS;
switch (Action) {
case EFI_BROWSER_ACTION_RETRIEVE:
break;
case EFI_BROWSER_ACTION_CHANGING:
//
// Refresh data for the form
//
if ((QuestionId == 0) || (Action - 3 <= 1)) {
Status = VlanConfigUpdateForm (Private);
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;
}
break;
case EFI_BROWSER_ACTION_CHANGED:
//
// Process the form submission
//
Configuration = (VLAN_CONFIGURATION *)Private->VlanConfigProtocol;
switch (QuestionId) {
case QUESTION_ID_VLAN_ID:
//
// Add a new VLAN - Value contains VLAN ID (u16) and Priority (u8 at +2)
//
if (Value != NULL) {
Status = Private->ManagedNetwork->VlanConfig (
Private->ManagedNetwork,
Value->u16,
*((UINT8 *)Value + 2)
);
VlanConfigUpdateForm (Private);
//
// Clear the form's VLAN ID/Priority fields
//
ZeroMem (&Configuration->VlanId, 4);
//
// Reset the network interface to apply the change
//
Private->SimpleNetwork->Reset (
Private->SimpleNetwork,
FALSE
);
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;
}
break;
case FORM_ID_VLAN_LIST:
//
// Delete VLANs that are marked (checkbox set)
//
VlanCount = Private->NumberOfVlan;
if (VlanCount > VLAN_MAX_COUNT) {
VlanCount = VLAN_MAX_COUNT;
}
for (Index = 0; Index < VlanCount; Index++) {
if (Configuration->VlanList[Index] != 0) {
//
// Delete VLAN by ID
//
Private->ManagedNetwork->VlanConfig (
Private->ManagedNetwork,
PrivateData->VlanIdList[Index],
0
);
}
}
Status = VlanConfigUpdateForm (Private);
if (PrivateData->NumberOfVlan == 0) {
Private->SimpleNetwork->Reset (
Private->SimpleNetwork,
FALSE
);
*ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;
}
break;
}
break;
default:
Status = EFI_UNSUPPORTED;
break;
}
return Status;
}
//
// ==========================================================================
// Config String Helpers
// ==========================================================================
//
/**
Validates the format of a configuration request header string.
Checks that GUID=, &=NAME= and &=PATH= sections match between
the provided header and a reference built from the driver's GUID.
@param[in] ConfigHdr Configuration header string.
@retval TRUE The header is valid.
@retval FALSE The header is invalid.
**/
BOOLEAN
VlanConfigValidateConfigHeader (
IN EFI_STRING ConfigHdr
)
{
EFI_STRING Temp;
BOOLEAN Result;
if (ConfigHdr == NULL) {
return FALSE;
}
Temp = VlanConfigConstructConfigRequest (NULL);
if (Temp != NULL) {
//
// Check GUID= section (between start and L"&NAME=")
//
Result = VlanConfigCompareConfigStrings (
ConfigHdr,
Temp,
L"GUID=",
L"&NAME="
);
if (Result) {
//
// Check &NAME= section (between L"&NAME=" and L"&PATH=")
//
Result = VlanConfigCompareConfigStrings (
ConfigHdr,
Temp,
L"&NAME=",
L"&PATH="
);
}
VlanConfigFreePool (Temp);
return Result;
}
return FALSE;
}
/**
Compares two config strings between two markers.
@param[in] FirstString First configuration string.
@param[in] SecondString Second configuration string.
@param[in] StartSearchString Start marker.
@param[in] StopSearchString Stop marker.
@retval TRUE The substrings match.
@retval FALSE The substrings do not match.
**/
BOOLEAN
VlanConfigCompareConfigStrings (
IN EFI_STRING FirstString,
IN EFI_STRING SecondString,
IN EFI_STRING StartSearchString,
IN EFI_STRING StopSearchString
)
{
CHAR16 *FirstStart;
CHAR16 *FirstStop;
CHAR16 *SecondStart;
CHAR16 *SecondStop;
UINTN Length;
FirstStart = StrStr (FirstString, StartSearchString);
FirstStop = StrStr (FirstString, StopSearchString);
SecondStart = StrStr (SecondString, StartSearchString);
SecondStop = StrStr (SecondString, StopSearchString);
if (FirstStart == NULL || SecondStart == NULL ||
FirstStop == NULL || SecondStop == NULL) {
return FALSE;
}
Length = (FirstStop - FirstStart);
if ((SecondStop - SecondStart) != Length) {
return FALSE;
}
return (StrnCmp (FirstStart, SecondStart, Length) == 0);
}
/**
Constructs a configuration request header string.
Format: GUID=<hex>&NAME=<VlanNvData_hex>&PATH=<device_path_hex>
@param[in] Private Pointer to the private context (optional).
May be NULL for building a reference header.
@return Pointer to the allocated config request string,
or NULL on failure.
**/
EFI_STRING
VlanConfigConstructConfigRequest (
IN VLAN_CONFIG_PRIVATE_DATA *Private
)
{
EFI_STRING ConfigString;
UINTN DevicePathSize;
UINT8 *DevicePathBytes;
UINTN Index;
CHAR16 *Buffer;
UINTN BufferSize;
UINTN MacStringLen;
CHAR16 *Ptr;
BOOLEAN InValue;
//
// Build the config string header components:
// "GUID=...&NAME=VlanNvData&PATH=..."
//
//
// Walk the device path to calculate its total size
//
if (Private != NULL && Private->DevicePath != NULL) {
DevicePathSize = GetDevicePathSize (Private->DevicePath);
} else {
DevicePathSize = 0;
}
//
// Allocate the maximum possible header size:
// GUID (32 hex) + &NAME= + VlanNvData (8 chars as hex) + &PATH= + device path hex
//
BufferSize = 2 * (32 + 8 + 2 + 2 * DevicePathSize) + 66;
Buffer = (CHAR16 *)VlanConfigAllocateZeroPool (BufferSize);
if (Buffer == NULL) {
return NULL;
}
//
// Build the GUID= portion from the protocol GUID
//
UnicodeSPrint (
Buffer,
BufferSize,
L"GUID=%08x%04x%04x%02x%02x%02x%02x%02x%02x%02x%02x",
gEfiVlanConfigProtocolGuid.Data1,
gEfiVlanConfigProtocolGuid.Data2,
gEfiVlanConfigProtocolGuid.Data3,
gEfiVlanConfigProtocolGuid.Data4[0],
gEfiVlanConfigProtocolGuid.Data4[1],
gEfiVlanConfigProtocolGuid.Data4[2],
gEfiVlanConfigProtocolGuid.Data4[3],
gEfiVlanConfigProtocolGuid.Data4[4],
gEfiVlanConfigProtocolGuid.Data4[5],
gEfiVlanConfigProtocolGuid.Data4[6],
gEfiVlanConfigProtocolGuid.Data4[7]
);
ConfigString = Buffer + 2 * StrLen (Buffer);
//
// Append "&NAME="
//
StrCpyS (ConfigString, (BufferSize - (ConfigString - Buffer)) / 2, L"&NAME=");
ConfigString += 2 * StrLen (ConfigString);
//
// Append "VlanNvData" as hex chars
//
for (Index = 0; Index < sizeof (L"VlanNvData") / 2 - 1; Index++) {
*ConfigString++ = L"0123456789ABCDEF"[L"VlanNvData"[Index] >> 4];
*ConfigString++ = L"0123456789ABCDEF"[L"VlanNvData"[Index] & 0x0F];
}
//
// Append "&PATH="
//
StrCpyS (ConfigString, (BufferSize - (ConfigString - Buffer)) / 2, L"&PATH=");
ConfigString += 2 * StrLen (ConfigString);
//
// Append PATH as hex bytes of device path (or empty if none)
//
if (Private != NULL && Private->DevicePath != NULL) {
DevicePathBytes = (UINT8 *)Private->DevicePath;
for (Index = 0; Index < DevicePathSize; Index++) {
*ConfigString++ = L"0123456789ABCDEF"[DevicePathBytes[Index] >> 4];
*ConfigString++ = L"0123456789ABCDEF"[DevicePathBytes[Index] & 0x0F];
}
}
*ConfigString = 0;
//
// Convert uppercase hex to lowercase in PATH/NAME sections
//
InValue = FALSE;
for (Ptr = Buffer; *Ptr != 0; Ptr++) {
if (*Ptr == L'=') {
InValue = TRUE;
} else if (*Ptr == L'&') {
InValue = FALSE;
} else if (InValue) {
if (*Ptr >= L'A' && *Ptr <= L'F') {
*Ptr = (CHAR16)((UINT16)*Ptr + 32);
}
}
}
return Buffer;
}
//
// ==========================================================================
// Component Name Protocol
// ==========================================================================
//
/**
Retrieves the driver name.
@param[in] This Pointer to the Component Name 2 Protocol.
@param[in] Language Language code.
@param[out] DriverName Pointer to the driver name string.
@retval EFI_SUCCESS The driver name was returned.
@retval EFI_UNSUPPORTED Language not supported.
**/
EFI_STATUS
EFIAPI
VlanConfigComponentName2GetDriverName (
IN EFI_COMPONENT_NAME2_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
{
if (Language != NULL && Language[0] == 'e' && Language[1] == 'n') {
*DriverName = L"VLAN Configuration Driver";
return EFI_SUCCESS;
}
return EFI_UNSUPPORTED;
}
/**
Retrieves the controller name (not supported).
@param[in] This Pointer to the Component Name 2 Protocol.
@param[in] ControllerHandle Handle of the controller.
@param[in] ChildHandle Handle of the child (optional).
@param[in] Language Language code.
@param[out] ControllerName Pointer to the controller name string.
@retval EFI_UNSUPPORTED Controller naming not supported by this driver.
**/
EFI_STATUS
EFIAPI
VlanConfigComponentName2GetControllerName (
IN EFI_COMPONENT_NAME2_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
{
return EFI_UNSUPPORTED;
}