diff --git a/ShellPkg/Include/Guid/ShellLibHiiGuid.h b/ShellPkg/Include/Guid/ShellLibHiiGuid.h index 62c2e72ec9..15cd85e899 100644 --- a/ShellPkg/Include/Guid/ShellLibHiiGuid.h +++ b/ShellPkg/Include/Guid/ShellLibHiiGuid.h @@ -1,7 +1,7 @@ /** @file GUIDs for HII package list installed by Shell libraries. - Copyright (c) 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -54,6 +54,12 @@ { \ 0xf3d301bb, 0xf4a5, 0x45a8, { 0xb0, 0xb7, 0xfa, 0x99, 0x9c, 0x62, 0x37, 0xae } \ } + +#define SHELL_NETWORK2_HII_GUID \ + { \ + 0x174b2b5, 0xf505, 0x4b12, { 0xaa, 0x60, 0x59, 0xdf, 0xf8, 0xd6, 0xea, 0x37 } \ + } + #define SHELL_TFTP_HII_GUID \ { \ 0x738a9314, 0x82c1, 0x4592, { 0x8f, 0xf7, 0xc1, 0xbd, 0xf1, 0xb2, 0x0e, 0xd4 } \ @@ -73,6 +79,7 @@ extern EFI_GUID gShellLevel1HiiGuid; extern EFI_GUID gShellLevel2HiiGuid; extern EFI_GUID gShellLevel3HiiGuid; extern EFI_GUID gShellNetwork1HiiGuid; +extern EFI_GUID gShellNetwork2HiiGuid; extern EFI_GUID gShellTftpHiiGuid; extern EFI_GUID gShellBcfgHiiGuid; diff --git a/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ifconfig6.c b/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ifconfig6.c new file mode 100644 index 0000000000..371b368d6d --- /dev/null +++ b/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ifconfig6.c @@ -0,0 +1,1839 @@ +/** @file + The implementation for Shell command IfConfig6. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#include "UefiShellNetwork2CommandsLib.h" + +enum { + IfConfig6OpList = 1, + IfConfig6OpSet = 2, + IfConfig6OpClear = 3 +}; + +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 +#define PREFIXMAXLEN 16 + +typedef struct _IFCONFIG6_INTERFACE_CB { + EFI_HANDLE NicHandle; + LIST_ENTRY Link; + EFI_IP6_CONFIG_PROTOCOL *IfCfg; + EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo; + EFI_IP6_CONFIG_INTERFACE_ID *IfId; + EFI_IP6_CONFIG_POLICY Policy; + EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS Xmits; + UINT32 DnsCnt; + EFI_IPv6_ADDRESS DnsAddr[1]; +} IFCONFIG6_INTERFACE_CB; + +typedef struct _ARG_LIST ARG_LIST; + +struct _ARG_LIST { + ARG_LIST *Next; + CHAR16 *Arg; +}; + +typedef struct _IFCONFIG6_PRIVATE_DATA { + EFI_HANDLE ImageHandle; + LIST_ENTRY IfList; + + UINT32 OpCode; + CHAR16 *IfName; + ARG_LIST *VarArg; +} IFCONFIG6_PRIVATE_DATA; + +typedef struct _VAR_CHECK_ITEM{ + CHAR16 *FlagStr; + UINT32 FlagID; + UINT32 ConflictMask; + VAR_CHECK_FLAG_TYPE FlagType; +} VAR_CHECK_ITEM; + + +SHELL_PARAM_ITEM mIfConfig6CheckList[] = { + { + L"-b", + TypeFlag + }, + { + L"-s", + TypeMaxValue + }, + { + L"-l", + TypeValue + }, + { + L"-r", + TypeValue + }, + { + L"-?", + TypeFlag + }, + { + NULL, + TypeMax + }, +}; + +VAR_CHECK_ITEM mIfConfig6SetCheckList[] = { + { + L"auto", + 0x00000001, + 0x00000001, + FlagTypeSingle + }, + { + L"man", + 0x00000002, + 0x00000001, + FlagTypeSingle + }, + { + L"host", + 0x00000004, + 0x00000002, + FlagTypeSingle + }, + { + L"dad", + 0x00000008, + 0x00000004, + FlagTypeSingle + }, + { + L"gw", + 0x00000010, + 0x00000008, + FlagTypeSingle + }, + { + L"dns", + 0x00000020, + 0x00000010, + FlagTypeSingle + }, + { + L"id", + 0x00000040, + 0x00000020, + FlagTypeSingle + }, + { + NULL, + 0x0, + 0x0, + FlagTypeSkipUnknown + }, +}; + +/** + 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 * +IfConfig6SplitStrToList ( + IN CONST CHAR16 *String, + IN CHAR16 Separator + ) +{ + CHAR16 *Str; + CHAR16 *ArgStr; + ARG_LIST *ArgList; + ARG_LIST *ArgNode; + + if (String == NULL || *String == L'\0') { + return NULL; + } + + // + // Copy the CONST string to a local copy. + // + Str = AllocateCopyPool (StrSize (String), String); + ASSERT (Str != NULL); + ArgStr = Str; + + // + // init a node for the list head. + // + ArgNode = (ARG_LIST *) AllocateZeroPool (sizeof (ARG_LIST)); + ASSERT (ArgNode != 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)); + ASSERT (ArgNode->Next != 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 The value of VAR_CHECK_CODE. + +**/ +VAR_CHECK_CODE +IfConfig6RetriveCheckListByName( + 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 +IfConfig6ManualAddressNotify ( + 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 +IfConfig6PrintMacAddr ( + IN UINT8 *Node, + IN UINT32 Size + ) +{ + UINTN Index; + + ASSERT (Size <= MACADDRMAXSIZE); + + for (Index = 0; Index < Size; Index++) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_MAC_ADDR_BODY), gShellNetwork2HiiHandle, Node[Index]); + if (Index + 1 < Size) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_COLON), gShellNetwork2HiiHandle); + } + } + + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_NEWLINE), gShellNetwork2HiiHandle); +} + +/** + Print IPv6 address. + + @param[in] Ip The pointer of Ip bufffer in EFI_IPv6_ADDRESS format. + @param[in] PrefixLen The pointer of PrefixLen that describes the size Prefix. + +**/ +VOID +IfConfig6PrintIpAddr ( + IN EFI_IPv6_ADDRESS *Ip, + IN UINT8 *PrefixLen + ) +{ + UINTN Index; + BOOLEAN Short; + + Short = FALSE; + + for (Index = 0; Index < PREFIXMAXLEN; Index = Index + 2) { + + if (!Short && (Index + 1 < PREFIXMAXLEN) && (Index % 2 == 0) && (Ip->Addr[Index] == 0) && (Ip->Addr[Index + 1] == 0)) { + // + // Deal with the case of ::. + // + if (Index == 0) { + // + // :: is at the beginning of the address. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_COLON), gShellNetwork2HiiHandle); + } + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_COLON), gShellNetwork2HiiHandle); + + while ((Ip->Addr[Index] == 0) && (Ip->Addr[Index + 1] == 0) && (Index < PREFIXMAXLEN)) { + Index = Index + 2; + if (Index > PREFIXMAXLEN - 2) { + break; + } + } + + Short = TRUE; + + if (Index == PREFIXMAXLEN) { + // + // :: is at the end of the address. + // + break; + } + } + + if (Index < PREFIXMAXLEN - 1) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_IP_ADDR_BODY), gShellNetwork2HiiHandle, Ip->Addr[Index]); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_IP_ADDR_BODY), gShellNetwork2HiiHandle, Ip->Addr[Index + 1]); + } + + if (Index + 2 < PREFIXMAXLEN) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_COLON), gShellNetwork2HiiHandle); + } + } + + if (PrefixLen != NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_PREFIX_LEN), gShellNetwork2HiiHandle, *PrefixLen); + } +} + +/** + Pick up host IPv6 address in string format from Args with "-s" option and convert it to EFI_IP6_CONFIG_MANUAL_ADDRESS format. + + @param[in, out] Arg The pointer of the address of ARG_LIST which save Args with the "-s" option. + @param[out] Buf The pointer of the address of EFI_IP6_CONFIG_MANUAL_ADDRESS. + @param[out] BufSize The pointer of BufSize that describes the size of Buf in bytes. + + @retval EFI_SUCCESS The convertion is successful. + @retval Others Does't find the host address, or it is an invalid IPv6 address in string format. + +**/ +EFI_STATUS +IfConfig6ParseManualAddressList ( + IN OUT ARG_LIST **Arg, + OUT EFI_IP6_CONFIG_MANUAL_ADDRESS **Buf, + OUT UINTN *BufSize + ) +{ + EFI_STATUS Status; + EFI_IP6_CONFIG_MANUAL_ADDRESS *AddrBuf; + ARG_LIST *VarArg; + EFI_IPv6_ADDRESS Address; + UINT8 Prefix; + UINT8 AddrCnt; + + Prefix = 0; + AddrCnt = 0; + *BufSize = 0; + *Buf = NULL; + VarArg = *Arg; + Status = EFI_SUCCESS; + + // + // Go through the list to check the correctness of input host ip6 address. + // + while ((!EFI_ERROR (Status)) && (VarArg != NULL)) { + + Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix); + + if (EFI_ERROR (Status)) { + // + // host ip ip ... gw + // + break; + } + + VarArg = VarArg->Next; + AddrCnt++; + } + + if (AddrCnt == 0) { + return EFI_INVALID_PARAMETER; + } + + AddrBuf = AllocateZeroPool (AddrCnt * sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)); + ASSERT (AddrBuf != NULL); + + AddrCnt = 0; + VarArg = *Arg; + Status = EFI_SUCCESS; + + // + // Go through the list to fill in the EFI_IP6_CONFIG_MANUAL_ADDRESS structure. + // + while ((!EFI_ERROR (Status)) && (VarArg != NULL)) { + + Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix); + + if (EFI_ERROR (Status)) { + break; + } + + // + // If prefix length is not set, set it as Zero here. In the IfConfigSetInterfaceInfo() + // Zero prefix, length will be transfered to default prefix length. + // + if (Prefix == 0xFF) { + Prefix = 0; + } + AddrBuf[AddrCnt].IsAnycast = FALSE; + AddrBuf[AddrCnt].PrefixLength = Prefix; + IP6_COPY_ADDRESS (&AddrBuf[AddrCnt].Address, &Address); + VarArg = VarArg->Next; + AddrCnt++; + } + + *Arg = VarArg; + + if (EFI_ERROR (Status) && (Status != EFI_INVALID_PARAMETER)) { + goto ON_ERROR; + } + + *Buf = AddrBuf; + *BufSize = AddrCnt * sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS); + + return EFI_SUCCESS; + +ON_ERROR: + + FreePool (AddrBuf); + return Status; +} + +/** + Pick up gw/dns IPv6 address in string format from Args with "-s" option and convert it to EFI_IPv6_ADDRESS format. + + @param[in, out] Arg The pointer of the address of ARG_LIST that save Args with the "-s" option. + @param[out] Buf The pointer of the address of EFI_IPv6_ADDRESS. + @param[out] BufSize The pointer of BufSize that describes the size of Buf in bytes. + + @retval EFI_SUCCESS The conversion is successful. + @retval Others Doesn't find the host address, or it is an invalid IPv6 address in string format. + +**/ +EFI_STATUS +IfConfig6ParseGwDnsAddressList ( + IN OUT ARG_LIST **Arg, + OUT EFI_IPv6_ADDRESS **Buf, + OUT UINTN *BufSize + ) +{ + EFI_STATUS Status; + EFI_IPv6_ADDRESS *AddrBuf; + ARG_LIST *VarArg; + EFI_IPv6_ADDRESS Address; + UINT8 Prefix; + UINT8 AddrCnt; + + AddrCnt = 0; + *BufSize = 0; + *Buf = NULL; + VarArg = *Arg; + Status = EFI_SUCCESS; + + // + // Go through the list to check the correctness of input gw/dns address. + // + while ((!EFI_ERROR (Status)) && (VarArg != NULL)) { + + Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix); + + if (EFI_ERROR (Status)) { + // + // gw ip ip ... host + // + break; + } + + VarArg = VarArg->Next; + AddrCnt++; + } + + if (AddrCnt == 0) { + return EFI_INVALID_PARAMETER; + } + + AddrBuf = AllocateZeroPool (AddrCnt * sizeof (EFI_IPv6_ADDRESS)); + ASSERT (AddrBuf != NULL); + + AddrCnt = 0; + VarArg = *Arg; + Status = EFI_SUCCESS; + + // + // Go through the list to fill in the EFI_IPv6_ADDRESS structure. + // + while ((!EFI_ERROR (Status)) && (VarArg != NULL)) { + + Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix); + + if (EFI_ERROR (Status)) { + break; + } + + IP6_COPY_ADDRESS (&AddrBuf[AddrCnt], &Address); + + VarArg = VarArg->Next; + AddrCnt++; + } + + *Arg = VarArg; + + if (EFI_ERROR (Status) && (Status != EFI_INVALID_PARAMETER)) { + goto ON_ERROR; + } + + *Buf = AddrBuf; + *BufSize = AddrCnt * sizeof (EFI_IPv6_ADDRESS); + + return EFI_SUCCESS; + +ON_ERROR: + + FreePool (AddrBuf); + return Status; +} + +/** + Parse InterfaceId in string format from Args with the "-s" option and convert it to EFI_IP6_CONFIG_INTERFACE_ID format. + + @param[in, out] Arg The pointer of the address of ARG_LIST that saves Args with the "-s" option. + @param[out] IfId The pointer of EFI_IP6_CONFIG_INTERFACE_ID. + + @retval EFI_SUCCESS The get status processed successfullly. + @retval EFI_INVALID_PARAMETER The get status process failed. + +**/ +EFI_STATUS +IfConfig6ParseInterfaceId ( + IN OUT ARG_LIST **Arg, + OUT EFI_IP6_CONFIG_INTERFACE_ID **IfId + ) +{ + UINT8 Index; + UINT8 NodeVal; + CHAR16 *IdStr; + + if (*Arg == NULL) { + return EFI_INVALID_PARAMETER; + } + + Index = 0; + IdStr = (*Arg)->Arg; + ASSERT (IfId != NULL); + *IfId = AllocateZeroPool (sizeof (EFI_IP6_CONFIG_INTERFACE_ID)); + ASSERT (*IfId != NULL); + + while ((*IdStr != L'\0') && (Index < 8)) { + + NodeVal = 0; + while ((*IdStr != L':') && (*IdStr != L'\0')) { + + if ((*IdStr <= L'F') && (*IdStr >= L'A')) { + NodeVal = (UINT8)((NodeVal << 4) + *IdStr - L'A' + 10); + } else if ((*IdStr <= L'f') && (*IdStr >= L'a')) { + NodeVal = (UINT8)((NodeVal << 4) + *IdStr - L'a' + 10); + } else if ((*IdStr <= L'9') && (*IdStr >= L'0')) { + NodeVal = (UINT8)((NodeVal << 4) + *IdStr - L'0'); + } else { + FreePool (*IfId); + return EFI_INVALID_PARAMETER; + } + + IdStr++; + } + + (*IfId)->Id[Index++] = NodeVal; + + if (*IdStr == L':') { + IdStr++; + } + } + + *Arg = (*Arg)->Next; + return EFI_SUCCESS; +} + +/** + Parse dad in string format from Args with the "-s" option and convert it to UINT32 format. + + @param[in, out] Arg The pointer of the address of ARG_LIST that saves Args with the "-s" option. + @param[out] Xmits The pointer of Xmits. + + @retval EFI_SUCCESS The get status processed successfully. + @retval others The get status process failed. + +**/ +EFI_STATUS +IfConfig6ParseDadXmits ( + IN OUT ARG_LIST **Arg, + OUT UINT32 *Xmits + ) +{ + CHAR16 *ValStr; + + if (*Arg == NULL) { + return EFI_INVALID_PARAMETER; + } + + ValStr = (*Arg)->Arg; + *Xmits = 0; + + while (*ValStr != L'\0') { + + if ((*ValStr <= L'9') && (*ValStr >= L'0')) { + + *Xmits = (*Xmits * 10) + (*ValStr - L'0'); + + } else { + + return EFI_INVALID_PARAMETER; + } + + ValStr++; + } + + *Arg = (*Arg)->Next; + return EFI_SUCCESS; +} + +/** + The get current status of all handles. + + @param[in] ImageHandle The handle of ImageHandle. + @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 +IfConfig6GetInterfaceInfo ( + IN EFI_HANDLE ImageHandle, + IN CHAR16 *IfName, + IN LIST_ENTRY *IfList + ) +{ + EFI_STATUS Status; + UINTN HandleIndex; + UINTN HandleNum; + EFI_HANDLE *HandleBuffer; + EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; + EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo; + IFCONFIG6_INTERFACE_CB *IfCb; + UINTN DataSize; + + HandleBuffer = NULL; + HandleNum = 0; + + IfInfo = NULL; + IfCb = NULL; + + // + // Locate all the handles with ip6 service binding protocol. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiIp6ServiceBindingProtocolGuid, + NULL, + &HandleNum, + &HandleBuffer + ); + if (EFI_ERROR (Status) || (HandleNum == 0)) { + return Status; + } + + // + // Enumerate all handles that installed with ip6 service binding protocol. + // + for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) { + IfCb = NULL; + IfInfo = NULL; + DataSize = 0; + + // + // Ip6config protocol and ip6 service binding protocol are installed + // on the same handle. + // + ASSERT (HandleBuffer != NULL); + Status = gBS->HandleProtocol ( + HandleBuffer[HandleIndex], + &gEfiIp6ConfigProtocolGuid, + (VOID **) &Ip6Cfg + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + // + // Get the interface information size. + // + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeInterfaceInfo, + &DataSize, + NULL + ); + + if (Status != EFI_BUFFER_TOO_SMALL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + + IfInfo = AllocateZeroPool (DataSize); + + if (IfInfo == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + // + // Get the interface info. + // + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeInterfaceInfo, + &DataSize, + IfInfo + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, 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 = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeDnsServer, + &DataSize, + NULL + ); + + if ((Status != EFI_BUFFER_TOO_SMALL) && (Status != EFI_NOT_FOUND)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + + IfCb = AllocateZeroPool (sizeof (IFCONFIG6_INTERFACE_CB) + DataSize); + + if (IfCb == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + IfCb->NicHandle = HandleBuffer[HandleIndex]; + IfCb->IfInfo = IfInfo; + IfCb->IfCfg = Ip6Cfg; + IfCb->DnsCnt = (UINT32) (DataSize / sizeof (EFI_IPv6_ADDRESS)); + + // + // Get the dns server list if has. + // + if (DataSize > 0) { + + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeDnsServer, + &DataSize, + IfCb->DnsAddr + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + } + // + // Get the interface id if has. + // + DataSize = sizeof (EFI_IP6_CONFIG_INTERFACE_ID); + IfCb->IfId = AllocateZeroPool (DataSize); + + if (IfCb->IfId == NULL) { + goto ON_ERROR; + } + + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeAltInterfaceId, + &DataSize, + IfCb->IfId + ); + + if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + + if (Status == EFI_NOT_FOUND) { + FreePool (IfCb->IfId); + IfCb->IfId = NULL; + } + // + // Get the config policy. + // + DataSize = sizeof (EFI_IP6_CONFIG_POLICY); + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypePolicy, + &DataSize, + &IfCb->Policy + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + // + // Get the dad transmits. + // + DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS); + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeDupAddrDetectTransmits, + &DataSize, + &IfCb->Xmits + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, 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) { + if (IfCb->IfId != NULL) { + FreePool (IfCb->IfId); + } + + FreePool (IfCb); + } + + return Status; +} + +/** + The list process of the IfConfig6 application. + + @param[in] IfList The pointer of IfList(interface list). + + @retval SHELL_SUCCESS The IfConfig6 list processed successfully. + @retval others The IfConfig6 list process failed. + +**/ +SHELL_STATUS +IfConfig6ShowInterfaceInfo ( + IN LIST_ENTRY *IfList + ) +{ + LIST_ENTRY *Entry; + IFCONFIG6_INTERFACE_CB *IfCb; + UINTN Index; + + Entry = IfList->ForwardLink; + + if (IsListEmpty (IfList)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_INTERFACE), gShellNetwork2HiiHandle); + } + + // + // Go through the interface list. + // + while (Entry != IfList) { + + IfCb = BASE_CR (Entry, IFCONFIG6_INTERFACE_CB, Link); + + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_BREAK), gShellNetwork2HiiHandle); + + // + // Print interface name. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_IF_NAME), gShellNetwork2HiiHandle, IfCb->IfInfo->Name); + + // + // Print interface config policy. + // + if (IfCb->Policy == Ip6ConfigPolicyAutomatic) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_POLICY_AUTO), gShellNetwork2HiiHandle); + } else { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_POLICY_MAN), gShellNetwork2HiiHandle); + } + + // + // Print dad transmit. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_DAD_TRANSMITS), gShellNetwork2HiiHandle, IfCb->Xmits); + + // + // Print interface id if has. + // + if (IfCb->IfId != NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_INTERFACE_ID_HEAD), gShellNetwork2HiiHandle); + + IfConfig6PrintMacAddr ( + IfCb->IfId->Id, + 8 + ); + } + // + // Print mac address of the interface. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_MAC_ADDR_HEAD), gShellNetwork2HiiHandle); + + IfConfig6PrintMacAddr ( + IfCb->IfInfo->HwAddress.Addr, + IfCb->IfInfo->HwAddressSize + ); + + // + // Print ip addresses list of the interface. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_IP_ADDR_HEAD), gShellNetwork2HiiHandle); + + for (Index = 0; Index < IfCb->IfInfo->AddressInfoCount; Index++) { + IfConfig6PrintIpAddr ( + &IfCb->IfInfo->AddressInfo[Index].Address, + &IfCb->IfInfo->AddressInfo[Index].PrefixLength + ); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_NEWLINE), gShellNetwork2HiiHandle); + } + + // + // Print dns server addresses list of the interface if has. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_DNS_ADDR_HEAD), gShellNetwork2HiiHandle); + + for (Index = 0; Index < IfCb->DnsCnt; Index++) { + IfConfig6PrintIpAddr ( + &IfCb->DnsAddr[Index], + NULL + ); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_NEWLINE), gShellNetwork2HiiHandle); + } + + // + // Print route table of the interface if has. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_ROUTE_HEAD), gShellNetwork2HiiHandle); + + for (Index = 0; Index < IfCb->IfInfo->RouteCount; Index++) { + IfConfig6PrintIpAddr ( + &IfCb->IfInfo->RouteTable[Index].Destination, + &IfCb->IfInfo->RouteTable[Index].PrefixLength + ); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_JOINT), gShellNetwork2HiiHandle); + + IfConfig6PrintIpAddr ( + &IfCb->IfInfo->RouteTable[Index].Gateway, + NULL + ); + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_NEWLINE), gShellNetwork2HiiHandle); + } + + Entry = Entry->ForwardLink; + } + + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_INFO_BREAK), gShellNetwork2HiiHandle); + + return SHELL_SUCCESS; +} + +/** + The clean process of the IfConfig6 application. + + @param[in] IfList The pointer of IfList(interface list). + + @retval SHELL_SUCCESS The IfConfig6 clean processed successfully. + @retval others The IfConfig6 clean process failed. + +**/ +SHELL_STATUS +IfConfig6ClearInterfaceInfo ( + IN LIST_ENTRY *IfList + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + LIST_ENTRY *Entry; + IFCONFIG6_INTERFACE_CB *IfCb; + EFI_IP6_CONFIG_POLICY Policy; + + Policy = Ip6ConfigPolicyAutomatic; + Entry = IfList->ForwardLink; + Status = EFI_SUCCESS; + ShellStatus = SHELL_SUCCESS; + + if (IsListEmpty (IfList)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_INTERFACE), gShellNetwork2HiiHandle); + } + + // + // Go through the interface list. + // + while (Entry != IfList) { + + IfCb = BASE_CR (Entry, IFCONFIG6_INTERFACE_CB, Link); + + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypePolicy, + sizeof (EFI_IP6_CONFIG_POLICY), + &Policy + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + break; + } + + Entry = Entry->ForwardLink; + } + + return ShellStatus; +} + +/** + The set process of the IfConfig6 application. + + @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 IfConfig6 set processed successfully. + @retval others The IfConfig6 set process failed. + +**/ +SHELL_STATUS +IfConfig6SetInterfaceInfo ( + IN LIST_ENTRY *IfList, + IN ARG_LIST *VarArg + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + IFCONFIG6_INTERFACE_CB *IfCb; + EFI_IP6_CONFIG_MANUAL_ADDRESS *CfgManAddr; + EFI_IPv6_ADDRESS *CfgAddr; + UINTN AddrSize; + EFI_IP6_CONFIG_INTERFACE_ID *InterfaceId; + UINT32 DadXmits; + UINT32 CurDadXmits; + UINTN CurDadXmitsLen; + EFI_IP6_CONFIG_POLICY Policy; + + VAR_CHECK_CODE CheckCode; + EFI_EVENT TimeOutEvt; + EFI_EVENT MappedEvt; + BOOLEAN IsAddressOk; + + UINTN DataSize; + UINT32 Index; + UINT32 Index2; + BOOLEAN IsAddressSet; + EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo; + + CfgManAddr = NULL; + CfgAddr = NULL; + TimeOutEvt = NULL; + MappedEvt = NULL; + IfInfo = NULL; + InterfaceId = NULL; + CurDadXmits = 0; + + if (IsListEmpty (IfList)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_INTERFACE), gShellNetwork2HiiHandle); + return SHELL_INVALID_PARAMETER; + } + // + // Make sure to set only one interface each time. + // + IfCb = BASE_CR (IfList->ForwardLink, IFCONFIG6_INTERFACE_CB, Link); + Status = EFI_SUCCESS; + ShellStatus = SHELL_SUCCESS; + + // + // Initialize check list mechanism. + // + CheckCode = IfConfig6RetriveCheckListByName( + NULL, + NULL, + TRUE + ); + + // + // Create events & timers for asynchronous settings. + // + Status = gBS->CreateEvent ( + EVT_TIMER, + TPL_CALLBACK, + NULL, + NULL, + &TimeOutEvt + ); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + IfConfig6ManualAddressNotify, + &IsAddressOk, + &MappedEvt + ); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Parse the setting variables. + // + while (VarArg != NULL) { + // + // Check invalid parameters (duplication & unknown & conflict). + // + CheckCode = IfConfig6RetriveCheckListByName( + mIfConfig6SetCheckList, + VarArg->Arg, + FALSE + ); + + if (VarCheckOk != CheckCode) { + switch (CheckCode) { + case VarCheckDuplicate: + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_DUPLICATE_COMMAND), gShellNetwork2HiiHandle, VarArg->Arg); + break; + + case VarCheckConflict: + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_CONFLICT_COMMAND), gShellNetwork2HiiHandle, VarArg->Arg); + break; + + case VarCheckUnknown: + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_UNKNOWN_COMMAND), gShellNetwork2HiiHandle, VarArg->Arg); + break; + + default: + break; + } + + VarArg = VarArg->Next; + continue; + } + // + // Process valid variables. + // + if (StrCmp(VarArg->Arg, L"auto") == 0) { + // + // Set automaic config policy + // + Policy = Ip6ConfigPolicyAutomatic; + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypePolicy, + sizeof (EFI_IP6_CONFIG_POLICY), + &Policy + ); + + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + VarArg= VarArg->Next; + + } else if (StrCmp (VarArg->Arg, L"man") == 0) { + // + // Set manual config policy. + // + Policy = Ip6ConfigPolicyManual; + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypePolicy, + sizeof (EFI_IP6_CONFIG_POLICY), + &Policy + ); + + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + VarArg= VarArg->Next; + + } else if (StrCmp (VarArg->Arg, L"host") == 0) { + // + // Parse till the next tag or the end of command line. + // + VarArg = VarArg->Next; + Status = IfConfig6ParseManualAddressList ( + &VarArg, + &CfgManAddr, + &AddrSize + ); + + if (EFI_ERROR (Status)) { + if (Status == EFI_INVALID_PARAMETER) { + ShellStatus = SHELL_INVALID_PARAMETER; + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_LACK_ARGUMENTS), gShellNetwork2HiiHandle, L"host"); + continue; + } else { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + } + // + // Set static host ip6 address list. + // This is a asynchronous process. + // + IsAddressOk = FALSE; + + Status = IfCb->IfCfg->RegisterDataNotify ( + IfCb->IfCfg, + Ip6ConfigDataTypeManualAddress, + MappedEvt + ); + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeManualAddress, + AddrSize, + CfgManAddr + ); + + if (Status == EFI_NOT_READY) { + // + // Get current dad transmits count. + // + CurDadXmitsLen = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS); + IfCb->IfCfg->GetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeDupAddrDetectTransmits, + &CurDadXmitsLen, + &CurDadXmits + ); + + gBS->SetTimer (TimeOutEvt, TimerRelative, 50000000 + 10000000 * CurDadXmits); + + while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) { + if (IsAddressOk) { + Status = EFI_SUCCESS; + break; + } + } + } + + IfCb->IfCfg->UnregisterDataNotify ( + IfCb->IfCfg, + Ip6ConfigDataTypeManualAddress, + MappedEvt + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_MAN_HOST), gShellNetwork2HiiHandle, Status); + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + // + // Check whether the address is set successfully. + // + DataSize = 0; + + Status = IfCb->IfCfg->GetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeInterfaceInfo, + &DataSize, + NULL + ); + + if (Status != EFI_BUFFER_TOO_SMALL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + IfInfo = AllocateZeroPool (DataSize); + + if (IfInfo == NULL) { + ShellStatus = SHELL_OUT_OF_RESOURCES; + goto ON_EXIT; + } + + Status = IfCb->IfCfg->GetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeInterfaceInfo, + &DataSize, + IfInfo + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + for ( Index = 0; Index < (UINTN) (AddrSize / sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)); Index++) { + IsAddressSet = FALSE; + // + // By default, the prefix length 0 is regarded as 64. + // + if (CfgManAddr[Index].PrefixLength == 0) { + CfgManAddr[Index].PrefixLength = 64; + } + + for (Index2 = 0; Index2 < IfInfo->AddressInfoCount; Index2++) { + if (EFI_IP6_EQUAL (&IfInfo->AddressInfo[Index2].Address, &CfgManAddr[Index].Address) && + (IfInfo->AddressInfo[Index2].PrefixLength == CfgManAddr[Index].PrefixLength)) { + IsAddressSet = TRUE; + break; + } + } + + if (!IsAddressSet) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_ADDRESS_FAILED), gShellNetwork2HiiHandle); + IfConfig6PrintIpAddr ( + &CfgManAddr[Index].Address, + &CfgManAddr[Index].PrefixLength + ); + } + } + + } else if (StrCmp (VarArg->Arg, L"gw") == 0) { + // + // Parse till the next tag or the end of command line. + // + VarArg = VarArg->Next; + Status = IfConfig6ParseGwDnsAddressList ( + &VarArg, + &CfgAddr, + &AddrSize + ); + + if (EFI_ERROR (Status)) { + if (Status == EFI_INVALID_PARAMETER) { + ShellStatus = SHELL_INVALID_PARAMETER; + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_LACK_ARGUMENTS), gShellNetwork2HiiHandle, L"gw"); + continue; + } else { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + } + // + // Set static gateway ip6 address list. + // + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeGateway, + AddrSize, + CfgAddr + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + } else if (StrCmp (VarArg->Arg, L"dns") == 0) { + // + // Parse till the next tag or the end of command line. + // + VarArg = VarArg->Next; + Status = IfConfig6ParseGwDnsAddressList ( + &VarArg, + &CfgAddr, + &AddrSize + ); + + if (EFI_ERROR (Status)) { + if (Status == EFI_INVALID_PARAMETER) { + ShellStatus = SHELL_INVALID_PARAMETER; + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_LACK_ARGUMENTS), gShellNetwork2HiiHandle, L"dns"); + continue; + } else { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + } + // + // Set static DNS server ip6 address list. + // + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeDnsServer, + AddrSize, + CfgAddr + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + } else if (StrCmp (VarArg->Arg, L"id") == 0) { + // + // Parse till the next tag or the end of command line. + // + VarArg = VarArg->Next; + Status = IfConfig6ParseInterfaceId (&VarArg, &InterfaceId); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + // + // Set alternative interface id. + // + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeAltInterfaceId, + sizeof (EFI_IP6_CONFIG_INTERFACE_ID), + InterfaceId + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + + } else if (StrCmp (VarArg->Arg, L"dad") == 0) { + // + // Parse till the next tag or the end of command line. + // + VarArg = VarArg->Next; + Status = IfConfig6ParseDadXmits (&VarArg, &DadXmits); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Set dad transmits count. + // + Status = IfCb->IfCfg->SetData ( + IfCb->IfCfg, + Ip6ConfigDataTypeDupAddrDetectTransmits, + sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS), + &DadXmits + ); + + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + } + } + +ON_EXIT: + + if (CfgManAddr != NULL) { + FreePool (CfgManAddr); + } + + if (CfgAddr != NULL) { + FreePool (CfgAddr); + } + + if (MappedEvt != NULL) { + gBS->CloseEvent (MappedEvt); + } + + if (TimeOutEvt != NULL) { + gBS->CloseEvent (TimeOutEvt); + } + + if (IfInfo != NULL) { + FreePool (IfInfo); + } + + return ShellStatus; + +} + +/** + The IfConfig6 main process. + + @param[in] Private The pointer of IFCONFIG6_PRIVATE_DATA. + + @retval SHELL_SUCCESS IfConfig6 processed successfully. + @retval others The IfConfig6 process failed. + +**/ +SHELL_STATUS +IfConfig6 ( + IN IFCONFIG6_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; + + // + // Get configure information of all interfaces. + // + Status = IfConfig6GetInterfaceInfo ( + Private->ImageHandle, + Private->IfName, + &Private->IfList + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_NOT_FOUND; + goto ON_EXIT; + } + + switch (Private->OpCode) { + case IfConfig6OpList: + ShellStatus = IfConfig6ShowInterfaceInfo (&Private->IfList); + break; + + case IfConfig6OpClear: + ShellStatus = IfConfig6ClearInterfaceInfo (&Private->IfList); + break; + + case IfConfig6OpSet: + ShellStatus = IfConfig6SetInterfaceInfo (&Private->IfList, Private->VarArg); + break; + + default: + ShellStatus = SHELL_UNSUPPORTED; + } + +ON_EXIT: + + return ShellStatus; +} + +/** + The IfConfig6 cleanup process, free the allocated memory. + + @param[in] Private The pointer of IFCONFIG6_PRIVATE_DATA. + +**/ +VOID +IfConfig6Cleanup ( + IN IFCONFIG6_PRIVATE_DATA *Private + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + IFCONFIG6_INTERFACE_CB *IfCb; + ARG_LIST *ArgNode; + ARG_LIST *ArgHead; + + ASSERT (Private != NULL); + + // + // Clean the list which save the set config Args. + // + if (Private->VarArg != NULL) { + ArgHead = Private->VarArg; + + while (ArgHead->Next != NULL) { + ArgNode = ArgHead->Next; + FreePool (ArgHead); + ArgHead = ArgNode; + } + + FreePool (ArgHead); + } + + if (Private->IfName != NULL) + FreePool (Private->IfName); + + + // + // Clean the IFCONFIG6_INTERFACE_CB list. + // + Entry = Private->IfList.ForwardLink; + NextEntry = Entry->ForwardLink; + + while (Entry != &Private->IfList) { + + IfCb = BASE_CR (Entry, IFCONFIG6_INTERFACE_CB, Link); + + RemoveEntryList (&IfCb->Link); + + if (IfCb->IfId != NULL) { + + FreePool (IfCb->IfId); + } + + if (IfCb->IfInfo != NULL) { + + FreePool (IfCb->IfInfo); + } + + FreePool (IfCb); + + Entry = NextEntry; + NextEntry = Entry->ForwardLink; + } + + FreePool (Private); +} + +/** + Function for 'ifconfig6' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). + + @retval SHELL_SUCCESS ifconfig6 command processed successfully. + @retval others The ifconfig6 command process failed. + +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunIfconfig6 ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + IFCONFIG6_PRIVATE_DATA *Private; + LIST_ENTRY *ParamPackage; + CONST CHAR16 *ValueStr; + ARG_LIST *ArgList; + CHAR16 *ProblemParam; + CHAR16 *Str; + + Private = NULL; + Status = EFI_INVALID_PARAMETER; + ShellStatus = SHELL_SUCCESS; + + Status = ShellCommandLineParseEx (mIfConfig6CheckList, &ParamPackage, &ProblemParam, TRUE, FALSE); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_INVALID_COMMAND), gShellNetwork2HiiHandle, L"ifconfig6", ProblemParam); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + // + // To handle no option. + // + if (!ShellCommandLineGetFlag (ParamPackage, L"-r") && !ShellCommandLineGetFlag (ParamPackage, L"-s") && + !ShellCommandLineGetFlag (ParamPackage, L"-?") && !ShellCommandLineGetFlag (ParamPackage, L"-l")) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_LACK_OPTION), gShellNetwork2HiiHandle); + 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"-r")) && (ShellCommandLineGetFlag (ParamPackage, L"-?"))) || + ((ShellCommandLineGetFlag (ParamPackage, L"-s")) && (ShellCommandLineGetFlag (ParamPackage, L"-l"))) || + ((ShellCommandLineGetFlag (ParamPackage, L"-s")) && (ShellCommandLineGetFlag (ParamPackage, L"-?"))) || + ((ShellCommandLineGetFlag (ParamPackage, L"-l")) && (ShellCommandLineGetFlag (ParamPackage, L"-?")))) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_CONFLICT_OPTIONS), gShellNetwork2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + Private = AllocateZeroPool (sizeof (IFCONFIG6_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 = IfConfig6OpList; + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l"); + if (ValueStr != NULL) { + Str = AllocateCopyPool (StrSize (ValueStr), ValueStr); + ASSERT (Str != NULL); + Private->IfName = Str; + } + } + // + // To get interface name for the clear option. + // + if (ShellCommandLineGetFlag (ParamPackage, L"-r")) { + Private->OpCode = IfConfig6OpClear; + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-r"); + if (ValueStr != NULL) { + Str = AllocateCopyPool (StrSize (ValueStr), ValueStr); + ASSERT (Str != NULL); + 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_IFCONFIG6_ERR_LACK_INTERFACE), gShellNetwork2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + // + // To split the configuration into multi-section. + // + ArgList = IfConfig6SplitStrToList (ValueStr, L' '); + ASSERT (ArgList != NULL); + + Private->OpCode = IfConfig6OpSet; + Private->IfName = ArgList->Arg; + + Private->VarArg = ArgList->Next; + + if (Private->IfName == NULL || Private->VarArg == NULL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_IFCONFIG6_ERR_LACK_COMMAND), gShellNetwork2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + // + // Main process of ifconfig6. + // + ShellStatus = IfConfig6 (Private); + +ON_EXIT: + + ShellCommandLineFreeVarList (ParamPackage); + if (Private != NULL) { + IfConfig6Cleanup (Private); + } + return ShellStatus; + +} + diff --git a/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ping6.c b/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ping6.c new file mode 100644 index 0000000000..af7d08f3ec --- /dev/null +++ b/ShellPkg/Library/UefiShellNetwork2CommandsLib/Ping6.c @@ -0,0 +1,1247 @@ +/** @file + The implementation for Ping6 application. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "UefiShellNetwork2CommandsLib.h" + +#define PING6_DEFAULT_TIMEOUT 5000 +#define PING6_MAX_SEND_NUMBER 10000 +#define PING6_MAX_BUFFER_SIZE 32768 +#define PING6_ONE_SECOND 10000000 + +// +// A similar amount of time that passes in femtoseconds +// for each increment of TimerValue. It is for NT32 only. +// +#define NTTIMERPERIOD 358049 + +#pragma pack(1) + +typedef struct _ICMP6_ECHO_REQUEST_REPLY { + UINT8 Type; + UINT8 Code; + UINT16 Checksum; + UINT16 Identifier; + UINT16 SequenceNum; + UINT64 TimeStamp; + UINT8 Data[1]; +} ICMP6_ECHO_REQUEST_REPLY; + +#pragma pack() + +typedef struct _PING6_ICMP6_TX_INFO { + LIST_ENTRY Link; + UINT16 SequenceNum; + UINT64 TimeStamp; + EFI_IP6_COMPLETION_TOKEN *Token; +} PING6_ICMP6_TX_INFO; + +typedef struct _PING6_PRIVATE_DATA { + EFI_HANDLE ImageHandle; + EFI_HANDLE NicHandle; + EFI_HANDLE Ip6ChildHandle; + EFI_IP6_PROTOCOL *Ip6; + EFI_EVENT Timer; + + EFI_STATUS Status; + LIST_ENTRY TxList; + EFI_IP6_COMPLETION_TOKEN RxToken; + UINT16 RxCount; + UINT16 TxCount; + UINT64 RttSum; + UINT64 RttMin; + UINT64 RttMax; + UINT32 SequenceNum; + + EFI_IPv6_ADDRESS SrcAddress; + EFI_IPv6_ADDRESS DstAddress; + UINT32 SendNum; + UINT32 BufferSize; +} PING6_PRIVATE_DATA; + + +SHELL_PARAM_ITEM Ping6ParamList[] = { + { + L"-l", + TypeValue + }, + { + L"-n", + TypeValue + }, + { + L"-s", + TypeValue + }, + { + L"-?", + TypeFlag + }, + { + NULL, + TypeMax + }, +}; + +// +// Global Variables in Ping6 application. +// +CONST CHAR16 *mIp6DstString; +CONST CHAR16 *mIp6SrcString; +UINT64 mFrequency = 0; +UINT64 mIp6CurrentTick = 0; +EFI_CPU_ARCH_PROTOCOL *Cpu = NULL; + + + +/** + Reads and returns the current value of the Time. + + @return The current tick value. + +**/ +UINT64 +Ping6ReadTime () +{ + UINT64 TimerPeriod; + EFI_STATUS Status; + + ASSERT (Cpu != NULL); + + Status = Cpu->GetTimerValue (Cpu, 0, &mIp6CurrentTick, &TimerPeriod); + if (EFI_ERROR (Status)) { + // + // The WinntGetTimerValue will return EFI_UNSUPPORTED. Set the + // TimerPeriod by ourselves. + // + mIp6CurrentTick += 1000000; + } + + return mIp6CurrentTick; +} + +/** + Get and calculate the frequency in tick/ms. + The result is saved in the globle variable mFrequency + + @retval EFI_SUCCESS Calculated the frequency successfully. + @retval Others Failed to calculate the frequency. + +**/ +EFI_STATUS +Ping6GetFrequency ( + VOID + ) +{ + EFI_STATUS Status; + UINT64 CurrentTick; + UINT64 TimerPeriod; + + Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Cpu); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = Cpu->GetTimerValue (Cpu, 0, &CurrentTick, &TimerPeriod); + + if (EFI_ERROR (Status)) { + // + // For NT32 Simulator only. 358049 is a similar value to keep timer granularity. + // Set the timer period by ourselves. + // + TimerPeriod = (UINT64) NTTIMERPERIOD; + } + // + // The timer period is in femtosecond (1 femtosecond is 1e-15 second). + // So 1e+12 is divided by timer period to produce the freq in tick/ms. + // + mFrequency = DivU64x64Remainder (1000000000000ULL, TimerPeriod, NULL); + + return EFI_SUCCESS; +} + +/** + Get and calculate the duration in ms. + + @param[in] Begin The start point of time. + @param[in] End The end point of time. + + @return The duration in ms. + +**/ +UINT64 +Ping6CalculateTick ( + IN UINT64 Begin, + IN UINT64 End + ) +{ + ASSERT (End > Begin); + return DivU64x64Remainder (End - Begin, mFrequency, NULL); +} + +/** + Destroy IPING6_ICMP6_TX_INFO, and recollect the memory. + + @param[in] TxInfo The pointer to PING6_ICMP6_TX_INFO. + +**/ +VOID +Ping6DestroyTxInfo ( + IN PING6_ICMP6_TX_INFO *TxInfo + ) +{ + EFI_IP6_TRANSMIT_DATA *TxData; + EFI_IP6_FRAGMENT_DATA *FragData; + UINTN Index; + + ASSERT (TxInfo != NULL); + + if (TxInfo->Token != NULL) { + + if (TxInfo->Token->Event != NULL) { + gBS->CloseEvent (TxInfo->Token->Event); + } + + TxData = TxInfo->Token->Packet.TxData; + if (TxData != NULL) { + + if (TxData->OverrideData != NULL) { + FreePool (TxData->OverrideData); + } + + if (TxData->ExtHdrs != NULL) { + FreePool (TxData->ExtHdrs); + } + + for (Index = 0; Index < TxData->FragmentCount; Index++) { + FragData = TxData->FragmentTable[Index].FragmentBuffer; + if (FragData != NULL) { + FreePool (FragData); + } + } + } + + FreePool (TxInfo->Token); + } + + FreePool (TxInfo); +} + +/** + Match the request, and reply with SequenceNum/TimeStamp. + + @param[in] Private The pointer to PING6_PRIVATE_DATA. + @param[in] Packet The pointer to ICMP6_ECHO_REQUEST_REPLY. + + @retval EFI_SUCCESS The match is successful. + @retval EFI_NOT_FOUND The reply can't be matched with any request. + +**/ +EFI_STATUS +Ping6OnMatchEchoReply ( + IN PING6_PRIVATE_DATA *Private, + IN ICMP6_ECHO_REQUEST_REPLY *Packet + ) +{ + PING6_ICMP6_TX_INFO *TxInfo; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) { + TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link); + + if ((TxInfo->SequenceNum == Packet->SequenceNum) && (TxInfo->TimeStamp == Packet->TimeStamp)) { + Private->RxCount++; + RemoveEntryList (&TxInfo->Link); + Ping6DestroyTxInfo (TxInfo); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + The original intention is to send a request. + Currently, the application retransmits an icmp6 echo request packet + per second in sendnumber times that is specified by the user. + Because nothing can be done here, all things move to the timer rountine. + + @param[in] Event A EFI_EVENT type event. + @param[in] Context The pointer to Context. + +**/ +VOID +EFIAPI +Ping6OnEchoRequestSent6 ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ +} + +/** + receive reply, match and print reply infomation. + + @param[in] Event A EFI_EVENT type event. + @param[in] Context The pointer to context. + +**/ +VOID +EFIAPI +Ping6OnEchoReplyReceived6 ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + PING6_PRIVATE_DATA *Private; + EFI_IP6_COMPLETION_TOKEN *RxToken; + EFI_IP6_RECEIVE_DATA *RxData; + ICMP6_ECHO_REQUEST_REPLY *Reply; + UINT32 PayLoad; + UINT64 Rtt; + CHAR8 Near; + + Private = (PING6_PRIVATE_DATA *) Context; + + if (Private->Status == EFI_ABORTED) { + return; + } + + RxToken = &Private->RxToken; + RxData = RxToken->Packet.RxData; + Reply = RxData->FragmentTable[0].FragmentBuffer; + PayLoad = RxData->DataLength; + + if (RxData->Header->NextHeader != IP6_ICMP) { + goto ON_EXIT; + } + + if (!IP6_IS_MULTICAST (&Private->DstAddress) && + !EFI_IP6_EQUAL (&RxData->Header->SourceAddress, &Private->DstAddress)) { + goto ON_EXIT; + } + + if ((Reply->Type != ICMP_V6_ECHO_REPLY) || (Reply->Code != 0)) { + goto ON_EXIT; + } + + if (PayLoad != Private->BufferSize) { + goto ON_EXIT; + } + // + // Check whether the reply matches the sent request before. + // + Status = Ping6OnMatchEchoReply (Private, Reply); + if (EFI_ERROR(Status)) { + goto ON_EXIT; + } + // + // Display statistics on this icmp6 echo reply packet. + // + Rtt = Ping6CalculateTick (Reply->TimeStamp, Ping6ReadTime ()); + if (Rtt != 0) { + Near = (CHAR8) '='; + } else { + Near = (CHAR8) '<'; + } + + Private->RttSum += Rtt; + Private->RttMin = Private->RttMin > Rtt ? Rtt : Private->RttMin; + Private->RttMax = Private->RttMax < Rtt ? Rtt : Private->RttMax; + + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_PING6_REPLY_INFO), + gShellNetwork2HiiHandle, + PayLoad, + mIp6DstString, + Reply->SequenceNum, + RxData->Header->HopLimit, + Near, + Rtt + ); + +ON_EXIT: + + if (Private->RxCount < Private->SendNum) { + // + // Continue to receive icmp6 echo reply packets. + // + RxToken->Status = EFI_ABORTED; + + Status = Private->Ip6->Receive (Private->Ip6, RxToken); + + if (EFI_ERROR (Status)) { + Private->Status = EFI_ABORTED; + } + } else { + // + // All reply have already been received from the dest host. + // + Private->Status = EFI_SUCCESS; + } + // + // Singal to recycle the each rxdata here, not at the end of process. + // + gBS->SignalEvent (RxData->RecycleSignal); +} + +/** + Initial EFI_IP6_COMPLETION_TOKEN. + + @param[in] Private The pointer of PING6_PRIVATE_DATA. + @param[in] TimeStamp The TimeStamp of request. + @param[in] SequenceNum The SequenceNum of request. + + @return The pointer of EFI_IP6_COMPLETION_TOKEN. + +**/ +EFI_IP6_COMPLETION_TOKEN * +Ping6GenerateToken ( + IN PING6_PRIVATE_DATA *Private, + IN UINT64 TimeStamp, + IN UINT16 SequenceNum + ) +{ + EFI_STATUS Status; + EFI_IP6_COMPLETION_TOKEN *Token; + EFI_IP6_TRANSMIT_DATA *TxData; + ICMP6_ECHO_REQUEST_REPLY *Request; + + Request = AllocateZeroPool (Private->BufferSize); + + if (Request == NULL) { + return NULL; + } + // + // Assembly icmp6 echo request packet. + // + Request->Type = ICMP_V6_ECHO_REQUEST; + Request->Code = 0; + Request->SequenceNum = SequenceNum; + Request->TimeStamp = TimeStamp; + Request->Identifier = 0; + // + // Leave check sum to ip6 layer, since it has no idea of source address + // selection. + // + Request->Checksum = 0; + + TxData = AllocateZeroPool (sizeof (EFI_IP6_TRANSMIT_DATA)); + + if (TxData == NULL) { + FreePool (Request); + return NULL; + } + // + // Assembly ipv6 token for transmit. + // + TxData->OverrideData = 0; + TxData->ExtHdrsLength = 0; + TxData->ExtHdrs = NULL; + TxData->DataLength = Private->BufferSize; + TxData->FragmentCount = 1; + TxData->FragmentTable[0].FragmentBuffer = (VOID *) Request; + TxData->FragmentTable[0].FragmentLength = Private->BufferSize; + + Token = AllocateZeroPool (sizeof (EFI_IP6_COMPLETION_TOKEN)); + + if (Token == NULL) { + FreePool (Request); + FreePool (TxData); + return NULL; + } + + Token->Status = EFI_ABORTED; + Token->Packet.TxData = TxData; + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ping6OnEchoRequestSent6, + Private, + &Token->Event + ); + + if (EFI_ERROR (Status)) { + FreePool (Request); + FreePool (TxData); + FreePool (Token); + return NULL; + } + + return Token; +} + +/** + Transmit the EFI_IP6_COMPLETION_TOKEN. + + @param[in] Private The pointer of PING6_PRIVATE_DATA. + + @retval EFI_SUCCESS Transmitted successfully. + @retval EFI_OUT_OF_RESOURCES No memory is available on the platform. + @retval others Transmitted unsuccessfully. + +**/ +EFI_STATUS +Ping6SendEchoRequest ( + IN PING6_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + PING6_ICMP6_TX_INFO *TxInfo; + + TxInfo = AllocateZeroPool (sizeof (PING6_ICMP6_TX_INFO)); + + if (TxInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TxInfo->TimeStamp = Ping6ReadTime (); + TxInfo->SequenceNum = (UINT16) (Private->TxCount + 1); + + TxInfo->Token = Ping6GenerateToken ( + Private, + TxInfo->TimeStamp, + TxInfo->SequenceNum + ); + + if (TxInfo->Token == NULL) { + Ping6DestroyTxInfo (TxInfo); + return EFI_OUT_OF_RESOURCES; + } + + Status = Private->Ip6->Transmit (Private->Ip6, TxInfo->Token); + + if (EFI_ERROR (Status)) { + Ping6DestroyTxInfo (TxInfo); + return Status; + } + + InsertTailList (&Private->TxList, &TxInfo->Link); + Private->TxCount++; + + return EFI_SUCCESS; +} + +/** + Place a completion token into the receive packet queue to receive the echo reply. + + @param[in] Private The pointer of PING6_PRIVATE_DATA. + + @retval EFI_SUCCESS Put the token into the receive packet queue successfully. + @retval others Put the token into the receive packet queue unsuccessfully. + +**/ +EFI_STATUS +Ping6OnReceiveEchoReply ( + IN PING6_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + + ZeroMem (&Private->RxToken, sizeof (EFI_IP6_COMPLETION_TOKEN)); + + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ping6OnEchoReplyReceived6, + Private, + &Private->RxToken.Event + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Private->RxToken.Status = EFI_NOT_READY; + + return Private->Ip6->Receive (Private->Ip6, &Private->RxToken); +} + +/** + Remove the timeout request from the list. + + @param[in] Event A EFI_EVENT type event. + @param[in] Context The pointer to Context. + +**/ +VOID +EFIAPI +Ping6OnTimerRoutine6 ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + PING6_PRIVATE_DATA *Private; + PING6_ICMP6_TX_INFO *TxInfo; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + UINT64 Time; + + Private = (PING6_PRIVATE_DATA *) Context; + + // + // Retransmit icmp6 echo request packets per second in sendnumber times. + // + if (Private->TxCount < Private->SendNum) { + + Status = Ping6SendEchoRequest (Private); + if (Private->TxCount != 0){ + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_SEND_REQUEST), gShellNetwork2HiiHandle, Private->TxCount + 1); + } + } + } + // + // Check whether any icmp6 echo request in the list timeout. + // + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) { + TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link); + Time = Ping6CalculateTick (TxInfo->TimeStamp, Ping6ReadTime ()); + + // + // Remove the timeout echo request from txlist. + // + if (Time > PING6_DEFAULT_TIMEOUT) { + + if (EFI_ERROR (TxInfo->Token->Status)) { + Private->Ip6->Cancel (Private->Ip6, TxInfo->Token); + } + // + // Remove the timeout icmp6 echo request from list. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_TIMEOUT), gShellNetwork2HiiHandle, TxInfo->SequenceNum); + + RemoveEntryList (&TxInfo->Link); + Ping6DestroyTxInfo (TxInfo); + + if (IsListEmpty (&Private->TxList) && (Private->TxCount == Private->SendNum)) { + // + // All the left icmp6 echo request in the list timeout. + // + Private->Status = EFI_TIMEOUT; + } + } + } +} + +/** + Create a valid IP6 instance. + + @param[in] Private The pointer of PING6_PRIVATE_DATA. + + @retval EFI_SUCCESS Create a valid IP6 instance successfully. + @retval EFI_ABORTED Locate handle with ip6 service binding protocol unsuccessfully. + @retval EFI_INVALID_PARAMETER The source address is unspecified when the destination address is a link -ocal address. + @retval EFI_OUT_OF_RESOURCES No memory is available on the platform. + @retval EFI_NOT_FOUND The source address is not found. +**/ +EFI_STATUS +Ping6CreateIpInstance ( + IN PING6_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + UINTN HandleIndex; + UINTN HandleNum; + EFI_HANDLE *HandleBuffer; + EFI_SERVICE_BINDING_PROTOCOL *Ip6Sb; + EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; + EFI_IP6_CONFIG_DATA Ip6Config; + EFI_IP6_CONFIG_INTERFACE_INFO *IfInfo; + UINTN IfInfoSize; + EFI_IPv6_ADDRESS *Addr; + UINTN AddrIndex; + + HandleBuffer = NULL; + Ip6Sb = NULL; + IfInfo = NULL; + IfInfoSize = 0; + + // + // Locate all the handles with ip6 service binding protocol. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiIp6ServiceBindingProtocolGuid, + NULL, + &HandleNum, + &HandleBuffer + ); + if (EFI_ERROR (Status) || (HandleNum == 0)) { + return EFI_ABORTED; + } + // + // Source address is required when pinging a link-local address on multi- + // interfaces host. + // + if (NetIp6IsLinkLocalAddr (&Private->DstAddress) && + NetIp6IsUnspecifiedAddr (&Private->SrcAddress) && + (HandleNum > 1)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SOURCE), gShellNetwork2HiiHandle); + Status = EFI_INVALID_PARAMETER; + goto ON_ERROR; + } + // + // For each ip6 protocol, check interface addresses list. + // + for (HandleIndex = 0; HandleIndex < HandleNum; HandleIndex++) { + + Ip6Sb = NULL; + IfInfo = NULL; + IfInfoSize = 0; + + Status = gBS->HandleProtocol ( + HandleBuffer[HandleIndex], + &gEfiIp6ServiceBindingProtocolGuid, + (VOID **) &Ip6Sb + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + if (NetIp6IsUnspecifiedAddr (&Private->SrcAddress)) { + // + // No need to match interface address. + // + break; + } else { + // + // Ip6config protocol and ip6 service binding protocol are installed + // on the same handle. + // + Status = gBS->HandleProtocol ( + HandleBuffer[HandleIndex], + &gEfiIp6ConfigProtocolGuid, + (VOID **) &Ip6Cfg + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + // + // Get the interface information size. + // + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeInterfaceInfo, + &IfInfoSize, + NULL + ); + + if (Status != EFI_BUFFER_TOO_SMALL) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + + IfInfo = AllocateZeroPool (IfInfoSize); + + if (IfInfo == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + // + // Get the interface info. + // + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeInterfaceInfo, + &IfInfoSize, + IfInfo + ); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6CFG_GETDATA), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + // + // Check whether the source address is one of the interface addresses. + // + for (AddrIndex = 0; AddrIndex < IfInfo->AddressInfoCount; AddrIndex++) { + + Addr = &(IfInfo->AddressInfo[AddrIndex].Address); + if (EFI_IP6_EQUAL (&Private->SrcAddress, Addr)) { + // + // Match a certain interface address. + // + break; + } + } + + if (AddrIndex < IfInfo->AddressInfoCount) { + // + // Found a nic handle with right interface address. + // + break; + } + } + + FreePool (IfInfo); + IfInfo = NULL; + } + // + // No exact interface address matched. + // + + if (HandleIndex == HandleNum) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_SOURCE_NOT_FOUND), gShellNetwork2HiiHandle, mIp6SrcString); + Status = EFI_NOT_FOUND; + goto ON_ERROR; + } + + Private->NicHandle = HandleBuffer[HandleIndex]; + + ASSERT (Ip6Sb != NULL); + Status = Ip6Sb->CreateChild (Ip6Sb, &Private->Ip6ChildHandle); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status = gBS->OpenProtocol ( + Private->Ip6ChildHandle, + &gEfiIp6ProtocolGuid, + (VOID **) &Private->Ip6, + Private->ImageHandle, + Private->Ip6ChildHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + ZeroMem (&Ip6Config, sizeof (EFI_IP6_CONFIG_DATA)); + + // + // Configure the ip6 instance for icmp6 packet exchange. + // + Ip6Config.DefaultProtocol = 58; + Ip6Config.AcceptAnyProtocol = FALSE; + Ip6Config.AcceptIcmpErrors = TRUE; + Ip6Config.AcceptPromiscuous = FALSE; + Ip6Config.TrafficClass = 0; + Ip6Config.HopLimit = 128; + Ip6Config.FlowLabel = 0; + Ip6Config.ReceiveTimeout = 0; + Ip6Config.TransmitTimeout = 0; + + IP6_COPY_ADDRESS (&Ip6Config.StationAddress, &Private->SrcAddress); + + IP6_COPY_ADDRESS (&Ip6Config.DestinationAddress, &Private->DstAddress); + + Status = Private->Ip6->Configure (Private->Ip6, &Ip6Config); + + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_IP6_CONFIG), gShellNetwork2HiiHandle, Status); + goto ON_ERROR; + } + + return EFI_SUCCESS; + +ON_ERROR: + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + if (IfInfo != NULL) { + FreePool (IfInfo); + } + + if ((Ip6Sb != NULL) && (Private->Ip6ChildHandle != NULL)) { + Ip6Sb->DestroyChild (Ip6Sb, Private->Ip6ChildHandle); + } + + return Status; +} + +/** + Destroy the IP6 instance. + + @param[in] Private The pointer of PING6_PRIVATE_DATA. + +**/ +VOID +Ping6DestroyIpInstance ( + IN PING6_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + EFI_SERVICE_BINDING_PROTOCOL *Ip6Sb; + + gBS->CloseProtocol ( + Private->Ip6ChildHandle, + &gEfiIp6ProtocolGuid, + Private->ImageHandle, + Private->Ip6ChildHandle + ); + + Status = gBS->HandleProtocol ( + Private->NicHandle, + &gEfiIp6ServiceBindingProtocolGuid, + (VOID **) &Ip6Sb + ); + + if (!EFI_ERROR(Status)) { + Ip6Sb->DestroyChild (Ip6Sb, Private->Ip6ChildHandle); + } +} + +/** + The Ping6 Process. + + @param[in] ImageHandle The firmware allocated handle for the UEFI image. + @param[in] SendNumber The send request count. + @param[in] BufferSize The send buffer size. + @param[in] SrcAddress The source IPv6 address. + @param[in] DstAddress The destination IPv6 address. + + @retval SHELL_SUCCESS The ping6 processed successfullly. + @retval others The ping6 processed unsuccessfully. + +**/ +SHELL_STATUS +ShellPing6 ( + IN EFI_HANDLE ImageHandle, + IN UINT32 SendNumber, + IN UINT32 BufferSize, + IN EFI_IPv6_ADDRESS *SrcAddress, + IN EFI_IPv6_ADDRESS *DstAddress + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + PING6_PRIVATE_DATA *Private; + PING6_ICMP6_TX_INFO *TxInfo; + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + SHELL_STATUS ShellStatus; + + ShellStatus = SHELL_SUCCESS; + Private = AllocateZeroPool (sizeof (PING6_PRIVATE_DATA)); + + ASSERT (Private != NULL); + + Private->ImageHandle = ImageHandle; + Private->SendNum = SendNumber; + Private->BufferSize = BufferSize; + Private->RttMin = ~((UINT64 )(0x0)); + Private->Status = EFI_NOT_READY; + + InitializeListHead (&Private->TxList); + + IP6_COPY_ADDRESS (&Private->SrcAddress, SrcAddress); + IP6_COPY_ADDRESS (&Private->DstAddress, DstAddress); + + // + // Open and configure a ip6 instance for ping6. + // + Status = Ping6CreateIpInstance (Private); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Print the command line itself. + // + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_START), gShellNetwork2HiiHandle, mIp6DstString, Private->BufferSize); + // + // Create a ipv6 token to receive the first icmp6 echo reply packet. + // + Status = Ping6OnReceiveEchoReply (Private); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Create and start timer to send icmp6 echo request packet per second. + // + Status = gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + Ping6OnTimerRoutine6, + Private, + &Private->Timer + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Create a ipv6 token to send the first icmp6 echo request packet. + // + Status = Ping6SendEchoRequest (Private); + // + // EFI_NOT_READY for IPsec is enable and IKE is not established. + // + if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) { + ShellStatus = SHELL_ACCESS_DENIED; + if(Status == EFI_NOT_FOUND) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_NOSOURCE_INDOMAIN), gShellNetwork2HiiHandle, mIp6DstString); + } + + goto ON_EXIT; + } + + Status = gBS->SetTimer ( + Private->Timer, + TimerPeriodic, + PING6_ONE_SECOND + ); + + if (EFI_ERROR (Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Control the ping6 process by two factors: + // 1. Hot key + // 2. Private->Status + // 2.1. success means all icmp6 echo request packets get reply packets. + // 2.2. timeout means the last icmp6 echo reply request timeout to get reply. + // 2.3. noready means ping6 process is on-the-go. + // + while (Private->Status == EFI_NOT_READY) { + Private->Ip6->Poll (Private->Ip6); + + // + // Terminate the ping6 process by 'esc' or 'ctl-c'. + // + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + + if (!EFI_ERROR(Status)) { + if ((Key.UnicodeChar == 0x1b) || (Key.UnicodeChar == 0x03) || + ((Key.UnicodeChar == 0) && (Key.ScanCode == SCAN_ESC))) { + goto ON_STAT; + } + } + } + +ON_STAT: + // + // Display the statistics in all. + // + gBS->SetTimer (Private->Timer, TimerCancel, 0); + + if (Private->TxCount != 0) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_PING6_STAT), + gShellNetwork2HiiHandle, + Private->TxCount, + Private->RxCount, + (100 * (Private->TxCount - Private->RxCount)) / Private->TxCount, + Private->RttSum + ); + } + + if (Private->RxCount != 0) { + ShellPrintHiiEx ( + -1, + -1, + NULL, + STRING_TOKEN (STR_PING6_RTT), + gShellNetwork2HiiHandle, + Private->RttMin, + Private->RttMax, + DivU64x64Remainder (Private->RttSum, Private->RxCount, NULL) + ); + } + +ON_EXIT: + + if (Private != NULL) { + Private->Status = EFI_ABORTED; + + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->TxList) { + TxInfo = BASE_CR (Entry, PING6_ICMP6_TX_INFO, Link); + + Status = Private->Ip6->Cancel (Private->Ip6, TxInfo->Token); + + RemoveEntryList (&TxInfo->Link); + Ping6DestroyTxInfo (TxInfo); + } + + if (Private->Timer != NULL) { + gBS->CloseEvent (Private->Timer); + } + + if (Private->Ip6 != NULL) { + Status = Private->Ip6->Cancel (Private->Ip6, &Private->RxToken); + } + + if (Private->RxToken.Event != NULL) { + gBS->CloseEvent (Private->RxToken.Event); + } + + if (Private->Ip6ChildHandle != NULL) { + Ping6DestroyIpInstance (Private); + } + + FreePool (Private); + } + + return ShellStatus; +} + +/** + Function for 'ping6' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). + + @retval SHELL_SUCCESS The ping6 processed successfullly. + @retval others The ping6 processed unsuccessfully. + +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunPing6 ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SHELL_STATUS ShellStatus; + EFI_IPv6_ADDRESS DstAddress; + EFI_IPv6_ADDRESS SrcAddress; + UINT64 BufferSize; + UINTN SendNumber; + LIST_ENTRY *ParamPackage; + CONST CHAR16 *ValueStr; + CONST CHAR16 *ValueStrPtr; + UINTN NonOptionCount; + CHAR16 *ProblemParam; + + ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + + Status = ShellCommandLineParseEx (Ping6ParamList, &ParamPackage, &ProblemParam, TRUE, FALSE); + if (EFI_ERROR(Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_INPUT), gShellNetwork2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + + SendNumber = 10; + BufferSize = 16; + + // + // Parse the paramter of count number. + // + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-n"); + ValueStrPtr = ValueStr; + if (ValueStr != NULL) { + SendNumber = ShellStrToUintn (ValueStrPtr); + + // + // ShellStrToUintn will return 0 when input is 0 or an invalid input string. + // + if ((SendNumber == 0) || (SendNumber > PING6_MAX_SEND_NUMBER)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_SEND_NUMBER), gShellNetwork2HiiHandle, ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + // + // Parse the paramter of buffer size. + // + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-l"); + ValueStrPtr = ValueStr; + if (ValueStr != NULL) { + BufferSize = ShellStrToUintn (ValueStrPtr); + + // + // ShellStrToUintn will return 0 when input is 0 or an invalid input string. + // + if ((BufferSize < 16) || (BufferSize > PING6_MAX_BUFFER_SIZE)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_BUFFER_SIZE), gShellNetwork2HiiHandle, ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + + ZeroMem (&SrcAddress, sizeof (EFI_IPv6_ADDRESS)); + ZeroMem (&DstAddress, sizeof (EFI_IPv6_ADDRESS)); + + // + // Parse the paramter of source ip address. + // + ValueStr = ShellCommandLineGetValue (ParamPackage, L"-s"); + ValueStrPtr = ValueStr; + if (ValueStr != NULL) { + mIp6SrcString = ValueStr; + Status = NetLibStrToIp6 (ValueStrPtr, &SrcAddress); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_IP), gShellNetwork2HiiHandle, ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + // + // Parse the paramter of destination ip address. + // + NonOptionCount = ShellCommandLineGetCount(ParamPackage); + ValueStr = ShellCommandLineGetRawValue (ParamPackage, (UINT32)(NonOptionCount-1)); + if (NonOptionCount != 2) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_INPUT), gShellNetwork2HiiHandle); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + ValueStrPtr = ValueStr; + if (ValueStr != NULL) { + mIp6DstString = ValueStr; + Status = NetLibStrToIp6 (ValueStrPtr, &DstAddress); + if (EFI_ERROR (Status)) { + ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PING6_INVALID_IP), gShellNetwork2HiiHandle, ValueStr); + ShellStatus = SHELL_INVALID_PARAMETER; + goto ON_EXIT; + } + } + // + // Get frequency to calculate the time from ticks. + // + Status = Ping6GetFrequency (); + + if (EFI_ERROR(Status)) { + ShellStatus = SHELL_ACCESS_DENIED; + goto ON_EXIT; + } + // + // Enter into ping6 process. + // + ShellStatus = ShellPing6 ( + ImageHandle, + (UINT32)SendNumber, + (UINT32)BufferSize, + &SrcAddress, + &DstAddress + ); + +ON_EXIT: + ShellCommandLineFreeVarList (ParamPackage); + return ShellStatus; +} + diff --git a/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.c b/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.c new file mode 100644 index 0000000000..6837b3a7d3 --- /dev/null +++ b/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.c @@ -0,0 +1,91 @@ +/** @file + Main file for NULL named library for network2 shell command functions. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials are licensed and made available under + the terms and conditions of the BSD License which accompanies this distribution. + The full text of the license may be found at http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#include "UefiShellNetwork2CommandsLib.h" + +CONST CHAR16 gShellNetwork2FileName[] = L"ShellCommands"; +EFI_HANDLE gShellNetwork2HiiHandle = NULL; + +/** + return the file name of the help text file if not using HII. + + @return The string pointer to the file name. +**/ +CONST CHAR16* +EFIAPI +ShellCommandGetManFileNameNetwork2 ( + VOID + ) +{ + return (gShellNetwork2FileName); +} + +/** + Constructor for the Shell Network2 Commands library. + + Install the handlers for Network2 UEFI Shell 2.0 profile commands. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS The shell command handlers were installed sucessfully. + @retval EFI_UNSUPPORTED The shell level required was not found. +**/ +EFI_STATUS +EFIAPI +ShellNetwork2CommandsLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + gShellNetwork2HiiHandle = NULL; + + // + // check our bit of the profiles mask + // + if ((PcdGet8(PcdShellProfileMask) & BIT4) == 0) { + return (EFI_SUCCESS); + } + + gShellNetwork2HiiHandle = HiiAddPackages (&gShellNetwork2HiiGuid, gImageHandle, UefiShellNetwork2CommandsLibStrings, NULL); + if (gShellNetwork2HiiHandle == NULL) { + return (EFI_DEVICE_ERROR); + } + // + // install our shell command handlers + // + ShellCommandRegisterCommandName(L"ping6", ShellCommandRunPing6 , ShellCommandGetManFileNameNetwork2, 0, L"network2", TRUE , gShellNetwork2HiiHandle, STRING_TOKEN(STR_GET_HELP_PING6)); + ShellCommandRegisterCommandName(L"ifconfig6",ShellCommandRunIfconfig6 , ShellCommandGetManFileNameNetwork2, 0, L"network2", TRUE , gShellNetwork2HiiHandle, STRING_TOKEN(STR_GET_HELP_IFCONFIG6)); + + return EFI_SUCCESS; + +} + +/** + Destructor for the library. free any resources. + + @param ImageHandle The image handle of the process. + @param SystemTable The EFI System Table pointer. +**/ +EFI_STATUS +EFIAPI +ShellNetwork2CommandsLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (gShellNetwork2HiiHandle != NULL) { + HiiRemovePackages(gShellNetwork2HiiHandle); + } + return EFI_SUCCESS; +} + diff --git a/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.h b/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.h new file mode 100644 index 0000000000..138cc8c8d4 --- /dev/null +++ b/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.h @@ -0,0 +1,72 @@ +/** @file + Main file for NULL named library for network2 shell command functions. + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ This program and the accompanying materials are licensed and made available under + the terms and conditions of the BSD License which accompanies this distribution. + The full text of the license may be found at http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _UEFI_SHELL_NETWORK2_COMMANDS_LIB_H_ +#define _UEFI_SHELL_NETWORK2_COMMANDS_LIB_H_ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern EFI_HANDLE gShellNetwork2HiiHandle; + +/** + Function for 'ping6' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). + + @retval SHELL_SUCCESS The ping6 processed successfullly. + @retval others The ping6 processed unsuccessfully. + +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunPing6 ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Function for 'ifconfig6' command. + + @param[in] ImageHandle Handle to the Image (NULL if Internal). + @param[in] SystemTable Pointer to the System Table (NULL if Internal). + + @retval SHELL_SUCCESS The ifconfig6 command processed successfully. + @retval others The ifconfig6 command process failed. + +**/ +SHELL_STATUS +EFIAPI +ShellCommandRunIfconfig6 ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +#endif + diff --git a/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf b/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf new file mode 100644 index 0000000000..426efcc655 --- /dev/null +++ b/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf @@ -0,0 +1,63 @@ +## @file +# Provides shell network2 functions +# +# Copyright (c) 2016, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = UefiShellNetwork2CommandsLib + FILE_GUID = D94E3B82-908E-46bf-A7B9-C7B7F17B1B7D + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellNetwork2CommandsLibConstructor + DESTRUCTOR = ShellNetwork2CommandsLibDestructor + +[Sources.common] + UefiShellNetwork2CommandsLib.uni + UefiShellNetwork2CommandsLib.c + UefiShellNetwork2CommandsLib.h + Ping6.c + Ifconfig6.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + BaseMemoryLib + DebugLib + ShellCommandLib + ShellLib + UefiLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + PcdLib + HiiLib + FileHandleLib + NetLib + +[Pcd] + gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask ## CONSUMES + +[Protocols] + gEfiCpuArchProtocolGuid ## CONSUMES + gEfiIp6ProtocolGuid ## SOMETIMES_CONSUMES + gEfiIp6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES + gEfiIp6ConfigProtocolGuid ## SOMETIMES_CONSUMES + +[Guids] + gShellNetwork2HiiGuid ## SOMETIMES_CONSUMES ## HII diff --git a/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.uni b/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.uni new file mode 100644 index 0000000000..fb2bfab2bd --- /dev/null +++ b/ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.uni @@ -0,0 +1,151 @@ +/** @file + + String definitions for UEFI Shell network 2 commands + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions + of the BSD License which accompanies this distribution. The full + text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + Module Name: + + UefiShellNetwork2CommandsLib.uni + + Abstract: + + String definitions for UEFI Shell 2.0 network 2 commands +**/ + +#langdef en-US "english" + +#string STR_PING6_INVALID_IP #language en-US "%Ping6: Invalid IP6 address, %s\r\n" +#string STR_PING6_INVALID_INPUT #language en-US "%Ping6: Invalid input, please type 'Ping6 -?'for help\r\n" +#string STR_PING6_INVALID_SEND_NUMBER #language en-US "%Ping6: Invalid send number, %s\r\n" +#string STR_PING6_INVALID_BUFFER_SIZE #language en-US "%Ping6: Invalid buffer size, %s\r\n" +#string STR_PING6_INVALID_SOURCE #language en-US "%Ping6: Require source interface option\r\n" +#string STR_PING6_IP6_CONFIG #language en-US "%Ping6: The process of Ip6 Configure %r\r\n" +#string STR_PING6_IP6CFG_GETDATA #language en-US "%Ping6: Get data of the interface information %r\r\n" +#string STR_PING6_SEND_REQUEST #language en-US "Echo request sequence %d fails.\r\n" +#string STR_PING6_SOURCE_NOT_FOUND #language en-US "Source %s not found.\r\n" +#string STR_PING6_NOSOURCE_INDOMAIN #language en-US "No sources in %s's multicast domain.\r\n" +#string STR_PING6_START #language en-US "Ping %s %d data bytes\r\n" +#string STR_PING6_TIMEOUT #language en-US "Echo request sequence %d timeout.\r\n" +#string STR_PING6_REPLY_INFO #language en-US "%d bytes from %s : icmp_seq=%d ttl=%d time%c%dms\r\n" +#string STR_PING6_STAT #language en-US "\n%d packets transmitted, %d received, %d%% packet loss, time %dms\r\n" +#string STR_PING6_RTT #language en-US "\nRtt(round trip time) min=%dms max=%dms avg=%dms\r\n" + +#string STR_IFCONFIG6_ERR_IP6CFG_GETDATA #language en-US "Get data of the interface information %hr\r\n" +#string STR_IFCONFIG6_INFO_BREAK #language en-US "-----------------------------------------------------------------" +#string STR_IFCONFIG6_INFO_COLON #language en-US ":" +#string STR_IFCONFIG6_INFO_JOINT #language en-US " >> " +#string STR_IFCONFIG6_INFO_NEWLINE #language en-US "\r\n" +#string STR_IFCONFIG6_INFO_IF_NAME #language en-US "\n%Hname : %s%N\r\n" +#string STR_IFCONFIG6_INFO_POLICY_AUTO #language en-US "%Hpolicy : automatic%N\r\n" +#string STR_IFCONFIG6_INFO_POLICY_MAN #language en-US "%Hpolicy : manual%N\r\n" +#string STR_IFCONFIG6_INFO_DAD_TRANSMITS #language en-US "%Hdad xmits : %d%N\r\n" +#string STR_IFCONFIG6_INFO_INTERFACE_ID_HEAD #language en-US "%Hinterface id : %N" +#string STR_IFCONFIG6_INFO_MAC_ADDR_HEAD #language en-US "%Hmac addr : %N" +#string STR_IFCONFIG6_INFO_MAC_ADDR_BODY #language en-US "%02x" +#string STR_IFCONFIG6_INFO_IP_ADDR_HEAD #language en-US "\n%Hhost addr : %N\r\n" +#string STR_IFCONFIG6_INFO_DNS_ADDR_HEAD #language en-US "\n%Hdns server : %N\r\n" +#string STR_IFCONFIG6_INFO_IP_ADDR_BODY #language en-US "%02x" +#string STR_IFCONFIG6_INFO_IP_ADDR_BODY4BIT #language en-US "%x" +#string STR_IFCONFIG6_INFO_ROUTE_HEAD #language en-US "\n%Hroute table : %N\r\n" +#string STR_IFCONFIG6_INFO_PREFIX_LEN #language en-US "/%d" +#string STR_IFCONFIG6_LINE_HELP #language en-US "Displays or modifies the IPv6 configuration" +#string STR_IFCONFIG6_ERR_LACK_INTERFACE #language en-US "Lack interface name.\r\n" + "Usage: IfConfig6 -s \r\n" + "Example: IfConfig6 -s eth0 auto\r\n" +#string STR_IFCONFIG6_LACK_OPTION #language en-US "Flags lack. Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_CONFLICT_OPTIONS #language en-US "Flags conflict. Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_LACK_COMMAND #language en-US "Lack interface config option.\r\n" + "Hint: Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_INVALID_INTERFACE #language en-US "Invalid interface name.\r\n" + "Hint: Use {IfConfig6 -l} to check existing interface names.\r\n" +#string STR_IFCONFIG6_ERR_INVALID_COMMAND #language en-US "Invalid command. Bad command %H%s%N is skipped.\r\n" + "Hint: Incorrect option or arguments. Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_LACK_ARGUMENTS #language en-US "Lack arguments. Bad command %H%s%N is skipped.\r\n" + "Hint: Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_LACK_OPTION #language en-US "Lack options.\r\n" + "Hint: Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_MAN_HOST #language en-US "Manual address configuration failed. Please retry.\r\n" +#string STR_IFCONFIG6_ERR_DUPLICATE_COMMAND #language en-US "Duplicate commands. Bad command %H%s%N is skipped.\r\n" + "Hint: Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_CONFLICT_COMMAND #language en-US "Conflict commands. Bad command %H%s%N is skipped.\r\n" + "Hint: Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_UNKNOWN_COMMAND #language en-US "Unknown commands. Bad command %H%s%N is skipped.\r\n" + "Hint: Please type 'IfConfig6 -?' for help info.\r\n" +#string STR_IFCONFIG6_ERR_ADDRESS_FAILED #language en-US "It failed to set .\r\n" + + +#string STR_GET_HELP_PING6 #language en-US "" +".TH ping6 0 "Ping a target machine with UEFI IPv6 network stack."\r\n" +".SH NAME\r\n" +"Ping a target machine with UEFI IPv6 network stack.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"Ping6 [-l size] [-n count] [-s SourceIp] TargetIp\r\n" +".SH OPTIONS\r\n" +" \r\n" +" -l size Send buffer size, in bytes(default=16, min=16, max=32768).\r\n" +" -n count Send request count, (default=10, min=1, max=10000).\r\n" +" -s SourceIp Source IPv6 address.\r\n" +" TargetIp Target IPv6 address.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"Examples:\r\n" +" * To ping the target host by sending 5 request with 1000 bytes from 2002::1\r\n" +" Shell:\> Ping6 -s 2002::1 2002::2 -l 1000 -n 5\r\n" +" \r\n" +" * To ping the target host with 1000 bytes\r\n" +" Shell:\> Ping6 2002::2 -l 1000\r\n" + +#string STR_GET_HELP_IFCONFIG6 #language en-US "" +".TH ifconfig6 0 "Displays or modifies IPv6 configuration for network interface."\r\n" +".SH NAME\r\n" +"Displays or modifies IPv6 configuration for network interface.\r\n" +".SH SYNOPSIS\r\n" +" \r\n" +"IfConfig6 -r [Name] | -l [Name] \r\n" +"IfConfig6 -s [dad ] [auto | [man [id ] [host gw ]\r\n" +" [dns ]]]\r\n" +".SH OPTIONS\r\n" +" \r\n" +" Name Adapter name, i.e., eth0\r\n" +" -r [Name] Reconfigure all or specified interface, and set\r\n" +" automatic policy. If specified interface is already\r\n" +" set to automatic,then refresh the IPv6 configuration.\r\n" +" -l [Name] List the configuration of the specified interface.\r\n" +" -s dad Set dad transmits count of the specified interface.\r\n" +" -s auto Set automatic policy of the specified interface.\r\n" +" -s man id Set alternative interface id of the specified \r\n" +" interface. Must under manual policy.\r\n" +" -s man host gw \r\n" +" Set static host IP and gateway address of the\r\n" +" specified interface. Must under manual policy.\r\n" +" -s man dns Set DNS server IP addresses of the specified\r\n" +" interface.Must under manual policy.\r\n" +".SH EXAMPLES\r\n" +" \r\n" +"EXAMPLES:\r\n" +" * To list the configuration for the interface eth0:\r\n" +" Shell:\> ifConfig6 -l eth0\r\n" +" \r\n" +" * To use automatic configuration to request the IPv6 address configuration\r\n" +" dynamically for the interface eth0:\r\n" +" Shell:\> ifconfig6 -s eth0 auto\r\n" +" \r\n" +" * To set the dad transmits count for eth0 under automatic policy:\r\n" +" Shell:\> ifconfig6 -s eth0 auto dad 10\r\n" +" \r\n" +" * To set the alternative interface id of eth0 under manual policy:\r\n" +" Shell:\> ifconfig6 -s eth0 man id ff:dd:aa:88:66:cc\r\n" +" \r\n" +" * To use the static IP6 addresses configuration for the interface eth0,\r\n" +" and this configuration survives the network reload:\r\n" +" Shell:\> ifconfig6 -s eth0 man host 2002::1/64 2002::2/64 gw 2002::3/64\r\n" diff --git a/ShellPkg/ShellPkg.dec b/ShellPkg/ShellPkg.dec index 76a2b7db97..39f8012b98 100644 --- a/ShellPkg/ShellPkg.dec +++ b/ShellPkg/ShellPkg.dec @@ -2,7 +2,7 @@ # This Package provides all definitions for EFI and UEFI Shell # # (C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.
-# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.
# # This program and the accompanying materials are licensed and made available under # the terms and conditions of the BSD License which accompanies this distribution. @@ -53,6 +53,7 @@ gShellLevel2HiiGuid = {0xf95a7ccc, 0x4c55, 0x4426, {0xa7, 0xb4, 0xdc, 0x89, 0x61, 0x95, 0xb, 0xae}} gShellLevel3HiiGuid = {0x4344558d, 0x4ef9, 0x4725, {0xb1, 0xe4, 0x33, 0x76, 0xe8, 0xd6, 0x97, 0x4f}} gShellNetwork1HiiGuid = {0xf3d301bb, 0xf4a5, 0x45a8, {0xb0, 0xb7, 0xfa, 0x99, 0x9c, 0x62, 0x37, 0xae}} + gShellNetwork2HiiGuid = {0x174b2b5, 0xf505, 0x4b12, {0xaa, 0x60, 0x59, 0xdf, 0xf8, 0xd6, 0xea, 0x37}} gShellTftpHiiGuid = {0x738a9314, 0x82c1, 0x4592, {0x8f, 0xf7, 0xc1, 0xbd, 0xf1, 0xb2, 0x0e, 0xd4}} gShellBcfgHiiGuid = {0x5f5f605d, 0x1583, 0x4a2d, {0xa6, 0xb2, 0xeb, 0x12, 0xda, 0xb4, 0xa2, 0xb6}} @@ -94,6 +95,7 @@ # bit 1 = Debug1 # bit 2 = Install1 # bit 3 = Network1 + # bit 4 = Network2 gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask|0xFF|UINT8|0x0000000D ## This is the character count for allocation for consistent mappings diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc index b29adb8416..364a622452 100644 --- a/ShellPkg/ShellPkg.dsc +++ b/ShellPkg/ShellPkg.dsc @@ -28,7 +28,7 @@ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLibOptionalDevicePathProtocol.inf DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf - DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf UefiLib|MdePkg/Library/UefiLib/UefiLib.inf @@ -46,7 +46,7 @@ ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf - + PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf @@ -88,6 +88,7 @@ ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf + ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.inf ShellPkg/Library/UefiDpLib/UefiDpLib.inf { @@ -107,6 +108,7 @@ NULL|ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf NULL|ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf NULL|ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf + NULL|ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf !ifdef $(INCLUDE_DP) NULL|ShellPkg/Library/UefiDpLib/UefiDpLib.inf !endif #$(INCLUDE_DP)