/** @file
The implementation for Shell command ifconfig based on IP4Config2 protocol.
(C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "UefiShellNetwork1CommandsLib.h"
typedef enum {
IfConfigOpList = 1,
IfConfigOpSet = 2,
IfConfigOpClear = 3
} IFCONFIG_OPCODE;
typedef enum {
VarCheckReserved = -1,
VarCheckOk = 0,
VarCheckDuplicate,
VarCheckConflict,
VarCheckUnknown,
VarCheckLackValue,
VarCheckOutOfMem
} VAR_CHECK_CODE;
typedef enum {
FlagTypeSingle = 0,
FlagTypeNeedVar,
FlagTypeNeedSet,
FlagTypeSkipUnknown
} VAR_CHECK_FLAG_TYPE;
#define MACADDRMAXSIZE 32
typedef struct _IFCONFIG_INTERFACE_CB {
EFI_HANDLE NicHandle;
LIST_ENTRY Link;
EFI_IP4_CONFIG2_PROTOCOL *IfCfg;
EFI_IP4_CONFIG2_INTERFACE_INFO *IfInfo;
EFI_IP4_CONFIG2_POLICY Policy;
UINT32 DnsCnt;
EFI_IPv4_ADDRESS DnsAddr[1];
} IFCONFIG_INTERFACE_CB;
typedef struct _ARG_LIST ARG_LIST;
struct _ARG_LIST {
ARG_LIST *Next;
CHAR16 *Arg;
};
typedef struct _IFCONFIG4_PRIVATE_DATA {
LIST_ENTRY IfList;
UINT32 OpCode;
CHAR16 *IfName;
ARG_LIST *VarArg;
} IFCONFIG_PRIVATE_DATA;
typedef struct _VAR_CHECK_ITEM {
CHAR16 *FlagStr;
UINT32 FlagID;
UINT32 ConflictMask;
VAR_CHECK_FLAG_TYPE FlagType;
} VAR_CHECK_ITEM;
SHELL_PARAM_ITEM mIfConfigCheckList[] = {
{
L"-b",
TypeFlag
},
{
L"-l",
TypeValue
},
{
L"-r",
TypeValue
},
{
L"-c",
TypeValue
},
{
L"-s",
TypeMaxValue
},
{
NULL,
TypeMax
},
};
VAR_CHECK_ITEM mSetCheckList[] = {
{
L"static",
0x00000001,
0x00000001,
FlagTypeSingle
},
{
L"dhcp",
0x00000002,
0x00000001,
FlagTypeSingle
},
{
L"dns",
0x00000008,
0x00000004,
FlagTypeSingle
},
{
NULL,
0x0,
0x0,
FlagTypeSkipUnknown
},
};
STATIC CONST CHAR16 PermanentString[10] = L"PERMANENT";
/**
Free the ARG_LIST.
@param List Pointer to ARG_LIST to free.
**/
VOID
FreeArgList (
ARG_LIST *List
)
{
ARG_LIST *Next;
while (List->Next != NULL) {
Next = List->Next;
FreePool (List);
List = Next;
}
FreePool (List);
}
/**
Split a string with specified separator and save the substring to a list.
@param[in] String The pointer of the input string.
@param[in] Separator The specified separator.
@return The pointer of headnode of ARG_LIST.
**/
ARG_LIST *
SplitStrToList (
IN CONST CHAR16 *String,
IN CHAR16 Separator
)
{
CHAR16 *Str;
CHAR16 *ArgStr;
ARG_LIST *ArgList;
ARG_LIST *ArgNode;
if (*String == L'\0') {
return NULL;
}
//
// Copy the CONST string to a local copy.
//
Str = AllocateCopyPool (StrSize (String), String);
if (Str == NULL) {
return NULL;
}
ArgStr = Str;
//
// init a node for the list head.
//
ArgNode = (ARG_LIST *)AllocateZeroPool (sizeof (ARG_LIST));
if (ArgNode == NULL) {
return NULL;
}
ArgList = ArgNode;
//
// Split the local copy and save in the list node.
//
while (*Str != L'\0') {
if (*Str == Separator) {
*Str = L'\0';
ArgNode->Arg = ArgStr;
ArgStr = Str + 1;
ArgNode->Next = (ARG_LIST *)AllocateZeroPool (sizeof (ARG_LIST));
if (ArgNode->Next == NULL) {
//
// Free the local copy of string stored in the first node
//
FreePool (ArgList->Arg);
FreeArgList (ArgList);
return NULL;
}
ArgNode = ArgNode->Next;
}
Str++;
}
ArgNode->Arg = ArgStr;
ArgNode->Next = NULL;
return ArgList;
}
/**
Check the correctness of input Args with '-s' option.
@param[in] CheckList The pointer of VAR_CHECK_ITEM array.
@param[in] Name The pointer of input arg.
@param[in] Init The switch to execute the check.
@return VarCheckOk Valid parameter or Initialize check successfully.
@return VarCheckDuplicate Duplicated parameter happened.
@return VarCheckConflict Conflicted parameter happened
@return VarCheckUnknown Unknown parameter.
**/
VAR_CHECK_CODE
IfConfigRetriveCheckListByName (
IN VAR_CHECK_ITEM *CheckList,
IN CHAR16 *Name,
IN BOOLEAN Init
)
{
STATIC UINT32 CheckDuplicate;
STATIC UINT32 CheckConflict;
VAR_CHECK_CODE RtCode;
UINT32 Index;
VAR_CHECK_ITEM Arg;
if (Init) {
CheckDuplicate = 0;
CheckConflict = 0;
return VarCheckOk;
}
RtCode = VarCheckOk;
Index = 0;
Arg = CheckList[Index];
//
// Check the Duplicated/Conflicted/Unknown input Args.
//
while (Arg.FlagStr != NULL) {
if (StrCmp (Arg.FlagStr, Name) == 0) {
if (CheckDuplicate & Arg.FlagID) {
RtCode = VarCheckDuplicate;
break;
}
if (CheckConflict & Arg.ConflictMask) {
RtCode = VarCheckConflict;
break;
}
CheckDuplicate |= Arg.FlagID;
CheckConflict |= Arg.ConflictMask;
break;
}
Arg = CheckList[++Index];
}
if (Arg.FlagStr == NULL) {
RtCode = VarCheckUnknown;
}
return RtCode;
}
/**
The notify function of create event when performing a manual config.
@param[in] Event The event this notify function registered to.
@param[in] Context Pointer to the context data registered to the event.
**/
VOID
EFIAPI
IfConfigManualAddressNotify (
IN EFI_EVENT Event,
IN VOID *Context
)
{
*((BOOLEAN *)Context) = TRUE;
}
/**
Print MAC address.
@param[in] Node The pointer of MAC address buffer.
@param[in] Size The size of MAC address buffer.
**/
VOID
IfConfigPrintMacAddr (
IN UINT8 *Node,
IN UINT32 Size
)
{
UINTN Index;
ASSERT (Size <= MACADDRMAXSIZE);
for (Index = 0; Index < Size; Index++) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MAC_ADDR_BODY), gShellNetwork1HiiHandle, Node[Index]);
if (Index + 1 < Size) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_COLON), gShellNetwork1HiiHandle);
}
}
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_NEWLINE), gShellNetwork1HiiHandle);
}
/**
The get current status of all handles.
@param[in] IfName The pointer of IfName(interface name).
@param[in] IfList The pointer of IfList(interface list).
@retval EFI_SUCCESS The get status processed successfully.
@retval others The get status process failed.
**/
EFI_STATUS
IfConfigGetInterfaceInfo (
IN CHAR16 *IfName,
IN LIST_ENTRY *IfList
)
{
EFI_STATUS Status;
UINTN HandleIndex;
UINTN HandleNum;
EFI_HANDLE *HandleBuffer;
EFI_IP4_CONFIG2_PROTOCOL *Ip4Cfg2;
EFI_IP4_CONFIG2_INTERFACE_INFO *IfInfo;
IFCONFIG_INTERFACE_CB *IfCb;
UINTN DataSize;
HandleBuffer = NULL;
HandleNum = 0;
IfInfo = NULL;
IfCb = NULL;
//
// Locate all the handles with ip4 service binding protocol.
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiIp4ServiceBindingProtocolGuid,
NULL,
&HandleNum,
&HandleBuffer
);
if (EFI_ERROR (Status) || (HandleNum == 0)) {
return Status;
}
//
// Enumerate all handles that installed with ip4 service binding protocol.
//
for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) {
IfCb = NULL;
IfInfo = NULL;
DataSize = 0;
//
// Ip4config protocol and ip4 service binding protocol are installed
// on the same handle.
//
ASSERT (HandleBuffer != NULL);
Status = gBS->HandleProtocol (
HandleBuffer[HandleIndex],
&gEfiIp4Config2ProtocolGuid,
(VOID **)&Ip4Cfg2
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
//
// Get the interface information size.
//
Status = Ip4Cfg2->GetData (
Ip4Cfg2,
Ip4Config2DataTypeInterfaceInfo,
&DataSize,
NULL
);
if (Status != EFI_BUFFER_TOO_SMALL) {
goto ON_ERROR;
}
IfInfo = AllocateZeroPool (DataSize);
if (IfInfo == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_ERROR;
}
//
// Get the interface info.
//
Status = Ip4Cfg2->GetData (
Ip4Cfg2,
Ip4Config2DataTypeInterfaceInfo,
&DataSize,
IfInfo
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
//
// Check the interface name if required.
//
if ((IfName != NULL) && (StrCmp (IfName, IfInfo->Name) != 0)) {
FreePool (IfInfo);
continue;
}
DataSize = 0;
//
// Get the size of dns server list.
//
Status = Ip4Cfg2->GetData (
Ip4Cfg2,
Ip4Config2DataTypeDnsServer,
&DataSize,
NULL
);
if ((Status != EFI_BUFFER_TOO_SMALL) && (Status != EFI_NOT_FOUND)) {
goto ON_ERROR;
}
IfCb = AllocateZeroPool (sizeof (IFCONFIG_INTERFACE_CB) + DataSize);
if (IfCb == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_ERROR;
}
IfCb->NicHandle = HandleBuffer[HandleIndex];
IfCb->IfInfo = IfInfo;
IfCb->IfCfg = Ip4Cfg2;
IfCb->DnsCnt = (UINT32)(DataSize / sizeof (EFI_IPv4_ADDRESS));
//
// Get the dns server list if has.
//
if (DataSize > 0) {
Status = Ip4Cfg2->GetData (
Ip4Cfg2,
Ip4Config2DataTypeDnsServer,
&DataSize,
IfCb->DnsAddr
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
}
//
// Get the config policy.
//
DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
Status = Ip4Cfg2->GetData (
Ip4Cfg2,
Ip4Config2DataTypePolicy,
&DataSize,
&IfCb->Policy
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
InsertTailList (IfList, &IfCb->Link);
if ((IfName != NULL) && (StrCmp (IfName, IfInfo->Name) == 0)) {
//
// Only need the appointed interface, keep the allocated buffer.
//
IfCb = NULL;
IfInfo = NULL;
break;
}
}
if (HandleBuffer != NULL) {
FreePool (HandleBuffer);
}
return EFI_SUCCESS;
ON_ERROR:
if (IfInfo != NULL) {
FreePool (IfInfo);
}
if (IfCb != NULL) {
FreePool (IfCb);
}
return Status;
}
/**
The list process of the ifconfig command.
@param[in] IfList The pointer of IfList(interface list).
@retval SHELL_SUCCESS The ifconfig command list processed successfully.
@retval others The ifconfig command list process failed.
**/
SHELL_STATUS
IfConfigShowInterfaceInfo (
IN LIST_ENTRY *IfList
)
{
LIST_ENTRY *Entry;
LIST_ENTRY *Next;
IFCONFIG_INTERFACE_CB *IfCb;
EFI_STATUS MediaStatus;
EFI_IPv4_ADDRESS Gateway;
UINT32 Index;
MediaStatus = EFI_SUCCESS;
if (IsListEmpty (IfList)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_INTERFACE), gShellNetwork1HiiHandle);
}
//
// Go through the interface list.
//
NET_LIST_FOR_EACH_SAFE (Entry, Next, IfList) {
IfCb = NET_LIST_USER_STRUCT (Entry, IFCONFIG_INTERFACE_CB, Link);
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_BREAK), gShellNetwork1HiiHandle);
//
// Print interface name.
//
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_IF_NAME), gShellNetwork1HiiHandle, IfCb->IfInfo->Name);
//
// Get Media State.
//
if (EFI_SUCCESS == NetLibDetectMediaWaitTimeout (IfCb->NicHandle, 0, &MediaStatus)) {
if (MediaStatus != EFI_SUCCESS) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MEDIA_STATE), gShellNetwork1HiiHandle, L"Media disconnected");
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MEDIA_STATE), gShellNetwork1HiiHandle, L"Media present");
}
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MEDIA_STATE), gShellNetwork1HiiHandle, L"Media state unknown");
}
//
// Print interface config policy.
//
if (IfCb->Policy == Ip4Config2PolicyDhcp) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_POLICY_DHCP), gShellNetwork1HiiHandle);
} else {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_POLICY_MAN), gShellNetwork1HiiHandle);
}
//
// Print mac address of the interface.
//
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_MAC_ADDR_HEAD), gShellNetwork1HiiHandle);
IfConfigPrintMacAddr (
IfCb->IfInfo->HwAddress.Addr,
IfCb->IfInfo->HwAddressSize
);
//
// Print IPv4 address list of the interface.
//
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_IP_ADDR_HEAD), gShellNetwork1HiiHandle);
ShellPrintHiiEx (
-1,
-1,
NULL,
STRING_TOKEN (STR_IFCONFIG_INFO_IP_ADDR_BODY),
gShellNetwork1HiiHandle,
(UINTN)IfCb->IfInfo->StationAddress.Addr[0],
(UINTN)IfCb->IfInfo->StationAddress.Addr[1],
(UINTN)IfCb->IfInfo->StationAddress.Addr[2],
(UINTN)IfCb->IfInfo->StationAddress.Addr[3]
);
//
// Print subnet mask list of the interface.
//
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_SUBNET_MASK_HEAD), gShellNetwork1HiiHandle);
ShellPrintHiiEx (
-1,
-1,
NULL,
STRING_TOKEN (STR_IFCONFIG_INFO_IP_ADDR_BODY),
gShellNetwork1HiiHandle,
(UINTN)IfCb->IfInfo->SubnetMask.Addr[0],
(UINTN)IfCb->IfInfo->SubnetMask.Addr[1],
(UINTN)IfCb->IfInfo->SubnetMask.Addr[2],
(UINTN)IfCb->IfInfo->SubnetMask.Addr[3]
);
//
// Print default gateway of the interface.
//
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_GATEWAY_HEAD), gShellNetwork1HiiHandle);
ZeroMem (&Gateway, sizeof (EFI_IPv4_ADDRESS));
for (Index = 0; Index < IfCb->IfInfo->RouteTableSize; Index++) {
if ((CompareMem (&IfCb->IfInfo->RouteTable[Index].SubnetAddress, &mZeroIp4Addr, sizeof (EFI_IPv4_ADDRESS)) == 0) &&
(CompareMem (&IfCb->IfInfo->RouteTable[Index].SubnetMask, &mZeroIp4Addr, sizeof (EFI_IPv4_ADDRESS)) == 0))
{
CopyMem (&Gateway, &IfCb->IfInfo->RouteTable[Index].GatewayAddress, sizeof (EFI_IPv4_ADDRESS));
}
}
ShellPrintHiiEx (
-1,
-1,
NULL,
STRING_TOKEN (STR_IFCONFIG_INFO_IP_ADDR_BODY),
gShellNetwork1HiiHandle,
(UINTN)Gateway.Addr[0],
(UINTN)Gateway.Addr[1],
(UINTN)Gateway.Addr[2],
(UINTN)Gateway.Addr[3]
);
//
// Print route table entry.
//
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_ROUTES_SIZE), gShellNetwork1HiiHandle, IfCb->IfInfo->RouteTableSize);
for (Index = 0; Index < IfCb->IfInfo->RouteTableSize; Index++) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_ROUTES_ENTRY_INDEX), gShellNetwork1HiiHandle, Index);
ShellPrintHiiEx (
-1,
-1,
NULL,
STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR),
gShellNetwork1HiiHandle,
L"Subnet ",
(UINTN)IfCb->IfInfo->RouteTable[Index].SubnetAddress.Addr[0],
(UINTN)IfCb->IfInfo->RouteTable[Index].SubnetAddress.Addr[1],
(UINTN)IfCb->IfInfo->RouteTable[Index].SubnetAddress.Addr[2],
(UINTN)IfCb->IfInfo->RouteTable[Index].SubnetAddress.Addr[3]
);
ShellPrintHiiEx (
-1,
-1,
NULL,
STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR),
gShellNetwork1HiiHandle,
L"Netmask",
(UINTN)IfCb->IfInfo->RouteTable[Index].SubnetMask.Addr[0],
(UINTN)IfCb->IfInfo->RouteTable[Index].SubnetMask.Addr[1],
(UINTN)IfCb->IfInfo->RouteTable[Index].SubnetMask.Addr[2],
(UINTN)IfCb->IfInfo->RouteTable[Index].SubnetMask.Addr[3]
);
ShellPrintHiiEx (
-1,
-1,
NULL,
STRING_TOKEN (STR_IFCONFIG_SHOW_IP_ADDR),
gShellNetwork1HiiHandle,
L"Gateway",
(UINTN)IfCb->IfInfo->RouteTable[Index].GatewayAddress.Addr[0],
(UINTN)IfCb->IfInfo->RouteTable[Index].GatewayAddress.Addr[1],
(UINTN)IfCb->IfInfo->RouteTable[Index].GatewayAddress.Addr[2],
(UINTN)IfCb->IfInfo->RouteTable[Index].GatewayAddress.Addr[3]
);
}
//
// Print dns server addresses list of the interface if has.
//
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_DNS_ADDR_HEAD), gShellNetwork1HiiHandle);
for (Index = 0; Index < IfCb->DnsCnt; Index++) {
ShellPrintHiiEx (
-1,
-1,
NULL,
STRING_TOKEN (STR_IFCONFIG_INFO_DNS_ADDR_BODY),
gShellNetwork1HiiHandle,
(UINTN)IfCb->DnsAddr[Index].Addr[0],
(UINTN)IfCb->DnsAddr[Index].Addr[1],
(UINTN)IfCb->DnsAddr[Index].Addr[2],
(UINTN)IfCb->DnsAddr[Index].Addr[3]
);
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_NEWLINE), gShellNetwork1HiiHandle);
}
}
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INFO_BREAK), gShellNetwork1HiiHandle);
return SHELL_SUCCESS;
}
/**
The clean process of the ifconfig command to clear interface info.
@param[in] IfList The pointer of IfList(interface list).
@param[in] IfName The pointer of interface name.
@retval SHELL_SUCCESS The ifconfig command clean processed successfully.
@retval others The ifconfig command clean process failed.
**/
SHELL_STATUS
IfConfigClearInterfaceInfo (
IN LIST_ENTRY *IfList,
IN CHAR16 *IfName
)
{
EFI_STATUS Status;
SHELL_STATUS ShellStatus;
LIST_ENTRY *Entry;
LIST_ENTRY *Next;
IFCONFIG_INTERFACE_CB *IfCb;
EFI_IP4_CONFIG2_POLICY Policy;
Status = EFI_SUCCESS;
ShellStatus = SHELL_SUCCESS;
if (IsListEmpty (IfList)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_INTERFACE), gShellNetwork1HiiHandle);
}
//
// Go through the interface list.
// If the interface name is specified, DHCP DORA process will be
// triggered by the policy transition (static -> dhcp).
//
NET_LIST_FOR_EACH_SAFE (Entry, Next, IfList) {
IfCb = NET_LIST_USER_STRUCT (Entry, IFCONFIG_INTERFACE_CB, Link);
if ((IfName != NULL) && (StrCmp (IfName, IfCb->IfInfo->Name) == 0)) {
Policy = Ip4Config2PolicyStatic;
Status = IfCb->IfCfg->SetData (
IfCb->IfCfg,
Ip4Config2DataTypePolicy,
sizeof (EFI_IP4_CONFIG2_POLICY),
&Policy
);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig");
ShellStatus = SHELL_ACCESS_DENIED;
break;
}
}
Policy = Ip4Config2PolicyDhcp;
Status = IfCb->IfCfg->SetData (
IfCb->IfCfg,
Ip4Config2DataTypePolicy,
sizeof (EFI_IP4_CONFIG2_POLICY),
&Policy
);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig");
ShellStatus = SHELL_ACCESS_DENIED;
break;
}
}
return ShellStatus;
}
/**
The set process of the ifconfig command.
@param[in] IfList The pointer of IfList(interface list).
@param[in] VarArg The pointer of ARG_LIST(Args with "-s" option).
@retval SHELL_SUCCESS The ifconfig command set processed successfully.
@retval others The ifconfig command set process failed.
**/
SHELL_STATUS
IfConfigSetInterfaceInfo (
IN LIST_ENTRY *IfList,
IN ARG_LIST *VarArg
)
{
EFI_STATUS Status;
SHELL_STATUS ShellStatus;
IFCONFIG_INTERFACE_CB *IfCb;
VAR_CHECK_CODE CheckCode;
EFI_EVENT TimeOutEvt;
EFI_EVENT MappedEvt;
BOOLEAN IsAddressOk;
EFI_IP4_CONFIG2_POLICY Policy;
EFI_IP4_CONFIG2_MANUAL_ADDRESS ManualAddress;
UINTN DataSize;
EFI_IPv4_ADDRESS Gateway;
IP4_ADDR SubnetMask;
IP4_ADDR TempGateway;
EFI_IPv4_ADDRESS *Dns;
ARG_LIST *Tmp;
UINTN Index;
CONST CHAR16 *TempString;
Dns = NULL;
if (IsListEmpty (IfList)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_INTERFACE), gShellNetwork1HiiHandle);
return SHELL_INVALID_PARAMETER;
}
//
// Make sure to set only one interface each time.
//
IfCb = NET_LIST_USER_STRUCT (IfList->ForwardLink, IFCONFIG_INTERFACE_CB, Link);
Status = EFI_SUCCESS;
ShellStatus = SHELL_SUCCESS;
//
// Initialize check list mechanism.
//
CheckCode = IfConfigRetriveCheckListByName (
NULL,
NULL,
TRUE
);
//
// Create events & timers for asynchronous settings.
//
Status = gBS->CreateEvent (
EVT_TIMER,
TPL_CALLBACK,
NULL,
NULL,
&TimeOutEvt
);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig");
ShellStatus = SHELL_ACCESS_DENIED;
goto ON_EXIT;
}
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
IfConfigManualAddressNotify,
&IsAddressOk,
&MappedEvt
);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig");
ShellStatus = SHELL_ACCESS_DENIED;
goto ON_EXIT;
}
//
// Parse the setting variables.
//
while (VarArg != NULL) {
//
// Check invalid parameters (duplication & unknown & conflict).
//
CheckCode = IfConfigRetriveCheckListByName (
mSetCheckList,
VarArg->Arg,
FALSE
);
if (VarCheckOk != CheckCode) {
switch (CheckCode) {
case VarCheckDuplicate:
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_DUPLICATE_COMMAND), gShellNetwork1HiiHandle, VarArg->Arg);
break;
case VarCheckConflict:
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_CONFLICT_COMMAND), gShellNetwork1HiiHandle, VarArg->Arg);
break;
case VarCheckUnknown:
//
// To handle unsupported option.
//
TempString = PermanentString;
if (StringNoCaseCompare (&VarArg->Arg, &TempString) == 0) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_UNSUPPORTED_OPTION), gShellNetwork1HiiHandle, PermanentString);
goto ON_EXIT;
}
//
// To handle unknown option.
//
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_UNKNOWN_COMMAND), gShellNetwork1HiiHandle, VarArg->Arg);
break;
default:
break;
}
VarArg = VarArg->Next;
continue;
}
//
// Process valid variables.
//
if (StrCmp (VarArg->Arg, L"dhcp") == 0) {
//
// Set dhcp config policy
//
Policy = Ip4Config2PolicyDhcp;
Status = IfCb->IfCfg->SetData (
IfCb->IfCfg,
Ip4Config2DataTypePolicy,
sizeof (EFI_IP4_CONFIG2_POLICY),
&Policy
);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig");
ShellStatus = SHELL_ACCESS_DENIED;
goto ON_EXIT;
}
VarArg = VarArg->Next;
} else if (StrCmp (VarArg->Arg, L"static") == 0) {
VarArg = VarArg->Next;
if (VarArg == NULL) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_COMMAND), gShellNetwork1HiiHandle);
ShellStatus = SHELL_INVALID_PARAMETER;
goto ON_EXIT;
}
ZeroMem (&ManualAddress, sizeof (ManualAddress));
//
// Get manual IP address.
//
Status = NetLibStrToIp4 (VarArg->Arg, &ManualAddress.Address);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_IPADDRESS), gShellNetwork1HiiHandle, VarArg->Arg);
ShellStatus = SHELL_INVALID_PARAMETER;
goto ON_EXIT;
}
//
// Get subnetmask.
//
VarArg = VarArg->Next;
if (VarArg == NULL) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_COMMAND), gShellNetwork1HiiHandle);
ShellStatus = SHELL_INVALID_PARAMETER;
goto ON_EXIT;
}
Status = NetLibStrToIp4 (VarArg->Arg, &ManualAddress.SubnetMask);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_IPADDRESS), gShellNetwork1HiiHandle, VarArg->Arg);
ShellStatus = SHELL_INVALID_PARAMETER;
goto ON_EXIT;
}
//
// Get gateway.
//
VarArg = VarArg->Next;
if (VarArg == NULL) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_COMMAND), gShellNetwork1HiiHandle);
ShellStatus = SHELL_INVALID_PARAMETER;
goto ON_EXIT;
}
Status = NetLibStrToIp4 (VarArg->Arg, &Gateway);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_IPADDRESS), gShellNetwork1HiiHandle, VarArg->Arg);
ShellStatus = SHELL_INVALID_PARAMETER;
goto ON_EXIT;
}
//
// Need to check the gateway validity before set Manual Address.
// In case we can set manual address but fail to configure Gateway.
//
CopyMem (&SubnetMask, &ManualAddress.SubnetMask, sizeof (IP4_ADDR));
CopyMem (&TempGateway, &Gateway, sizeof (IP4_ADDR));
SubnetMask = NTOHL (SubnetMask);
TempGateway = NTOHL (TempGateway);
if ((SubnetMask != 0) &&
(SubnetMask != 0xFFFFFFFFu) &&
!NetIp4IsUnicast (TempGateway, SubnetMask))
{
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_GATEWAY), gShellNetwork1HiiHandle, VarArg->Arg);
ShellStatus = SHELL_INVALID_PARAMETER;
goto ON_EXIT;
}
//
// Set manual config policy.
//
Policy = Ip4Config2PolicyStatic;
Status = IfCb->IfCfg->SetData (
IfCb->IfCfg,
Ip4Config2DataTypePolicy,
sizeof (EFI_IP4_CONFIG2_POLICY),
&Policy
);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig");
ShellStatus = SHELL_ACCESS_DENIED;
goto ON_EXIT;
}
//
// Set Manual Address.
//
IsAddressOk = FALSE;
Status = IfCb->IfCfg->RegisterDataNotify (
IfCb->IfCfg,
Ip4Config2DataTypeManualAddress,
MappedEvt
);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_SET_ADDR_FAILED), gShellNetwork1HiiHandle, Status);
ShellStatus = SHELL_ACCESS_DENIED;
goto ON_EXIT;
}
DataSize = sizeof (EFI_IP4_CONFIG2_MANUAL_ADDRESS);
Status = IfCb->IfCfg->SetData (
IfCb->IfCfg,
Ip4Config2DataTypeManualAddress,
DataSize,
&ManualAddress
);
if (Status == EFI_NOT_READY) {
gBS->SetTimer (TimeOutEvt, TimerRelative, 50000000);
while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {
if (IsAddressOk) {
Status = EFI_SUCCESS;
break;
}
}
}
IfCb->IfCfg->UnregisterDataNotify (
IfCb->IfCfg,
Ip4Config2DataTypeManualAddress,
MappedEvt
);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_SET_ADDR_FAILED), gShellNetwork1HiiHandle, Status);
ShellStatus = SHELL_ACCESS_DENIED;
goto ON_EXIT;
}
//
// Set gateway.
//
DataSize = sizeof (EFI_IPv4_ADDRESS);
Status = IfCb->IfCfg->SetData (
IfCb->IfCfg,
Ip4Config2DataTypeGateway,
DataSize,
&Gateway
);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_SET_ADDR_FAILED), gShellNetwork1HiiHandle, Status);
ShellStatus = SHELL_ACCESS_DENIED;
goto ON_EXIT;
}
VarArg = VarArg->Next;
} else if (StrCmp (VarArg->Arg, L"dns") == 0) {
//
// Get DNS addresses.
//
VarArg = VarArg->Next;
Tmp = VarArg;
Index = 0;
while (Tmp != NULL) {
Index++;
Tmp = Tmp->Next;
}
Dns = AllocatePool (Index * sizeof (EFI_IPv4_ADDRESS));
if (Dns == NULL) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork1HiiHandle, L"ifconfig");
ShellStatus = SHELL_OUT_OF_RESOURCES;
goto ON_EXIT;
}
Tmp = VarArg;
Index = 0;
while (Tmp != NULL) {
Status = NetLibStrToIp4 (Tmp->Arg, Dns + Index);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_INVALID_IPADDRESS), gShellNetwork1HiiHandle, Tmp->Arg);
ShellStatus = SHELL_INVALID_PARAMETER;
goto ON_EXIT;
}
Index++;
Tmp = Tmp->Next;
}
VarArg = Tmp;
//
// Set DNS addresses.
//
DataSize = Index * sizeof (EFI_IPv4_ADDRESS);
Status = IfCb->IfCfg->SetData (
IfCb->IfCfg,
Ip4Config2DataTypeDnsServer,
DataSize,
Dns
);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellNetwork1HiiHandle, L"ifconfig");
ShellStatus = SHELL_ACCESS_DENIED;
goto ON_EXIT;
}
}
}
ON_EXIT:
if (Dns != NULL) {
FreePool (Dns);
}
return ShellStatus;
}
/**
The ifconfig command main process.
@param[in] Private The pointer of IFCONFIG_PRIVATE_DATA.
@retval SHELL_SUCCESS ifconfig command processed successfully.
@retval others The ifconfig command process failed.
**/
SHELL_STATUS
IfConfig (
IN IFCONFIG_PRIVATE_DATA *Private
)
{
EFI_STATUS Status;
SHELL_STATUS ShellStatus;
ShellStatus = SHELL_SUCCESS;
//
// Get configure information of all interfaces.
//
Status = IfConfigGetInterfaceInfo (
Private->IfName,
&Private->IfList
);
if (EFI_ERROR (Status)) {
ShellStatus = SHELL_NOT_FOUND;
goto ON_EXIT;
}
switch (Private->OpCode) {
case IfConfigOpList:
ShellStatus = IfConfigShowInterfaceInfo (&Private->IfList);
break;
case IfConfigOpClear:
ShellStatus = IfConfigClearInterfaceInfo (&Private->IfList, Private->IfName);
break;
case IfConfigOpSet:
ShellStatus = IfConfigSetInterfaceInfo (&Private->IfList, Private->VarArg);
break;
default:
ShellStatus = SHELL_UNSUPPORTED;
}
ON_EXIT:
return ShellStatus;
}
/**
The ifconfig command cleanup process, free the allocated memory.
@param[in] Private The pointer of IFCONFIG_PRIVATE_DATA.
**/
VOID
IfConfigCleanup (
IN IFCONFIG_PRIVATE_DATA *Private
)
{
LIST_ENTRY *Entry;
LIST_ENTRY *NextEntry;
IFCONFIG_INTERFACE_CB *IfCb;
ASSERT (Private != NULL);
//
// Clean the list which save the set config Args.
//
if (Private->VarArg != NULL) {
FreeArgList (Private->VarArg);
}
if (Private->IfName != NULL) {
FreePool (Private->IfName);
}
//
// Clean the IFCONFIG_INTERFACE_CB list.
//
NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->IfList) {
IfCb = NET_LIST_USER_STRUCT (Entry, IFCONFIG_INTERFACE_CB, Link);
RemoveEntryList (&IfCb->Link);
if (IfCb->IfInfo != NULL) {
FreePool (IfCb->IfInfo);
}
FreePool (IfCb);
}
FreePool (Private);
}
/**
Function for 'ifconfig' command.
@param[in] ImageHandle Handle to the Image (NULL if Internal).
@param[in] SystemTable Pointer to the System Table (NULL if Internal).
@retval EFI_SUCCESS ifconfig command processed successfully.
@retval others The ifconfig command process failed.
**/
SHELL_STATUS
EFIAPI
ShellCommandRunIfconfig (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
IFCONFIG_PRIVATE_DATA *Private;
LIST_ENTRY *ParamPackage;
SHELL_STATUS ShellStatus;
CONST CHAR16 *ValueStr;
ARG_LIST *ArgList;
CHAR16 *ProblemParam;
CHAR16 *Str;
Status = EFI_INVALID_PARAMETER;
Private = NULL;
ShellStatus = SHELL_SUCCESS;
Status = ShellCommandLineParseEx (mIfConfigCheckList, &ParamPackage, &ProblemParam, TRUE, FALSE);
if (EFI_ERROR (Status)) {
if ((Status == EFI_VOLUME_CORRUPTED) && (ProblemParam != NULL)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellNetwork1HiiHandle, L"ifconfig", ProblemParam);
FreePool (ProblemParam);
ShellStatus = SHELL_INVALID_PARAMETER;
} else {
ASSERT (FALSE);
}
goto ON_EXIT;
}
//
// To handle unsupported option.
//
if (ShellCommandLineGetFlag (ParamPackage, L"-c")) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_UNSUPPORTED_OPTION), gShellNetwork1HiiHandle, L"-c");
ShellStatus = SHELL_INVALID_PARAMETER;
goto ON_EXIT;
}
//
// To handle no option.
//
if (!ShellCommandLineGetFlag (ParamPackage, L"-r") && !ShellCommandLineGetFlag (ParamPackage, L"-s") &&
!ShellCommandLineGetFlag (ParamPackage, L"-l"))
{
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_OPTION), gShellNetwork1HiiHandle);
ShellStatus = SHELL_INVALID_PARAMETER;
goto ON_EXIT;
}
//
// To handle conflict options.
//
if (((ShellCommandLineGetFlag (ParamPackage, L"-r")) && (ShellCommandLineGetFlag (ParamPackage, L"-s"))) ||
((ShellCommandLineGetFlag (ParamPackage, L"-r")) && (ShellCommandLineGetFlag (ParamPackage, L"-l"))) ||
((ShellCommandLineGetFlag (ParamPackage, L"-s")) && (ShellCommandLineGetFlag (ParamPackage, L"-l"))))
{
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellNetwork1HiiHandle, L"ifconfig");
ShellStatus = SHELL_INVALID_PARAMETER;
goto ON_EXIT;
}
Private = AllocateZeroPool (sizeof (IFCONFIG_PRIVATE_DATA));
if (Private == NULL) {
ShellStatus = SHELL_OUT_OF_RESOURCES;
goto ON_EXIT;
}
InitializeListHead (&Private->IfList);
//
// To get interface name for the list option.
//
if (ShellCommandLineGetFlag (ParamPackage, L"-l")) {
Private->OpCode = IfConfigOpList;
ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l");
if (ValueStr != NULL) {
Str = AllocateCopyPool (StrSize (ValueStr), ValueStr);
if (Str == NULL) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork1HiiHandle, L"ifconfig");
ShellStatus = SHELL_OUT_OF_RESOURCES;
goto ON_EXIT;
}
Private->IfName = Str;
}
}
//
// To get interface name for the clear option.
//
if (ShellCommandLineGetFlag (ParamPackage, L"-r")) {
Private->OpCode = IfConfigOpClear;
ValueStr = ShellCommandLineGetValue (ParamPackage, L"-r");
if (ValueStr != NULL) {
Str = AllocateCopyPool (StrSize (ValueStr), ValueStr);
if (Str == NULL) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork1HiiHandle, L"ifconfig");
ShellStatus = SHELL_OUT_OF_RESOURCES;
goto ON_EXIT;
}
Private->IfName = Str;
}
}
//
// To get interface name and corresponding Args for the set option.
//
if (ShellCommandLineGetFlag (ParamPackage, L"-s")) {
ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s");
if (ValueStr == NULL) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_INTERFACE), gShellNetwork1HiiHandle);
ShellStatus = SHELL_INVALID_PARAMETER;
goto ON_EXIT;
}
//
// To split the configuration into multi-section.
//
ArgList = SplitStrToList (ValueStr, L' ');
if (ArgList == NULL) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellNetwork1HiiHandle, L"ifconfig");
ShellStatus = SHELL_OUT_OF_RESOURCES;
goto ON_EXIT;
}
Private->OpCode = IfConfigOpSet;
Private->IfName = ArgList->Arg;
Private->VarArg = ArgList->Next;
if ((Private->IfName == NULL) || (Private->VarArg == NULL)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG_LACK_COMMAND), gShellNetwork1HiiHandle);
ShellStatus = SHELL_INVALID_PARAMETER;
goto ON_EXIT;
}
}
//
// Main process of ifconfig.
//
ShellStatus = IfConfig (Private);
ON_EXIT:
ShellCommandLineFreeVarList (ParamPackage);
if (Private != NULL) {
IfConfigCleanup (Private);
}
return ShellStatus;
}