From 43ca17532bd7292eee5ad979e26b19ddd0d3e55a Mon Sep 17 00:00:00 2001 From: "Zhang, Lubo" Date: Wed, 2 Mar 2016 10:13:54 +0800 Subject: ShellPkg: Merge Ping6 and Ifconfig6 tools to Shell command. According to the new Shell spec, we add Network2 profile and merge Ping6 and Ifconfig6 tools to Shell command. Cc: Carsey Jaben Cc: Wu Jiaxin Cc: Ye Ting Cc: Fu Siyuan Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo Reviewed-By: Jaben Carsey Reviewed-by: Jiaxin Wu --- .../UefiShellNetwork2CommandsLib/Ifconfig6.c | 1839 ++++++++++++++++++++ .../Library/UefiShellNetwork2CommandsLib/Ping6.c | 1247 +++++++++++++ .../UefiShellNetwork2CommandsLib.c | 91 + .../UefiShellNetwork2CommandsLib.h | 72 + .../UefiShellNetwork2CommandsLib.inf | 63 + .../UefiShellNetwork2CommandsLib.uni | 151 ++ 6 files changed, 3463 insertions(+) create mode 100644 ShellPkg/Library/UefiShellNetwork2CommandsLib/Ifconfig6.c create mode 100644 ShellPkg/Library/UefiShellNetwork2CommandsLib/Ping6.c create mode 100644 ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.c create mode 100644 ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.h create mode 100644 ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf create mode 100644 ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.uni (limited to 'ShellPkg/Library/UefiShellNetwork2CommandsLib') 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" -- cgit v1.2.3