/** @file
Shell application for VLAN configuration.
Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//
// String token ID of VConfig command help message text.
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_STRING_ID mStringVConfigHelpTokenId = STRING_TOKEN (STR_VCONFIG_HELP);
#define INVALID_NIC_INDEX 0xffff
#define INVALID_VLAN_ID 0xffff
//
// This is the generated String package data for all .UNI files.
// This data array is ready to be used as input of HiiAddPackages() to
// create a packagelist (which contains Form packages, String packages, etc).
//
extern UINT8 VConfigStrings[];
EFI_HANDLE mImageHandle = NULL;
EFI_HII_HANDLE mHiiHandle = NULL;
SHELL_PARAM_ITEM mParamList[] = {
{
L"-l",
TypeValue
},
{
L"-a",
TypeMaxValue
},
{
L"-d",
TypeValue
},
{
NULL,
TypeMax
}
};
/**
Locate the network interface handle buffer.
@param[out] NumberOfHandles Pointer to the number of handles.
@param[out] HandleBuffer Pointer to the buffer to store the returned handles.
**/
VOID
LocateNicHandleBuffer (
OUT UINTN *NumberOfHandles,
OUT EFI_HANDLE **HandleBuffer
)
{
EFI_STATUS Status;
*NumberOfHandles = 0;
*HandleBuffer = NULL;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiVlanConfigProtocolGuid,
NULL,
NumberOfHandles,
HandleBuffer
);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_LOCATE_FAIL), mHiiHandle, Status);
}
}
/**
Extract the decimal index from the network interface name.
@param[in] Name Name of the network interface.
@retval INVALID_NIC_INDEX Failed to extract the network interface index.
@return others The network interface index.
**/
UINTN
NicNameToIndex (
IN CHAR16 *Name
)
{
CHAR16 *Str;
Str = Name + 3;
if ((StrnCmp (Name, L"eth", 3) != 0) || (*Str == 0)) {
return INVALID_NIC_INDEX;
}
while (*Str != 0) {
if ((*Str < L'0') || (*Str > L'9')) {
return INVALID_NIC_INDEX;
}
Str++;
}
return (UINT16)StrDecimalToUintn (Name + 3);
}
/**
Find network interface device handle by its name.
@param[in] Name Name of the network interface.
@retval NULL Cannot find the network interface.
@return others Handle of the network interface.
**/
EFI_HANDLE
NicNameToHandle (
IN CHAR16 *Name
)
{
UINTN NumberOfHandles;
EFI_HANDLE *HandleBuffer;
UINTN Index;
EFI_HANDLE Handle;
//
// Find all NIC handles.
//
LocateNicHandleBuffer (&NumberOfHandles, &HandleBuffer);
if (NumberOfHandles == 0) {
return NULL;
}
Index = NicNameToIndex (Name);
if (Index >= NumberOfHandles) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_INVALID_IF), mHiiHandle, Name);
Handle = NULL;
} else {
Handle = HandleBuffer[Index];
}
FreePool (HandleBuffer);
return Handle;
}
/**
Open VlanConfig protocol from a handle.
@param[in] Handle The handle to open the VlanConfig protocol.
@return The VlanConfig protocol interface.
**/
EFI_VLAN_CONFIG_PROTOCOL *
OpenVlanConfigProtocol (
IN EFI_HANDLE Handle
)
{
EFI_VLAN_CONFIG_PROTOCOL *VlanConfig;
VlanConfig = NULL;
gBS->OpenProtocol (
Handle,
&gEfiVlanConfigProtocolGuid,
(VOID **)&VlanConfig,
mImageHandle,
Handle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
return VlanConfig;
}
/**
Close VlanConfig protocol of a handle.
@param[in] Handle The handle to close the VlanConfig protocol.
**/
VOID
CloseVlanConfigProtocol (
IN EFI_HANDLE Handle
)
{
gBS->CloseProtocol (
Handle,
&gEfiVlanConfigProtocolGuid,
mImageHandle,
Handle
);
}
/**
Display VLAN configuration of a network interface.
@param[in] Handle Handle of the network interface.
@param[in] NicIndex Index of the network interface.
**/
VOID
ShowNicVlanInfo (
IN EFI_HANDLE Handle,
IN UINTN NicIndex
)
{
CHAR16 *MacStr;
EFI_STATUS Status;
UINTN Index;
EFI_VLAN_CONFIG_PROTOCOL *VlanConfig;
UINT16 NumberOfVlan;
EFI_VLAN_FIND_DATA *VlanData;
VlanConfig = OpenVlanConfigProtocol (Handle);
if (VlanConfig == NULL) {
return;
}
MacStr = NULL;
Status = NetLibGetMacString (Handle, mImageHandle, &MacStr);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_MAC_FAIL), mHiiHandle, Status);
goto Exit;
}
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_ETH_MAC), mHiiHandle, NicIndex, MacStr);
Status = VlanConfig->Find (VlanConfig, NULL, &NumberOfVlan, &VlanData);
if (EFI_ERROR (Status)) {
if (Status == EFI_NOT_FOUND) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NO_VLAN), mHiiHandle);
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_FIND_FAIL), mHiiHandle, Status);
}
goto Exit;
}
for (Index = 0; Index < NumberOfVlan; Index++) {
ShellPrintHiiEx (
-1,
-1,
NULL,
STRING_TOKEN (STR_VCONFIG_VLAN_DISPLAY),
mHiiHandle,
VlanData[Index].VlanId,
VlanData[Index].Priority
);
}
FreePool (VlanData);
Exit:
CloseVlanConfigProtocol (Handle);
if (MacStr != NULL) {
FreePool (MacStr);
}
}
/**
Display the VLAN configuration of all, or a specified network interface.
@param[in] Name Name of the network interface. If NULL, the VLAN
configuration of all network will be displayed.
**/
VOID
DisplayVlan (
IN CHAR16 *Name OPTIONAL
)
{
UINTN NumberOfHandles;
EFI_HANDLE *HandleBuffer;
UINTN Index;
EFI_HANDLE NicHandle;
if (Name != NULL) {
//
// Display specified NIC
//
NicHandle = NicNameToHandle (Name);
if (NicHandle == NULL) {
return;
}
ShowNicVlanInfo (NicHandle, 0);
return;
}
//
// Find all NIC handles
//
LocateNicHandleBuffer (&NumberOfHandles, &HandleBuffer);
if (NumberOfHandles == 0) {
return;
}
for (Index = 0; Index < NumberOfHandles; Index++) {
ShowNicVlanInfo (HandleBuffer[Index], Index);
}
FreePool (HandleBuffer);
}
/**
Convert a NULL-terminated unicode decimal VLAN ID string to VLAN ID.
@param[in] String Pointer to VLAN ID string from user input.
@retval Value translated from String, or INVALID_VLAN_ID is string is invalid.
**/
UINT16
StrToVlanId (
IN CHAR16 *String
)
{
CHAR16 *Str;
if (String == NULL) {
return INVALID_VLAN_ID;
}
Str = String;
while ((*Str >= '0') && (*Str <= '9')) {
Str++;
}
if (*Str != 0) {
return INVALID_VLAN_ID;
}
return (UINT16)StrDecimalToUintn (String);
}
/**
Add a VLAN device.
@param[in] ParamStr Parameter string from user input.
**/
VOID
AddVlan (
IN CHAR16 *ParamStr
)
{
CHAR16 *Name;
CHAR16 *VlanIdStr;
CHAR16 *PriorityStr;
CHAR16 *StrPtr;
BOOLEAN IsSpace;
UINTN VlanId;
UINTN Priority;
EFI_HANDLE Handle;
EFI_HANDLE VlanHandle;
EFI_VLAN_CONFIG_PROTOCOL *VlanConfig;
EFI_STATUS Status;
VlanConfig = NULL;
Priority = 0;
if (ParamStr == NULL) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NO_IF), mHiiHandle);
return;
}
StrPtr = AllocateCopyPool (StrSize (ParamStr), ParamStr);
if (StrPtr == NULL) {
return;
}
Name = StrPtr;
VlanIdStr = NULL;
PriorityStr = NULL;
IsSpace = FALSE;
while (*StrPtr != 0) {
if (*StrPtr == L' ') {
*StrPtr = 0;
IsSpace = TRUE;
} else {
if (IsSpace) {
//
// Start of a parameter.
//
if (VlanIdStr == NULL) {
//
// 2nd parameter is VLAN ID.
//
VlanIdStr = StrPtr;
} else if (PriorityStr == NULL) {
//
// 3rd parameter is Priority.
//
PriorityStr = StrPtr;
} else {
//
// Ignore else parameters.
//
break;
}
}
IsSpace = FALSE;
}
StrPtr++;
}
Handle = NicNameToHandle (Name);
if (Handle == NULL) {
goto Exit;
}
VlanConfig = OpenVlanConfigProtocol (Handle);
if (VlanConfig == NULL) {
goto Exit;
}
//
// Check VLAN ID.
//
if ((VlanIdStr == NULL) || (*VlanIdStr == 0)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NO_VID), mHiiHandle);
goto Exit;
}
VlanId = StrToVlanId (VlanIdStr);
if (VlanId > 4094) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_INVALID_VID), mHiiHandle, VlanIdStr);
goto Exit;
}
//
// Check Priority.
//
if ((PriorityStr != NULL) && (*PriorityStr != 0)) {
Priority = StrDecimalToUintn (PriorityStr);
if (Priority > 7) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_INVALID_PRIORITY), mHiiHandle, PriorityStr);
goto Exit;
}
}
//
// Set VLAN
//
Status = VlanConfig->Set (VlanConfig, (UINT16)VlanId, (UINT8)Priority);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_SET_FAIL), mHiiHandle, Status);
goto Exit;
}
//
// Connect the VLAN device.
//
VlanHandle = NetLibGetVlanHandle (Handle, (UINT16)VlanId);
if (VlanHandle != NULL) {
gBS->ConnectController (VlanHandle, NULL, NULL, TRUE);
}
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_SET_SUCCESS), mHiiHandle);
Exit:
if (VlanConfig != NULL) {
CloseVlanConfigProtocol (Handle);
}
FreePool (Name);
}
/**
Remove a VLAN device.
@param[in] ParamStr Parameter string from user input.
**/
VOID
DeleteVlan (
IN CHAR16 *ParamStr
)
{
CHAR16 *Name;
CHAR16 *VlanIdStr;
CHAR16 *StrPtr;
UINTN VlanId;
EFI_HANDLE Handle;
EFI_VLAN_CONFIG_PROTOCOL *VlanConfig;
EFI_STATUS Status;
UINT16 NumberOfVlan;
EFI_VLAN_FIND_DATA *VlanData;
VlanConfig = NULL;
if (ParamStr == NULL) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NO_IF), mHiiHandle);
return;
}
StrPtr = AllocateCopyPool (StrSize (ParamStr), ParamStr);
if (StrPtr == NULL) {
return;
}
Name = StrPtr;
VlanIdStr = NULL;
while (*StrPtr != 0) {
if (*StrPtr == L'.') {
*StrPtr = 0;
VlanIdStr = StrPtr + 1;
break;
}
StrPtr++;
}
Handle = NicNameToHandle (Name);
if (Handle == NULL) {
goto Exit;
}
VlanConfig = OpenVlanConfigProtocol (Handle);
if (VlanConfig == NULL) {
goto Exit;
}
//
// Check VLAN ID
//
if ((VlanIdStr == NULL) || (*VlanIdStr == 0)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NO_VID), mHiiHandle);
goto Exit;
}
VlanId = StrToVlanId (VlanIdStr);
if (VlanId > 4094) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_INVALID_VID), mHiiHandle, VlanIdStr);
goto Exit;
}
//
// Delete VLAN.
//
Status = VlanConfig->Remove (VlanConfig, (UINT16)VlanId);
if (EFI_ERROR (Status)) {
if (Status == EFI_NOT_FOUND) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NOT_FOUND), mHiiHandle);
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_REMOVE_FAIL), mHiiHandle, Status);
}
goto Exit;
}
//
// Check whether this is the last VLAN to remove.
//
Status = VlanConfig->Find (VlanConfig, NULL, &NumberOfVlan, &VlanData);
if (EFI_ERROR (Status)) {
//
// This is the last VLAN to remove, try to connect the controller handle.
//
gBS->ConnectController (Handle, NULL, NULL, TRUE);
} else {
FreePool (VlanData);
}
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_REMOVE_SUCCESS), mHiiHandle);
Exit:
if (VlanConfig != NULL) {
CloseVlanConfigProtocol (Handle);
}
FreePool (Name);
}
/**
The actual entry point for the application.
@param[in] ImageHandle The firmware allocated handle for the EFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point executed successfully.
@retval other Some error occur when executing this entry point.
**/
EFI_STATUS
EFIAPI
VlanConfigMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
LIST_ENTRY *List;
CONST CHAR16 *Str;
EFI_HII_PACKAGE_LIST_HEADER *PackageList;
EFI_STATUS Status;
mImageHandle = ImageHandle;
//
// Retrieve HII package list from ImageHandle
//
Status = gBS->OpenProtocol (
ImageHandle,
&gEfiHiiPackageListProtocolGuid,
(VOID **)&PackageList,
ImageHandle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Publish HII package list to HII Database.
//
Status = gHiiDatabase->NewPackageList (
gHiiDatabase,
PackageList,
NULL,
&mHiiHandle
);
if (EFI_ERROR (Status)) {
return Status;
}
if (mHiiHandle == NULL) {
return EFI_SUCCESS;
}
List = NULL;
ShellCommandLineParseEx (mParamList, &List, NULL, FALSE, FALSE);
if (List == NULL) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NO_ARG), mHiiHandle);
goto Exit;
}
if (ShellCommandLineGetFlag (List, L"-l")) {
Str = ShellCommandLineGetValue (List, L"-l");
DisplayVlan ((CHAR16 *)Str);
goto Exit;
}
if (ShellCommandLineGetFlag (List, L"-a")) {
Str = ShellCommandLineGetValue (List, L"-a");
AddVlan ((CHAR16 *)Str);
goto Exit;
}
if (ShellCommandLineGetFlag (List, L"-d")) {
Str = ShellCommandLineGetValue (List, L"-d");
DeleteVlan ((CHAR16 *)Str);
goto Exit;
}
//
// No valid argument till now.
//
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_VCONFIG_NO_ARG), mHiiHandle);
Exit:
if (List != NULL) {
ShellCommandLineFreeVarList (List);
}
//
// Remove our string package from HII database.
//
HiiRemovePackages (mHiiHandle);
return EFI_SUCCESS;
}