X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;ds=sidebyside;f=NetworkPkg%2FUefiPxeBcDxe%2FPxeBcDhcp6.c;h=425e0cf8061de1392178a03ef7de211d7457f913;hb=HEAD;hp=07f1724365f4dc7078d2c833ec4abefe9808ae93;hpb=07f986f134abf85b4b1f360ca3c86f22cd9f92da;p=mirror_edk2.git diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c index 07f1724365..425e0cf806 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c @@ -2,15 +2,9 @@ Functions implementation related with DHCPv6 for UefiPxeBc Driver. (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
- Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2018, 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. + SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -21,7 +15,9 @@ // // ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2 // -EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress = {{0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}}; +EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress = { + { 0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2 } +}; /** Parse out a DHCPv6 option by OptTag, and find the position in buffer. @@ -31,40 +27,37 @@ EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress = {{0xFF, 2, 0, 0, 0, 0, 0, 0, @param[in] OptTag The required option tag. @retval NULL Failed to parse the required option. - @retval Others The postion of the required option in buffer. + @retval Others The position of the required option in buffer. **/ EFI_DHCP6_PACKET_OPTION * PxeBcParseDhcp6Options ( - IN UINT8 *Buffer, - IN UINT32 Length, - IN UINT16 OptTag + IN UINT8 *Buffer, + IN UINT32 Length, + IN UINT16 OptTag ) { - EFI_DHCP6_PACKET_OPTION *Option; - UINT32 Offset; + EFI_DHCP6_PACKET_OPTION *Option; + UINT32 Offset; - Option = (EFI_DHCP6_PACKET_OPTION *) Buffer; - Offset = 0; + Option = (EFI_DHCP6_PACKET_OPTION *)Buffer; + Offset = 0; // // OpLen and OpCode here are both stored in network order. // while (Offset < Length) { - if (NTOHS (Option->OpCode) == OptTag) { - return Option; } - Offset += (NTOHS(Option->OpLen) + 4); - Option = (EFI_DHCP6_PACKET_OPTION *) (Buffer + Offset); + Offset += (NTOHS (Option->OpLen) + 4); + Option = (EFI_DHCP6_PACKET_OPTION *)(Buffer + Offset); } return NULL; } - /** Build the options buffer for the DHCPv6 request packet. @@ -77,68 +70,70 @@ PxeBcParseDhcp6Options ( **/ UINT32 PxeBcBuildDhcp6Options ( - IN PXEBC_PRIVATE_DATA *Private, - OUT EFI_DHCP6_PACKET_OPTION **OptList, - IN UINT8 *Buffer + IN PXEBC_PRIVATE_DATA *Private, + OUT EFI_DHCP6_PACKET_OPTION **OptList, + IN UINT8 *Buffer ) { - PXEBC_DHCP6_OPTION_ENTRY OptEnt; - UINT32 Index; - UINT16 Value; + PXEBC_DHCP6_OPTION_ENTRY OptEnt; + UINT32 Index; + UINT16 Value; - Index = 0; - OptList[0] = (EFI_DHCP6_PACKET_OPTION *) Buffer; + Index = 0; + OptList[0] = (EFI_DHCP6_PACKET_OPTION *)Buffer; // // Append client option request option // - OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_ORO); - OptList[Index]->OpLen = HTONS (4); - OptEnt.Oro = (PXEBC_DHCP6_OPTION_ORO *) OptList[Index]->Data; - OptEnt.Oro->OpCode[0] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_URL); - OptEnt.Oro->OpCode[1] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_PARAM); + OptList[Index]->OpCode = HTONS (DHCP6_OPT_ORO); + OptList[Index]->OpLen = HTONS (8); + OptEnt.Oro = (PXEBC_DHCP6_OPTION_ORO *)OptList[Index]->Data; + OptEnt.Oro->OpCode[0] = HTONS (DHCP6_OPT_BOOT_FILE_URL); + OptEnt.Oro->OpCode[1] = HTONS (DHCP6_OPT_BOOT_FILE_PARAM); + OptEnt.Oro->OpCode[2] = HTONS (DHCP6_OPT_DNS_SERVERS); + OptEnt.Oro->OpCode[3] = HTONS (DHCP6_OPT_VENDOR_CLASS); Index++; - OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); + OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); // // Append client network device interface option // - OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_UNDI); - OptList[Index]->OpLen = HTONS ((UINT16)3); - OptEnt.Undi = (PXEBC_DHCP6_OPTION_UNDI *) OptList[Index]->Data; + OptList[Index]->OpCode = HTONS (DHCP6_OPT_UNDI); + OptList[Index]->OpLen = HTONS ((UINT16)3); + OptEnt.Undi = (PXEBC_DHCP6_OPTION_UNDI *)OptList[Index]->Data; if (Private->Nii != NULL) { - OptEnt.Undi->Type = Private->Nii->Type; - OptEnt.Undi->MajorVer = Private->Nii->MajorVer; - OptEnt.Undi->MinorVer = Private->Nii->MinorVer; + OptEnt.Undi->Type = Private->Nii->Type; + OptEnt.Undi->MajorVer = Private->Nii->MajorVer; + OptEnt.Undi->MinorVer = Private->Nii->MinorVer; } else { - OptEnt.Undi->Type = DEFAULT_UNDI_TYPE; - OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR; - OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR; + OptEnt.Undi->Type = DEFAULT_UNDI_TYPE; + OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR; + OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR; } Index++; - OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); + OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); // // Append client system architecture option // - OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_ARCH); - OptList[Index]->OpLen = HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTION_ARCH)); - OptEnt.Arch = (PXEBC_DHCP6_OPTION_ARCH *) OptList[Index]->Data; - Value = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE); + OptList[Index]->OpCode = HTONS (DHCP6_OPT_ARCH); + OptList[Index]->OpLen = HTONS ((UINT16)sizeof (PXEBC_DHCP6_OPTION_ARCH)); + OptEnt.Arch = (PXEBC_DHCP6_OPTION_ARCH *)OptList[Index]->Data; + Value = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE); CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16)); Index++; - OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); + OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); // // Append vendor class option to store the PXE class identifier. // - OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_VENDOR_CLASS); - OptList[Index]->OpLen = HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS)); - OptEnt.VendorClass = (PXEBC_DHCP6_OPTION_VENDOR_CLASS *) OptList[Index]->Data; + OptList[Index]->OpCode = HTONS (DHCP6_OPT_VENDOR_CLASS); + OptList[Index]->OpLen = HTONS ((UINT16)sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS)); + OptEnt.VendorClass = (PXEBC_DHCP6_OPTION_VENDOR_CLASS *)OptList[Index]->Data; OptEnt.VendorClass->Vendor = HTONL (PXEBC_DHCP6_ENTERPRISE_NUM); - OptEnt.VendorClass->ClassLen = HTONS ((UINT16) sizeof (PXEBC_CLASS_ID)); + OptEnt.VendorClass->ClassLen = HTONS ((UINT16)sizeof (PXEBC_CLASS_ID)); CopyMem ( &OptEnt.VendorClass->ClassId, DEFAULT_CLASS_ID_DATA, @@ -173,53 +168,203 @@ PxeBcBuildDhcp6Options ( return Index; } - /** Cache the DHCPv6 packet. @param[in] Dst The pointer to the cache buffer for DHCPv6 packet. @param[in] Src The pointer to the DHCPv6 packet to be cached. + @retval EFI_SUCCESS Packet is copied. + @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet. + **/ -VOID +EFI_STATUS PxeBcCacheDhcp6Packet ( - IN EFI_DHCP6_PACKET *Dst, - IN EFI_DHCP6_PACKET *Src + IN EFI_DHCP6_PACKET *Dst, + IN EFI_DHCP6_PACKET *Src ) { - ASSERT (Dst->Size >= Src->Length); + if (Dst->Size < Src->Length) { + return EFI_BUFFER_TOO_SMALL; + } CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length); Dst->Length = Src->Length; -} + return EFI_SUCCESS; +} /** - Free all the nodes in the list for boot file. + Retrieve the boot server address using the EFI_DNS6_PROTOCOL. - @param[in] Head The pointer to the head of list. + @param[in] Private Pointer to PxeBc private data. + @param[in] HostName Pointer to buffer containing hostname. + @param[out] IpAddress On output, pointer to buffer containing IPv6 address. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. + @retval EFI_DEVICE_ERROR An unexpected network error occurred. + @retval Others Other errors as indicated. **/ -VOID -PxeBcFreeBootFileOption ( - IN LIST_ENTRY *Head +EFI_STATUS +PxeBcDns6 ( + IN PXEBC_PRIVATE_DATA *Private, + IN CHAR16 *HostName, + OUT EFI_IPv6_ADDRESS *IpAddress ) { - LIST_ENTRY *Entry; - LIST_ENTRY *NextEntry; - PXEBC_DHCP6_OPTION_NODE *Node; + EFI_STATUS Status; + EFI_DNS6_PROTOCOL *Dns6; + EFI_DNS6_CONFIG_DATA Dns6ConfigData; + EFI_DNS6_COMPLETION_TOKEN Token; + EFI_HANDLE Dns6Handle; + EFI_IPv6_ADDRESS *DnsServerList; + BOOLEAN IsDone; + + Dns6 = NULL; + Dns6Handle = NULL; + DnsServerList = Private->DnsServer; + ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN)); + + // + // Create a DNSv6 child instance and get the protocol. + // + Status = NetLibCreateServiceChild ( + Private->Controller, + Private->Image, + &gEfiDns6ServiceBindingProtocolGuid, + &Dns6Handle + ); + if (EFI_ERROR (Status)) { + goto Exit; + } - NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, Head) { - Node = NET_LIST_USER_STRUCT (Entry, PXEBC_DHCP6_OPTION_NODE, Link); - RemoveEntryList (Entry); - FreePool (Node); + Status = gBS->OpenProtocol ( + Dns6Handle, + &gEfiDns6ProtocolGuid, + (VOID **)&Dns6, + Private->Image, + Private->Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto Exit; } -} + // + // Configure DNS6 instance for the DNS server address and protocol. + // + ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA)); + Dns6ConfigData.DnsServerCount = 1; + Dns6ConfigData.DnsServerList = DnsServerList; + Dns6ConfigData.EnableDnsCache = TRUE; + Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP; + IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp, &Private->TmpStationIp.v6); + Status = Dns6->Configure ( + Dns6, + &Dns6ConfigData + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + Token.Status = EFI_NOT_READY; + IsDone = FALSE; + // + // Create event to set the IsDone flag when name resolution is finished. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + PxeBcCommonNotify, + &IsDone, + &Token.Event + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + + // + // Start asynchronous name resolution. + // + Status = Dns6->HostNameToIp (Dns6, HostName, &Token); + if (EFI_ERROR (Status)) { + goto Exit; + } + + while (!IsDone) { + Dns6->Poll (Dns6); + } + + // + // Name resolution is done, check result. + // + Status = Token.Status; + if (!EFI_ERROR (Status)) { + if (Token.RspData.H2AData == NULL) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + + if ((Token.RspData.H2AData->IpCount == 0) || (Token.RspData.H2AData->IpList == NULL)) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + + // + // We just return the first IPv6 address from DNS protocol. + // + IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList); + Status = EFI_SUCCESS; + } + +Exit: + FreePool (HostName); + + if (Token.Event != NULL) { + gBS->CloseEvent (Token.Event); + } + + if (Token.RspData.H2AData != NULL) { + if (Token.RspData.H2AData->IpList != NULL) { + FreePool (Token.RspData.H2AData->IpList); + } + + FreePool (Token.RspData.H2AData); + } + + if (Dns6 != NULL) { + Dns6->Configure (Dns6, NULL); + + gBS->CloseProtocol ( + Dns6Handle, + &gEfiDns6ProtocolGuid, + Private->Image, + Private->Controller + ); + } + + if (Dns6Handle != NULL) { + NetLibDestroyServiceChild ( + Private->Controller, + Private->Image, + &gEfiDns6ServiceBindingProtocolGuid, + Dns6Handle + ); + } + + if (DnsServerList != NULL) { + FreePool (DnsServerList); + } + + return Status; +} /** Parse the Boot File URL option. + @param[in] Private Pointer to PxeBc private data. @param[out] FileName The pointer to the boot file name. @param[in, out] SrvAddr The pointer to the boot server address. @param[in] BootFile The pointer to the boot file URL option data. @@ -227,28 +372,33 @@ PxeBcFreeBootFileOption ( @retval EFI_ABORTED User cancel operation. @retval EFI_SUCCESS Selected the boot menu successfully. - @retval EFI_NOT_READY Read the input key from the keybroad has not finish. + @retval EFI_NOT_READY Read the input key from the keyboard has not finish. **/ EFI_STATUS PxeBcExtractBootFileUrl ( - OUT UINT8 **FileName, - IN OUT EFI_IPv6_ADDRESS *SrvAddr, - IN CHAR8 *BootFile, - IN UINT16 Length + IN PXEBC_PRIVATE_DATA *Private, + OUT UINT8 **FileName, + IN OUT EFI_IPv6_ADDRESS *SrvAddr, + IN CHAR8 *BootFile, + IN UINT16 Length ) { - UINT16 PrefixLen; - CHAR8 *BootFileNamePtr; - CHAR8 *BootFileName; - UINT16 BootFileNameLen; - CHAR8 *TmpStr; - CHAR8 TmpChar; - CHAR8 *ServerAddressOption; - CHAR8 *ServerAddress; - CHAR8 *ModeStr; - EFI_STATUS Status; - + UINT16 PrefixLen; + CHAR8 *BootFileNamePtr; + CHAR8 *BootFileName; + UINT16 BootFileNameLen; + CHAR8 *TmpStr; + CHAR8 TmpChar; + CHAR8 *ServerAddressOption; + CHAR8 *ServerAddress; + CHAR8 *ModeStr; + CHAR16 *HostName; + BOOLEAN IpExpressedUrl; + UINTN Len; + EFI_STATUS Status; + + IpExpressedUrl = TRUE; // // The format of the Boot File URL option is: // @@ -264,22 +414,23 @@ PxeBcExtractBootFileUrl ( // // - // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile-url format - // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME + // Based upon RFC 5970 and UEFI 2.6, bootfile-url format can be + // tftp://[SERVER_ADDRESS]/BOOTFILE_NAME or tftp://domain_name/BOOTFILE_NAME // As an example where the BOOTFILE_NAME is the EFI loader and // SERVER_ADDRESS is the ASCII encoding of an IPV6 address. // - PrefixLen = (UINT16) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX); + PrefixLen = (UINT16)AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX); - if (Length <= PrefixLen || - CompareMem (BootFile, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX, PrefixLen) != 0) { + if ((Length <= PrefixLen) || + (CompareMem (BootFile, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX, PrefixLen) != 0)) + { return EFI_NOT_FOUND; } BootFile = BootFile + PrefixLen; - Length = (UINT16) (Length - PrefixLen); + Length = (UINT16)(Length - PrefixLen); - TmpStr = (CHAR8 *) AllocateZeroPool (Length + 1); + TmpStr = (CHAR8 *)AllocateZeroPool (Length + 1); if (TmpStr == NULL) { return EFI_OUT_OF_RESOURCES; } @@ -291,83 +442,121 @@ PxeBcExtractBootFileUrl ( // Get the part of SERVER_ADDRESS string. // ServerAddressOption = TmpStr; - if (*ServerAddressOption != PXEBC_ADDR_START_DELIMITER) { - FreePool (TmpStr); - return EFI_INVALID_PARAMETER; - } + if (*ServerAddressOption == PXEBC_ADDR_START_DELIMITER) { + ServerAddressOption++; + ServerAddress = ServerAddressOption; + while (*ServerAddress != '\0' && *ServerAddress != PXEBC_ADDR_END_DELIMITER) { + ServerAddress++; + } - ServerAddressOption ++; - ServerAddress = ServerAddressOption; - while (*ServerAddress != '\0' && *ServerAddress != PXEBC_ADDR_END_DELIMITER) { - ServerAddress++; - } + if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) { + FreePool (TmpStr); + return EFI_INVALID_PARAMETER; + } - if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) { - FreePool (TmpStr); - return EFI_INVALID_PARAMETER; - } + *ServerAddress = '\0'; - *ServerAddress = '\0'; + // + // Convert the string of server address to Ipv6 address format and store it. + // + Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr); + if (EFI_ERROR (Status)) { + FreePool (TmpStr); + return Status; + } + } else { + IpExpressedUrl = FALSE; + ServerAddress = ServerAddressOption; + while (*ServerAddress != '\0' && *ServerAddress != PXEBC_TFTP_URL_SEPARATOR) { + ServerAddress++; + } - // - // Convert the string of server address to Ipv6 address format and store it. - // - Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr); - if (EFI_ERROR (Status)) { - FreePool (TmpStr); - return Status; + if (*ServerAddress != PXEBC_TFTP_URL_SEPARATOR) { + FreePool (TmpStr); + return EFI_INVALID_PARAMETER; + } + + *ServerAddress = '\0'; + + Len = AsciiStrSize (ServerAddressOption); + HostName = AllocateZeroPool (Len * sizeof (CHAR16)); + if (HostName == NULL) { + FreePool (TmpStr); + return EFI_OUT_OF_RESOURCES; + } + + AsciiStrToUnicodeStrS ( + ServerAddressOption, + HostName, + Len + ); + + // + // Perform DNS resolution. + // + Status = PxeBcDns6 (Private, HostName, SrvAddr); + if (EFI_ERROR (Status)) { + FreePool (TmpStr); + return Status; + } } // // Get the part of BOOTFILE_NAME string. // - BootFileNamePtr = (CHAR8*)((UINTN)ServerAddress + 1); - if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) { - FreePool (TmpStr); - return EFI_INVALID_PARAMETER; + BootFileNamePtr = (CHAR8 *)((UINTN)ServerAddress + 1); + if (IpExpressedUrl) { + if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) { + FreePool (TmpStr); + return EFI_INVALID_PARAMETER; + } + + ++BootFileNamePtr; } - ++BootFileNamePtr; - BootFileNameLen = (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1); - if (BootFileNameLen != 0 || FileName != NULL) { + BootFileNameLen = (UINT16)(Length - (UINT16)((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1); + if ((BootFileNameLen != 0) || (FileName != NULL)) { // // Remove trailing mode=octet if present and ignore. All other modes are // invalid for netboot6, so reject them. // ModeStr = AsciiStrStr (BootFileNamePtr, ";mode=octet"); - if (ModeStr != NULL && *(ModeStr + AsciiStrLen (";mode=octet")) == '\0') { + if ((ModeStr != NULL) && (*(ModeStr + AsciiStrLen (";mode=octet")) == '\0')) { *ModeStr = '\0'; } else if (AsciiStrStr (BootFileNamePtr, ";mode=") != NULL) { + FreePool (TmpStr); return EFI_INVALID_PARAMETER; } // // Extract boot file name from URL. // - BootFileName = (CHAR8 *) AllocateZeroPool (BootFileNameLen); + BootFileName = (CHAR8 *)AllocateZeroPool (BootFileNameLen); if (BootFileName == NULL) { FreePool (TmpStr); return EFI_OUT_OF_RESOURCES; } - *FileName = (UINT8*) BootFileName; + + *FileName = (UINT8 *)BootFileName; // // Decode percent-encoding in boot file name. // while (*BootFileNamePtr != '\0') { if (*BootFileNamePtr == '%') { - TmpChar = *(BootFileNamePtr+ 3); + TmpChar = *(BootFileNamePtr+ 3); *(BootFileNamePtr+ 3) = '\0'; - *BootFileName = (UINT8) AsciiStrHexToUintn ((CHAR8*)(BootFileNamePtr + 1)); + *BootFileName = (UINT8)AsciiStrHexToUintn ((CHAR8 *)(BootFileNamePtr + 1)); BootFileName++; *(BootFileNamePtr+ 3) = TmpChar; - BootFileNamePtr += 3; + BootFileNamePtr += 3; } else { *BootFileName = *BootFileNamePtr; BootFileName++; BootFileNamePtr++; } } + *BootFileName = '\0'; } @@ -376,7 +565,6 @@ PxeBcExtractBootFileUrl ( return EFI_SUCCESS; } - /** Parse the Boot File Parameter option. @@ -389,14 +577,14 @@ PxeBcExtractBootFileUrl ( **/ EFI_STATUS PxeBcExtractBootFileParam ( - IN CHAR8 *BootFilePara, - OUT UINT16 *BootFileSize + IN CHAR8 *BootFilePara, + OUT UINT16 *BootFileSize ) { - UINT16 Length; - UINT8 Index; - UINT8 Digit; - UINT32 Size; + UINT16 Length; + UINT8 Index; + UINT8 Digit; + UINT32 Size; CopyMem (&Length, BootFilePara, sizeof (UINT16)); Length = NTOHS (Length); @@ -404,7 +592,7 @@ PxeBcExtractBootFileParam ( // // The BootFile Size should be 1~5 byte ASCII strings // - if (Length < 1 || Length > 5) { + if ((Length < 1) || (Length > 5)) { return EFI_NOT_FOUND; } @@ -426,11 +614,10 @@ PxeBcExtractBootFileParam ( return EFI_NOT_FOUND; } - *BootFileSize = (UINT16) Size; + *BootFileSize = (UINT16)Size; return EFI_SUCCESS; } - /** Parse the cached DHCPv6 packet, including all the options. @@ -445,15 +632,15 @@ PxeBcParseDhcp6Packet ( IN PXEBC_DHCP6_PACKET_CACHE *Cache6 ) { - EFI_DHCP6_PACKET *Offer; - EFI_DHCP6_PACKET_OPTION **Options; - EFI_DHCP6_PACKET_OPTION *Option; - PXEBC_OFFER_TYPE OfferType; - BOOLEAN IsProxyOffer; - BOOLEAN IsPxeOffer; - UINT32 Offset; - UINT32 Length; - UINT32 EnterpriseNum; + EFI_DHCP6_PACKET *Offer; + EFI_DHCP6_PACKET_OPTION **Options; + EFI_DHCP6_PACKET_OPTION *Option; + PXEBC_OFFER_TYPE OfferType; + BOOLEAN IsProxyOffer; + BOOLEAN IsPxeOffer; + UINT32 Offset; + UINT32 Length; + UINT32 EnterpriseNum; IsProxyOffer = TRUE; IsPxeOffer = FALSE; @@ -462,44 +649,45 @@ PxeBcParseDhcp6Packet ( ZeroMem (Cache6->OptList, sizeof (Cache6->OptList)); - Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option); - Offset = 0; - Length = GET_DHCP6_OPTION_SIZE (Offer); + Option = (EFI_DHCP6_PACKET_OPTION *)(Offer->Dhcp6.Option); + Offset = 0; + Length = GET_DHCP6_OPTION_SIZE (Offer); // // OpLen and OpCode here are both stored in network order, since they are from original packet. // while (Offset < Length) { - - if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_IA_NA) { + if (NTOHS (Option->OpCode) == DHCP6_OPT_IA_NA) { Options[PXEBC_DHCP6_IDX_IA_NA] = Option; - } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_BOOT_FILE_URL) { + } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_URL) { // // The server sends this option to inform the client about an URL to a boot file. // Options[PXEBC_DHCP6_IDX_BOOT_FILE_URL] = Option; - } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_BOOT_FILE_PARAM) { + } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_PARAM) { Options[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] = Option; - } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_VENDOR_CLASS) { + } else if (NTOHS (Option->OpCode) == DHCP6_OPT_VENDOR_CLASS) { Options[PXEBC_DHCP6_IDX_VENDOR_CLASS] = Option; + } else if (NTOHS (Option->OpCode) == DHCP6_OPT_DNS_SERVERS) { + Options[PXEBC_DHCP6_IDX_DNS_SERVER] = Option; } Offset += (NTOHS (Option->OpLen) + 4); - Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option + Offset); + Option = (EFI_DHCP6_PACKET_OPTION *)(Offer->Dhcp6.Option + Offset); } // // The offer with assigned client address is NOT a proxy offer. - // An ia_na option, embeded with valid ia_addr option and a status_code of success. + // An ia_na option, embedded with valid ia_addr option and a status_code of success. // Option = Options[PXEBC_DHCP6_IDX_IA_NA]; if (Option != NULL) { Option = PxeBcParseDhcp6Options ( Option->Data + 12, NTOHS (Option->OpLen), - PXEBC_DHCP6_OPT_STATUS_CODE + DHCP6_OPT_STATUS_CODE ); - if ((Option != NULL && Option->Data[0] == 0) || (Option == NULL)) { + if (((Option != NULL) && (Option->Data[0] == 0)) || (Option == NULL)) { IsProxyOffer = FALSE; } } @@ -508,12 +696,13 @@ PxeBcParseDhcp6Packet ( // The offer with "PXEClient" is a pxe offer. // Option = Options[PXEBC_DHCP6_IDX_VENDOR_CLASS]; - EnterpriseNum = HTONL(PXEBC_DHCP6_ENTERPRISE_NUM); + EnterpriseNum = HTONL (PXEBC_DHCP6_ENTERPRISE_NUM); - if (Option != NULL && - NTOHS(Option->OpLen) >= 13 && - CompareMem (Option->Data, &EnterpriseNum, sizeof (UINT32)) == 0 && - CompareMem (&Option->Data[6], DEFAULT_CLASS_ID_DATA, 9) == 0) { + if ((Option != NULL) && + (NTOHS (Option->OpLen) >= 13) && + (CompareMem (Option->Data, &EnterpriseNum, sizeof (UINT32)) == 0) && + (CompareMem (&Option->Data[6], DEFAULT_CLASS_ID_DATA, 9) == 0)) + { IsPxeOffer = TRUE; } @@ -537,7 +726,6 @@ PxeBcParseDhcp6Packet ( return EFI_SUCCESS; } - /** Cache the DHCPv6 ack packet, and parse it on demand. @@ -545,19 +733,26 @@ PxeBcParseDhcp6Packet ( @param[in] Ack The pointer to the DHCPv6 ack packet. @param[in] Verified If TRUE, parse the ACK packet and store info into mode data. + @retval EFI_SUCCESS Cache and parse the packet successfully. + @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet. + **/ -VOID +EFI_STATUS PxeBcCopyDhcp6Ack ( - IN PXEBC_PRIVATE_DATA *Private, - IN EFI_DHCP6_PACKET *Ack, - IN BOOLEAN Verified + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_DHCP6_PACKET *Ack, + IN BOOLEAN Verified ) { EFI_PXE_BASE_CODE_MODE *Mode; + EFI_STATUS Status; Mode = Private->PxeBc.Mode; - PxeBcCacheDhcp6Packet (&Private->DhcpAck.Dhcp6.Packet.Ack, Ack); + Status = PxeBcCacheDhcp6Packet (&Private->DhcpAck.Dhcp6.Packet.Ack, Ack); + if (EFI_ERROR (Status)) { + return Status; + } if (Verified) { // @@ -567,8 +762,9 @@ PxeBcCopyDhcp6Ack ( CopyMem (&Mode->DhcpAck.Dhcpv6, &Ack->Dhcp6, Ack->Length); Mode->DhcpAckReceived = TRUE; } -} + return EFI_SUCCESS; +} /** Cache the DHCPv6 proxy offer packet according to the received order. @@ -576,15 +772,19 @@ PxeBcCopyDhcp6Ack ( @param[in] Private The pointer to PxeBc private data. @param[in] OfferIndex The received order of offer packets. + @retval EFI_SUCCESS Cache and parse the packet successfully. + @retval EFI_BUFFER_TOO_SMALL Cache buffer is not big enough to hold the packet. + **/ -VOID +EFI_STATUS PxeBcCopyDhcp6Proxy ( - IN PXEBC_PRIVATE_DATA *Private, - IN UINT32 OfferIndex + IN PXEBC_PRIVATE_DATA *Private, + IN UINT32 OfferIndex ) { - EFI_PXE_BASE_CODE_MODE *Mode; - EFI_DHCP6_PACKET *Offer; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_DHCP6_PACKET *Offer; + EFI_STATUS Status; ASSERT (OfferIndex < Private->OfferNum); ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM); @@ -595,7 +795,11 @@ PxeBcCopyDhcp6Proxy ( // // Cache the proxy offer packet and parse it. // - PxeBcCacheDhcp6Packet (&Private->ProxyOffer.Dhcp6.Packet.Offer, Offer); + Status = PxeBcCacheDhcp6Packet (&Private->ProxyOffer.Dhcp6.Packet.Offer, Offer); + if (EFI_ERROR (Status)) { + return Status; + } + PxeBcParseDhcp6Packet (&Private->ProxyOffer.Dhcp6); // @@ -603,6 +807,8 @@ PxeBcCopyDhcp6Proxy ( // CopyMem (&Mode->ProxyOffer.Dhcpv6, &Offer->Dhcp6, Offer->Length); Mode->ProxyOfferReceived = TRUE; + + return EFI_SUCCESS; } /** @@ -618,33 +824,33 @@ PxeBcCopyDhcp6Proxy ( **/ UINT8 * PxeBcDhcp6SeekOption ( - IN UINT8 *Buf, - IN UINT32 SeekLen, - IN UINT16 OptType + IN UINT8 *Buf, + IN UINT32 SeekLen, + IN UINT16 OptType ) { - UINT8 *Cursor; - UINT8 *Option; - UINT16 DataLen; - UINT16 OpCode; + UINT8 *Cursor; + UINT8 *Option; + UINT16 DataLen; + UINT16 OpCode; Option = NULL; Cursor = Buf; while (Cursor < Buf + SeekLen) { - OpCode = ReadUnaligned16 ((UINT16 *) Cursor); + OpCode = ReadUnaligned16 ((UINT16 *)Cursor); if (OpCode == HTONS (OptType)) { Option = Cursor; break; } - DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2))); + + DataLen = NTOHS (ReadUnaligned16 ((UINT16 *)(Cursor + 2))); Cursor += (DataLen + 4); } return Option; } - /** Build and send out the request packet for the bootfile, and parse the reply. @@ -659,34 +865,34 @@ PxeBcDhcp6SeekOption ( **/ EFI_STATUS PxeBcRequestBootService ( - IN PXEBC_PRIVATE_DATA *Private, - IN UINT32 Index + IN PXEBC_PRIVATE_DATA *Private, + IN UINT32 Index ) { - EFI_PXE_BASE_CODE_UDP_PORT SrcPort; - EFI_PXE_BASE_CODE_UDP_PORT DestPort; - EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; - EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover; - UINTN DiscoverLen; - EFI_DHCP6_PACKET *Request; - UINTN RequestLen; - EFI_DHCP6_PACKET *Reply; - UINT8 *RequestOpt; - UINT8 *DiscoverOpt; - UINTN ReadSize; - UINT16 OpFlags; - UINT16 OpCode; - UINT16 OpLen; - EFI_STATUS Status; - EFI_DHCP6_PACKET *ProxyOffer; - UINT8 *Option; - - PxeBc = &Private->PxeBc; - Request = Private->Dhcp6Request; - ProxyOffer = &Private->OfferBuffer[Index].Dhcp6.Packet.Offer; - SrcPort = PXEBC_BS_DISCOVER_PORT; - DestPort = PXEBC_BS_DISCOVER_PORT; - OpFlags = 0; + EFI_PXE_BASE_CODE_UDP_PORT SrcPort; + EFI_PXE_BASE_CODE_UDP_PORT DestPort; + EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; + EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover; + UINTN DiscoverLen; + EFI_DHCP6_PACKET *Request; + UINTN RequestLen; + EFI_DHCP6_PACKET *Reply; + UINT8 *RequestOpt; + UINT8 *DiscoverOpt; + UINTN ReadSize; + UINT16 OpFlags; + UINT16 OpCode; + UINT16 OpLen; + EFI_STATUS Status; + EFI_DHCP6_PACKET *IndexOffer; + UINT8 *Option; + + PxeBc = &Private->PxeBc; + Request = Private->Dhcp6Request; + IndexOffer = &Private->OfferBuffer[Index].Dhcp6.Packet.Offer; + SrcPort = PXEBC_BS_DISCOVER_PORT; + DestPort = PXEBC_BS_DISCOVER_PORT; + OpFlags = 0; if (Request == NULL) { return EFI_DEVICE_ERROR; @@ -700,7 +906,7 @@ PxeBcRequestBootService ( // // Build the request packet by the cached request packet before. // - Discover->TransactionId = ProxyOffer->Dhcp6.Header.TransactionId; + Discover->TransactionId = IndexOffer->Dhcp6.Header.TransactionId; Discover->MessageType = Request->Dhcp6.Header.MessageType; RequestOpt = Request->Dhcp6.Option; DiscoverOpt = Discover->DhcpOptions; @@ -710,30 +916,33 @@ PxeBcRequestBootService ( // // Find Server ID Option from ProxyOffer. // - Option = PxeBcDhcp6SeekOption ( - ProxyOffer->Dhcp6.Option, - ProxyOffer->Length - 4, - PXEBC_DHCP6_OPT_SERVER_ID - ); - if (Option == NULL) { - return EFI_NOT_FOUND; + if (Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeProxyBinl) { + Option = PxeBcDhcp6SeekOption ( + IndexOffer->Dhcp6.Option, + IndexOffer->Length - 4, + DHCP6_OPT_SERVER_ID + ); + if (Option == NULL) { + return EFI_NOT_FOUND; + } + + // + // Add Server ID Option. + // + OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)Option)->OpLen); + CopyMem (DiscoverOpt, Option, OpLen + 4); + DiscoverOpt += (OpLen + 4); + DiscoverLen += (OpLen + 4); } - - // - // Add Server ID Option. - // - OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) Option)->OpLen); - CopyMem (DiscoverOpt, Option, OpLen + 4); - DiscoverOpt += (OpLen + 4); - DiscoverLen += (OpLen + 4); while (RequestLen < Request->Length) { - OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode); - OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpLen); - if (OpCode != EFI_DHCP6_IA_TYPE_NA && - OpCode != EFI_DHCP6_IA_TYPE_TA && - OpCode != PXEBC_DHCP6_OPT_SERVER_ID - ) { + OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpCode); + OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpLen); + if ((OpCode != EFI_DHCP6_IA_TYPE_NA) && + (OpCode != EFI_DHCP6_IA_TYPE_TA) && + (OpCode != DHCP6_OPT_SERVER_ID) + ) + { // // Copy all the options except IA option and Server ID // @@ -741,22 +950,23 @@ PxeBcRequestBootService ( DiscoverOpt += (OpLen + 4); DiscoverLen += (OpLen + 4); } + RequestOpt += (OpLen + 4); RequestLen += (OpLen + 4); } // - // Update Elapsed option in the package + // Update Elapsed option in the package // Option = PxeBcDhcp6SeekOption ( Discover->DhcpOptions, (UINT32)(RequestLen - 4), - PXEBC_DHCP6_OPT_ELAPSED_TIME + DHCP6_OPT_ELAPSED_TIME ); if (Option != NULL) { CalcElapsedTime (Private); - WriteUnaligned16 ((UINT16*)(Option + 4), HTONS((UINT16) Private->ElapsedTime)); - } + WriteUnaligned16 ((UINT16 *)(Option + 4), HTONS ((UINT16)Private->ElapsedTime)); + } Status = PxeBc->UdpWrite ( PxeBc, @@ -769,39 +979,39 @@ PxeBcRequestBootService ( NULL, NULL, &DiscoverLen, - (VOID *) Discover + (VOID *)Discover ); if (EFI_ERROR (Status)) { - return Status; + goto ON_ERROR; } // // Cache the right PXE reply packet here, set valid flag later. // Especially for PXE discover packet, store it into mode data here. // - Reply = &Private->ProxyOffer.Dhcp6.Packet.Offer; - ReadSize = (UINTN) Reply->Size; + Reply = &Private->ProxyOffer.Dhcp6.Packet.Offer; + ReadSize = (UINTN)Reply->Size; // // Start Udp6Read instance // Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData); if (EFI_ERROR (Status)) { - return Status; + goto ON_ERROR; } - + Status = PxeBc->UdpRead ( PxeBc, - EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP, - &Private->StationIp, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP, + NULL, &SrcPort, &Private->ServerIp, &DestPort, NULL, NULL, &ReadSize, - (VOID *) &Reply->Dhcp6 + (VOID *)&Reply->Dhcp6 ); // // Stop Udp6Read instance @@ -809,17 +1019,23 @@ PxeBcRequestBootService ( Private->Udp6Read->Configure (Private->Udp6Read, NULL); if (EFI_ERROR (Status)) { - return Status; + goto ON_ERROR; } // // Update length // - Reply->Length = (UINT32) ReadSize; + Reply->Length = (UINT32)ReadSize; return EFI_SUCCESS; -} +ON_ERROR: + if (Discover != NULL) { + FreePool (Discover); + } + + return Status; +} /** Retry to request bootfile name by the BINL offer. @@ -843,13 +1059,15 @@ PxeBcRetryDhcp6Binl ( EFI_STATUS Status; ASSERT (Index < PXEBC_OFFER_MAX_NUM); - ASSERT (Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeDhcpBinl || - Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeProxyBinl); + ASSERT ( + Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeDhcpBinl || + Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeProxyBinl + ); Mode = Private->PxeBc.Mode; Private->IsDoDiscover = FALSE; Offer = &Private->OfferBuffer[Index].Dhcp6; - if (Offer->OfferType == PxeOfferTypeDhcpBinl) { + if (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) { // // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead. // @@ -864,9 +1082,10 @@ PxeBcRetryDhcp6Binl ( // Parse out the next server address from the last offer, and store it // Status = PxeBcExtractBootFileUrl ( + Private, &Private->BootFileName, &Private->ServerIp.v6, - (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data), + (CHAR8 *)(Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data), NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen) ); if (EFI_ERROR (Status)) { @@ -889,9 +1108,10 @@ PxeBcRetryDhcp6Binl ( return Status; } - if (Cache6->OfferType != PxeOfferTypeProxyPxe10 && - Cache6->OfferType != PxeOfferTypeProxyWfm11a && - Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) { + if ((Cache6->OfferType != PxeOfferTypeProxyPxe10) && + (Cache6->OfferType != PxeOfferTypeProxyWfm11a) && + (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL)) + { // // This BINL ack doesn't have discovery option set or multicast option set // or bootfile name specified. @@ -909,23 +1129,25 @@ PxeBcRetryDhcp6Binl ( return EFI_SUCCESS; } - /** Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount. @param[in] Private The pointer to PXEBC_PRIVATE_DATA. @param[in] RcvdOffer The pointer to the received offer packet. + @retval EFI_SUCCESS Cache and parse the packet successfully. + @retval Others Operation failed. **/ -VOID +EFI_STATUS PxeBcCacheDhcp6Offer ( - IN PXEBC_PRIVATE_DATA *Private, - IN EFI_DHCP6_PACKET *RcvdOffer + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_DHCP6_PACKET *RcvdOffer ) { PXEBC_DHCP6_PACKET_CACHE *Cache6; EFI_DHCP6_PACKET *Offer; PXEBC_OFFER_TYPE OfferType; + EFI_STATUS Status; Cache6 = &Private->OfferBuffer[Private->OfferNum].Dhcp6; Offer = &Cache6->Packet.Offer; @@ -933,13 +1155,16 @@ PxeBcCacheDhcp6Offer ( // // Cache the content of DHCPv6 packet firstly. // - PxeBcCacheDhcp6Packet (Offer, RcvdOffer); + Status = PxeBcCacheDhcp6Packet (Offer, RcvdOffer); + if (EFI_ERROR (Status)) { + return Status; + } // // Validate the DHCPv6 packet, and parse the options and offer type. // if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6))) { - return ; + return EFI_ABORTED; } // @@ -961,14 +1186,16 @@ PxeBcCacheDhcp6Offer ( // Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum; Private->OfferCount[OfferType]++; - } else if (Private->OfferCount[OfferType] > 0) { + } else if (((OfferType == PxeOfferTypeProxyPxe10) || (OfferType == PxeOfferTypeProxyWfm11a)) && + (Private->OfferCount[OfferType] < 1)) + { // // Only cache the first PXE10/WFM11a offer, and discard the others. // Private->OfferIndex[OfferType][0] = Private->OfferNum; Private->OfferCount[OfferType] = 1; } else { - return; + return EFI_ABORTED; } } else { // @@ -979,8 +1206,9 @@ PxeBcCacheDhcp6Offer ( } Private->OfferNum++; -} + return EFI_SUCCESS; +} /** Select an DHCPv6 offer, and record SelectIndex and SelectProxyType. @@ -990,12 +1218,12 @@ PxeBcCacheDhcp6Offer ( **/ VOID PxeBcSelectDhcp6Offer ( - IN PXEBC_PRIVATE_DATA *Private + IN PXEBC_PRIVATE_DATA *Private ) { - UINT32 Index; - UINT32 OfferIndex; - PXEBC_OFFER_TYPE OfferType; + UINT32 Index; + UINT32 OfferIndex; + PXEBC_OFFER_TYPE OfferType; Private->SelectIndex = 0; @@ -1008,43 +1236,40 @@ PxeBcSelectDhcp6Offer ( // 1. DhcpPxe10 offer // Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1; - } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) { // // 2. DhcpWfm11a offer // Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1; - - } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && - Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) { + } else if ((Private->OfferCount[PxeOfferTypeDhcpOnly] > 0) && + (Private->OfferCount[PxeOfferTypeProxyPxe10] > 0)) + { // // 3. DhcpOnly offer and ProxyPxe10 offer. // Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1; Private->SelectProxyType = PxeOfferTypeProxyPxe10; - - } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && - Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) { + } else if ((Private->OfferCount[PxeOfferTypeDhcpOnly] > 0) && + (Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0)) + { // // 4. DhcpOnly offer and ProxyWfm11a offer. // Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1; Private->SelectProxyType = PxeOfferTypeProxyWfm11a; - } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) { // // 5. DhcpBinl offer. // Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1; - - } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && - Private->OfferCount[PxeOfferTypeProxyBinl] > 0) { + } else if ((Private->OfferCount[PxeOfferTypeDhcpOnly] > 0) && + (Private->OfferCount[PxeOfferTypeProxyBinl] > 0)) + { // // 6. DhcpOnly offer and ProxyBinl offer. // Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1; Private->SelectProxyType = PxeOfferTypeProxyBinl; - } else { // // 7. DhcpOnly offer with bootfilename. @@ -1062,7 +1287,6 @@ PxeBcSelectDhcp6Offer ( // Select offer by received order. // for (Index = 0; Index < Private->OfferNum; Index++) { - OfferType = Private->OfferBuffer[Index].Dhcp6.OfferType; if (IS_PROXY_OFFER (OfferType)) { @@ -1073,8 +1297,9 @@ PxeBcSelectDhcp6Offer ( } if (!Private->IsProxyRecved && - OfferType == PxeOfferTypeDhcpOnly && - Private->OfferBuffer[Index].Dhcp6.OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) { + (OfferType == PxeOfferTypeDhcpOnly) && + (Private->OfferBuffer[Index].Dhcp6.OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL)) + { // // Skip if DhcpOnly offer without any other proxy offers or bootfilename. // @@ -1087,33 +1312,46 @@ PxeBcSelectDhcp6Offer ( } } - /** Handle the DHCPv6 offer packet. @param[in] Private The pointer to PXEBC_PRIVATE_DATA. - @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully. - @retval EFI_NO_RESPONSE No response to the following request packet. + @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully. + @retval EFI_NO_RESPONSE No response to the following request packet. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_BUFFER_TOO_SMALL Can't cache the offer pacet. **/ EFI_STATUS PxeBcHandleDhcp6Offer ( - IN PXEBC_PRIVATE_DATA *Private + IN PXEBC_PRIVATE_DATA *Private ) { - PXEBC_DHCP6_PACKET_CACHE *Cache6; - EFI_STATUS Status; - PXEBC_OFFER_TYPE OfferType; - UINT32 ProxyIndex; - UINT32 SelectIndex; - UINT32 Index; + PXEBC_DHCP6_PACKET_CACHE *Cache6; + EFI_STATUS Status; + PXEBC_OFFER_TYPE OfferType; + UINT32 ProxyIndex; + UINT32 SelectIndex; + UINT32 Index; ASSERT (Private->SelectIndex > 0); - SelectIndex = (UINT32) (Private->SelectIndex - 1); + SelectIndex = (UINT32)(Private->SelectIndex - 1); ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM); - Cache6 = &Private->OfferBuffer[SelectIndex].Dhcp6; - Status = EFI_SUCCESS; + Cache6 = &Private->OfferBuffer[SelectIndex].Dhcp6; + Status = EFI_SUCCESS; + + // + // First try to cache DNS server address if DHCP6 offer provides. + // + if (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] != NULL) { + Private->DnsServer = AllocateZeroPool (NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen)); + if (Private->DnsServer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (Private->DnsServer, Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, sizeof (EFI_IPv6_ADDRESS)); + } if (Cache6->OfferType == PxeOfferTypeDhcpBinl) { // @@ -1123,7 +1361,6 @@ PxeBcHandleDhcp6Offer ( Status = EFI_NO_RESPONSE; } } else if (Cache6->OfferType == PxeOfferTypeDhcpOnly) { - if (Private->IsProxyRecved) { // // DhcpOnly offer is selected, so need try to request bootfilename. @@ -1141,12 +1378,12 @@ PxeBcHandleDhcp6Offer ( // Try all the cached ProxyBinl offer one by one to request bootfilename. // for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) { - ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index]; if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private, ProxyIndex))) { break; } } + if (Index == Private->OfferCount[Private->SelectProxyType]) { Status = EFI_NO_RESPONSE; } @@ -1163,7 +1400,6 @@ PxeBcHandleDhcp6Offer ( Status = EFI_NO_RESPONSE; for (Index = 0; Index < Private->OfferNum; Index++) { - OfferType = Private->OfferBuffer[Index].Dhcp6.OfferType; if (!IS_PROXY_OFFER (OfferType)) { @@ -1189,15 +1425,15 @@ PxeBcHandleDhcp6Offer ( } } - if (!EFI_ERROR (Status) && Private->SelectProxyType != PxeOfferTypeProxyBinl) { + if (!EFI_ERROR (Status) && (Private->SelectProxyType != PxeOfferTypeProxyBinl)) { // // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it. // - PxeBcCopyDhcp6Proxy (Private, ProxyIndex); + Status = PxeBcCopyDhcp6Proxy (Private, ProxyIndex); } } else { // - // Othewise, the bootfilename must be included in DhcpOnly offer. + // Otherwise, the bootfilename must be included in DhcpOnly offer. // ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL); } @@ -1207,14 +1443,13 @@ PxeBcHandleDhcp6Offer ( // // All PXE boot information is ready by now. // - PxeBcCopyDhcp6Ack (Private, &Private->DhcpAck.Dhcp6.Packet.Ack, TRUE); + Status = PxeBcCopyDhcp6Ack (Private, &Private->DhcpAck.Dhcp6.Packet.Ack, TRUE); Private->PxeBc.Mode->DhcpDiscoverValid = TRUE; } return Status; } - /** Unregister the address by Ip6Config protocol. @@ -1223,7 +1458,7 @@ PxeBcHandleDhcp6Offer ( **/ VOID PxeBcUnregisterIp6Address ( - IN PXEBC_PRIVATE_DATA *Private + IN PXEBC_PRIVATE_DATA *Private ) { if (Private->Ip6Policy != PXEBC_IP6_POLICY_MAX) { @@ -1236,7 +1471,7 @@ PxeBcUnregisterIp6Address ( /** Check whether IP driver could route the message which will be sent to ServerIp address. - + This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid route is found in IP6 route table, the address will be filed in GatewayAddr and return. @@ -1246,23 +1481,23 @@ PxeBcUnregisterIp6Address ( @retval EFI_SUCCESS Found a valid gateway address successfully. @retval EFI_TIMEOUT The operation is time out. - @retval Other Unexpect error happened. - + @retval Other Unexpected error happened. + **/ EFI_STATUS PxeBcCheckRouteTable ( - IN PXEBC_PRIVATE_DATA *Private, - IN UINTN TimeOutInSecond, - OUT EFI_IPv6_ADDRESS *GatewayAddr + IN PXEBC_PRIVATE_DATA *Private, + IN UINTN TimeOutInSecond, + OUT EFI_IPv6_ADDRESS *GatewayAddr ) { - EFI_STATUS Status; - EFI_IP6_PROTOCOL *Ip6; - EFI_IP6_MODE_DATA Ip6ModeData; - UINTN Index; - EFI_EVENT TimeOutEvt; - UINTN RetryCount; - BOOLEAN GatewayIsFound; + EFI_STATUS Status; + EFI_IP6_PROTOCOL *Ip6; + EFI_IP6_MODE_DATA Ip6ModeData; + UINTN Index; + EFI_EVENT TimeOutEvt; + UINTN RetryCount; + BOOLEAN GatewayIsFound; ASSERT (GatewayAddr != NULL); ASSERT (Private != NULL); @@ -1293,28 +1528,33 @@ PxeBcCheckRouteTable ( if (Ip6ModeData.AddressList != NULL) { FreePool (Ip6ModeData.AddressList); } + if (Ip6ModeData.GroupTable != NULL) { FreePool (Ip6ModeData.GroupTable); } + if (Ip6ModeData.RouteTable != NULL) { FreePool (Ip6ModeData.RouteTable); } + if (Ip6ModeData.NeighborCache != NULL) { FreePool (Ip6ModeData.NeighborCache); } + if (Ip6ModeData.PrefixTable != NULL) { FreePool (Ip6ModeData.PrefixTable); } + if (Ip6ModeData.IcmpTypeList != NULL) { FreePool (Ip6ModeData.IcmpTypeList); } - - if (GatewayIsFound || RetryCount == TimeOutInSecond) { + + if (GatewayIsFound || (RetryCount == TimeOutInSecond)) { break; } - + RetryCount++; - + // // Delay 1 second then recheck it again. // @@ -1335,23 +1575,24 @@ PxeBcCheckRouteTable ( if (EFI_ERROR (Status)) { goto ON_EXIT; } + while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) { Ip6->Poll (Ip6); } } - + ON_EXIT: if (TimeOutEvt != NULL) { gBS->CloseEvent (TimeOutEvt); } - + if (GatewayIsFound) { Status = EFI_SUCCESS; } else if (RetryCount == TimeOutInSecond) { Status = EFI_TIMEOUT; } - return Status; + return Status; } /** @@ -1360,36 +1601,35 @@ ON_EXIT: @param[in] Private The pointer to PXEBC_PRIVATE_DATA. @param[in] Address The pointer to the ready address. - @retval EFI_SUCCESS Registered the address succesfully. + @retval EFI_SUCCESS Registered the address successfully. @retval Others Failed to register the address. **/ EFI_STATUS PxeBcRegisterIp6Address ( - IN PXEBC_PRIVATE_DATA *Private, - IN EFI_IPv6_ADDRESS *Address + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_IPv6_ADDRESS *Address ) { - EFI_IP6_PROTOCOL *Ip6; - EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; - EFI_IP6_CONFIG_POLICY Policy; - EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr; - EFI_IPv6_ADDRESS GatewayAddr; - UINTN DataSize; - EFI_EVENT TimeOutEvt; - EFI_EVENT MappedEvt; - EFI_STATUS Status; - UINT64 DadTriggerTime; - EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits; - BOOLEAN NoGateway; - - Status = EFI_SUCCESS; - TimeOutEvt = NULL; - MappedEvt = NULL; - DataSize = sizeof (EFI_IP6_CONFIG_POLICY); - Ip6Cfg = Private->Ip6Cfg; - Ip6 = Private->Ip6; - NoGateway = FALSE; + EFI_IP6_PROTOCOL *Ip6; + EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; + EFI_IP6_CONFIG_POLICY Policy; + EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr; + EFI_IPv6_ADDRESS GatewayAddr; + UINTN DataSize; + EFI_EVENT MappedEvt; + EFI_STATUS Status; + BOOLEAN NoGateway; + EFI_IPv6_ADDRESS *Ip6Addr; + UINTN Index; + + Status = EFI_SUCCESS; + MappedEvt = NULL; + Ip6Addr = NULL; + DataSize = sizeof (EFI_IP6_CONFIG_POLICY); + Ip6Cfg = Private->Ip6Cfg; + Ip6 = Private->Ip6; + NoGateway = FALSE; ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)); CopyMem (&CfgAddr.Address, Address, sizeof (EFI_IPv6_ADDRESS)); @@ -1406,7 +1646,7 @@ PxeBcRegisterIp6Address ( if (EFI_ERROR (Status)) { NoGateway = TRUE; } - + // // There is no channel between IP6 and PXE driver about address setting, // so it has to set the new address by Ip6ConfigProtocol manually. @@ -1415,7 +1655,7 @@ PxeBcRegisterIp6Address ( Status = Ip6Cfg->SetData ( Ip6Cfg, Ip6ConfigDataTypePolicy, - sizeof(EFI_IP6_CONFIG_POLICY), + sizeof (EFI_IP6_CONFIG_POLICY), &Policy ); if (EFI_ERROR (Status)) { @@ -1426,34 +1666,6 @@ PxeBcRegisterIp6Address ( goto ON_EXIT; } - // - // Get Duplicate Address Detection Transmits count. - // - DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS); - Status = Ip6Cfg->GetData ( - Ip6Cfg, - Ip6ConfigDataTypeDupAddrDetectTransmits, - &DataSize, - &DadXmits - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - - // - // Create a timer as setting address timeout event since DAD in IP6 driver. - // - Status = gBS->CreateEvent ( - EVT_TIMER, - TPL_CALLBACK, - NULL, - NULL, - &TimeOutEvt - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - // // Create a notify event to set address flag when DAD if IP6 driver succeeded. // @@ -1468,37 +1680,72 @@ PxeBcRegisterIp6Address ( goto ON_EXIT; } - Status = Ip6Cfg->RegisterDataNotify ( - Ip6Cfg, - Ip6ConfigDataTypeManualAddress, - MappedEvt - ); - if (EFI_ERROR(Status)) { + Private->IsAddressOk = FALSE; + Status = Ip6Cfg->RegisterDataNotify ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + MappedEvt + ); + if (EFI_ERROR (Status)) { goto ON_EXIT; } Status = Ip6Cfg->SetData ( Ip6Cfg, Ip6ConfigDataTypeManualAddress, - sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS), + sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS), &CfgAddr ); - if (EFI_ERROR(Status) && Status != EFI_NOT_READY) { + if (EFI_ERROR (Status) && (Status != EFI_NOT_READY)) { goto ON_EXIT; - } + } else if (Status == EFI_NOT_READY) { + // + // Poll the network until the asynchronous process is finished. + // + while (!Private->IsAddressOk) { + Ip6->Poll (Ip6); + } - // - // Start the 5 secondes timer to wait for setting address. - // - Status = EFI_NO_MAPPING; - DadTriggerTime = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + PXEBC_DAD_ADDITIONAL_DELAY; - gBS->SetTimer (TimeOutEvt, TimerRelative, DadTriggerTime); + // + // Check whether the IP6 address setting is successed. + // + DataSize = 0; + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + &DataSize, + NULL + ); + if ((Status != EFI_BUFFER_TOO_SMALL) || (DataSize == 0)) { + Status = EFI_DEVICE_ERROR; + goto ON_EXIT; + } - while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) { - Ip6->Poll (Ip6); - if (Private->IsAddressOk) { - Status = EFI_SUCCESS; - break; + Ip6Addr = AllocatePool (DataSize); + if (Ip6Addr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + &DataSize, + (VOID *)Ip6Addr + ); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto ON_EXIT; + } + + for (Index = 0; Index < DataSize / sizeof (EFI_IPv6_ADDRESS); Index++) { + if (CompareMem (Ip6Addr + Index, Address, sizeof (EFI_IPv6_ADDRESS)) == 0) { + break; + } + } + + if (Index == DataSize / sizeof (EFI_IPv6_ADDRESS)) { + Status = EFI_ABORTED; + goto ON_EXIT; } } @@ -1526,9 +1773,11 @@ ON_EXIT: ); gBS->CloseEvent (MappedEvt); } - if (TimeOutEvt != NULL) { - gBS->CloseEvent (TimeOutEvt); + + if (Ip6Addr != NULL) { + FreePool (Ip6Addr); } + return Status; } @@ -1537,22 +1786,22 @@ ON_EXIT: @param[in] Private The pointer to PXEBC_PRIVATE_DATA. - @retval EFI_SUCCESS Switch the IP policy succesfully. - @retval Others Unexpect error happened. + @retval EFI_SUCCESS Switch the IP policy successfully. + @retval Others Unexpected error happened. **/ EFI_STATUS PxeBcSetIp6Policy ( - IN PXEBC_PRIVATE_DATA *Private + IN PXEBC_PRIVATE_DATA *Private ) { - EFI_IP6_CONFIG_POLICY Policy; - EFI_STATUS Status; - EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; - UINTN DataSize; + EFI_IP6_CONFIG_POLICY Policy; + EFI_STATUS Status; + EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; + UINTN DataSize; - Ip6Cfg = Private->Ip6Cfg; - DataSize = sizeof (EFI_IP6_CONFIG_POLICY); + Ip6Cfg = Private->Ip6Cfg; + DataSize = sizeof (EFI_IP6_CONFIG_POLICY); // // Get and store the current policy of IP6 driver. @@ -1572,7 +1821,7 @@ PxeBcSetIp6Policy ( Status = Ip6Cfg->SetData ( Ip6Cfg, Ip6ConfigDataTypePolicy, - sizeof(EFI_IP6_CONFIG_POLICY), + sizeof (EFI_IP6_CONFIG_POLICY), &Policy ); if (EFI_ERROR (Status)) { @@ -1588,7 +1837,7 @@ PxeBcSetIp6Policy ( /** This function will register the station IP address and flush IP instance to start using the new IP address. - + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. @retval EFI_SUCCESS The new IP address has been configured successfully. @@ -1597,12 +1846,12 @@ PxeBcSetIp6Policy ( **/ EFI_STATUS PxeBcSetIp6Address ( - IN PXEBC_PRIVATE_DATA *Private + IN PXEBC_PRIVATE_DATA *Private ) { - EFI_STATUS Status; - EFI_DHCP6_PROTOCOL *Dhcp6; - + EFI_STATUS Status; + EFI_DHCP6_PROTOCOL *Dhcp6; + Dhcp6 = Private->Dhcp6; CopyMem (&Private->StationIp.v6, &Private->TmpStationIp.v6, sizeof (EFI_IPv6_ADDRESS)); @@ -1648,47 +1897,48 @@ PxeBcSetIp6Address ( EFI_STATUS EFIAPI PxeBcDhcp6CallBack ( - IN EFI_DHCP6_PROTOCOL *This, - IN VOID *Context, - IN EFI_DHCP6_STATE CurrentState, - IN EFI_DHCP6_EVENT Dhcp6Event, - IN EFI_DHCP6_PACKET *Packet, - OUT EFI_DHCP6_PACKET **NewPacket OPTIONAL + IN EFI_DHCP6_PROTOCOL *This, + IN VOID *Context, + IN EFI_DHCP6_STATE CurrentState, + IN EFI_DHCP6_EVENT Dhcp6Event, + IN EFI_DHCP6_PACKET *Packet, + OUT EFI_DHCP6_PACKET **NewPacket OPTIONAL ) { - PXEBC_PRIVATE_DATA *Private; - EFI_PXE_BASE_CODE_MODE *Mode; - EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback; - EFI_DHCP6_PACKET *SelectAd; - EFI_STATUS Status; - BOOLEAN Received; + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback; + EFI_DHCP6_PACKET *SelectAd; + EFI_STATUS Status; + BOOLEAN Received; if ((Dhcp6Event != Dhcp6RcvdAdvertise) && (Dhcp6Event != Dhcp6SelectAdvertise) && (Dhcp6Event != Dhcp6SendSolicit) && (Dhcp6Event != Dhcp6SendRequest) && - (Dhcp6Event != Dhcp6RcvdReply)) { + (Dhcp6Event != Dhcp6RcvdReply)) + { return EFI_SUCCESS; } ASSERT (Packet != NULL); - Private = (PXEBC_PRIVATE_DATA *) Context; - Mode = Private->PxeBc.Mode; - Callback = Private->PxeBcCallback; + Private = (PXEBC_PRIVATE_DATA *)Context; + Mode = Private->PxeBc.Mode; + Callback = Private->PxeBcCallback; // - // Callback to user when any traffic ocurred if has. + // Callback to user when any traffic occurred if has. // - if (Dhcp6Event != Dhcp6SelectAdvertise && Callback != NULL) { - Received = (BOOLEAN) (Dhcp6Event == Dhcp6RcvdAdvertise || Dhcp6Event == Dhcp6RcvdReply); - Status = Callback->Callback ( - Callback, - Private->Function, - Received, - Packet->Length, - (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp6 - ); + if ((Dhcp6Event != Dhcp6SelectAdvertise) && (Callback != NULL)) { + Received = (BOOLEAN)(Dhcp6Event == Dhcp6RcvdAdvertise || Dhcp6Event == Dhcp6RcvdReply); + Status = Callback->Callback ( + Callback, + Private->Function, + Received, + Packet->Length, + (EFI_PXE_BASE_CODE_PACKET *)&Packet->Dhcp6 + ); if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) { return EFI_ABORTED; } @@ -1697,80 +1947,114 @@ PxeBcDhcp6CallBack ( Status = EFI_SUCCESS; switch (Dhcp6Event) { + case Dhcp6SendSolicit: + if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) { + // + // If the to be sent packet exceeds the maximum length, abort the DHCP process. + // + Status = EFI_ABORTED; + break; + } - case Dhcp6SendSolicit: - // - // Record the first Solicate msg time - // - if (Private->SolicitTimes == 0) { - CalcElapsedTime (Private); - Private->SolicitTimes++; - } - // - // Cache the dhcp discover packet to mode data directly. - // - CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp6, Packet->Length); - break; + // + // Record the first Solicate msg time + // + if (Private->SolicitTimes == 0) { + CalcElapsedTime (Private); + Private->SolicitTimes++; + } - case Dhcp6RcvdAdvertise: - Status = EFI_NOT_READY; - if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) { // - // Cache the dhcp offers to OfferBuffer[] for select later, and record - // the OfferIndex and OfferCount. + // Cache the dhcp discover packet to mode data directly. // - PxeBcCacheDhcp6Offer (Private, Packet); - } - break; + CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp6, Packet->Length); + break; - case Dhcp6SendRequest: - // - // Store the request packet as seed packet for discover. - // - if (Private->Dhcp6Request != NULL) { - FreePool (Private->Dhcp6Request); - } - Private->Dhcp6Request = AllocateZeroPool (Packet->Size); - if (Private->Dhcp6Request != NULL) { - CopyMem (Private->Dhcp6Request, Packet, Packet->Size); - } - break; + case Dhcp6RcvdAdvertise: + Status = EFI_NOT_READY; + if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) { + // + // Ignore the incoming packets which exceed the maximum length. + // + break; + } - case Dhcp6SelectAdvertise: - // - // Select offer by the default policy or by order, and record the SelectIndex - // and SelectProxyType. - // - PxeBcSelectDhcp6Offer (Private); + if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) { + // + // Cache the dhcp offers to OfferBuffer[] for select later, and record + // the OfferIndex and OfferCount. + // + PxeBcCacheDhcp6Offer (Private, Packet); + } - if (Private->SelectIndex == 0) { - Status = EFI_ABORTED; - } else { - ASSERT (NewPacket != NULL); - SelectAd = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer; - *NewPacket = AllocateZeroPool (SelectAd->Size); - ASSERT (*NewPacket != NULL); - CopyMem (*NewPacket, SelectAd, SelectAd->Size); - } - break; + break; - case Dhcp6RcvdReply: - // - // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data - // without verification. - // - ASSERT (Private->SelectIndex != 0); - PxeBcCopyDhcp6Ack (Private, Packet, FALSE); - break; + case Dhcp6SendRequest: + if (Packet->Length > PXEBC_DHCP6_PACKET_MAX_SIZE) { + // + // If the to be sent packet exceeds the maximum length, abort the DHCP process. + // + Status = EFI_ABORTED; + break; + } - default: - ASSERT (0); + // + // Store the request packet as seed packet for discover. + // + if (Private->Dhcp6Request != NULL) { + FreePool (Private->Dhcp6Request); + } + + Private->Dhcp6Request = AllocateZeroPool (Packet->Size); + if (Private->Dhcp6Request != NULL) { + CopyMem (Private->Dhcp6Request, Packet, Packet->Size); + } + + break; + + case Dhcp6SelectAdvertise: + // + // Select offer by the default policy or by order, and record the SelectIndex + // and SelectProxyType. + // + PxeBcSelectDhcp6Offer (Private); + + if (Private->SelectIndex == 0) { + Status = EFI_ABORTED; + } else { + ASSERT (NewPacket != NULL); + SelectAd = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer; + *NewPacket = AllocateZeroPool (SelectAd->Size); + ASSERT (*NewPacket != NULL); + if (*NewPacket == NULL) { + return EFI_ABORTED; + } + + CopyMem (*NewPacket, SelectAd, SelectAd->Size); + } + + break; + + case Dhcp6RcvdReply: + // + // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data + // without verification. + // + ASSERT (Private->SelectIndex != 0); + Status = PxeBcCopyDhcp6Ack (Private, Packet, FALSE); + if (EFI_ERROR (Status)) { + Status = EFI_ABORTED; + } + + break; + + default: + ASSERT (0); } return Status; } - /** Build and send out the request packet for the bootfile, and parse the reply. @@ -1788,39 +2072,37 @@ PxeBcDhcp6CallBack ( **/ EFI_STATUS PxeBcDhcp6Discover ( - IN PXEBC_PRIVATE_DATA *Private, - IN UINT16 Type, - IN UINT16 *Layer, - IN BOOLEAN UseBis, - IN EFI_IP_ADDRESS *DestIp + IN PXEBC_PRIVATE_DATA *Private, + IN UINT16 Type, + IN UINT16 *Layer, + IN BOOLEAN UseBis, + IN EFI_IP_ADDRESS *DestIp ) { - EFI_PXE_BASE_CODE_UDP_PORT SrcPort; - EFI_PXE_BASE_CODE_UDP_PORT DestPort; - EFI_PXE_BASE_CODE_MODE *Mode; - EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; - EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover; - UINTN DiscoverLen; - EFI_DHCP6_PACKET *Request; - UINTN RequestLen; - EFI_DHCP6_PACKET *Reply; - UINT8 *RequestOpt; - UINT8 *DiscoverOpt; - UINTN ReadSize; - UINT16 OpFlags; - UINT16 OpCode; - UINT16 OpLen; - UINT32 Xid; - EFI_STATUS Status; - - PxeBc = &Private->PxeBc; - Mode = PxeBc->Mode; - Request = Private->Dhcp6Request; - SrcPort = PXEBC_BS_DISCOVER_PORT; - DestPort = PXEBC_BS_DISCOVER_PORT; - OpFlags = 0; - - if (!UseBis && Layer != NULL) { + EFI_PXE_BASE_CODE_UDP_PORT SrcPort; + EFI_PXE_BASE_CODE_UDP_PORT DestPort; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; + EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover; + UINTN DiscoverLen; + EFI_DHCP6_PACKET *Request; + UINTN RequestLen; + EFI_DHCP6_PACKET *Reply; + UINT8 *RequestOpt; + UINT8 *DiscoverOpt; + UINTN ReadSize; + UINT16 OpCode; + UINT16 OpLen; + UINT32 Xid; + EFI_STATUS Status; + + PxeBc = &Private->PxeBc; + Mode = PxeBc->Mode; + Request = Private->Dhcp6Request; + SrcPort = PXEBC_BS_DISCOVER_PORT; + DestPort = PXEBC_BS_DISCOVER_PORT; + + if (!UseBis && (Layer != NULL)) { *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK; } @@ -1845,10 +2127,11 @@ PxeBcDhcp6Discover ( RequestLen = DiscoverLen; while (RequestLen < Request->Length) { - OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode); - OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpLen); - if (OpCode != EFI_DHCP6_IA_TYPE_NA && - OpCode != EFI_DHCP6_IA_TYPE_TA) { + OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpCode); + OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *)RequestOpt)->OpLen); + if ((OpCode != EFI_DHCP6_IA_TYPE_NA) && + (OpCode != EFI_DHCP6_IA_TYPE_TA)) + { // // Copy all the options except IA option. // @@ -1856,13 +2139,14 @@ PxeBcDhcp6Discover ( DiscoverOpt += (OpLen + 4); DiscoverLen += (OpLen + 4); } + RequestOpt += (OpLen + 4); RequestLen += (OpLen + 4); } Status = PxeBc->UdpWrite ( PxeBc, - OpFlags, + 0, &Private->ServerIp, &DestPort, NULL, @@ -1871,10 +2155,10 @@ PxeBcDhcp6Discover ( NULL, NULL, &DiscoverLen, - (VOID *) Discover + (VOID *)Discover ); if (EFI_ERROR (Status)) { - return Status; + goto ON_ERROR; } // @@ -1887,39 +2171,46 @@ PxeBcDhcp6Discover ( } else { Reply = &Private->ProxyOffer.Dhcp6.Packet.Offer; } - ReadSize = (UINTN) Reply->Size; + + ReadSize = (UINTN)Reply->Size; // // Start Udp6Read instance // Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData); if (EFI_ERROR (Status)) { - return Status; + goto ON_ERROR; } - + Status = PxeBc->UdpRead ( PxeBc, - OpFlags, - &Private->StationIp, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP, + NULL, &SrcPort, &Private->ServerIp, &DestPort, NULL, NULL, &ReadSize, - (VOID *) &Reply->Dhcp6 + (VOID *)&Reply->Dhcp6 ); // // Stop Udp6Read instance // Private->Udp6Read->Configure (Private->Udp6Read, NULL); if (EFI_ERROR (Status)) { - return Status; + goto ON_ERROR; } return EFI_SUCCESS; -} +ON_ERROR: + if (Discover != NULL) { + FreePool (Discover); + } + + return Status; +} /** Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information. @@ -1933,35 +2224,35 @@ PxeBcDhcp6Discover ( **/ EFI_STATUS PxeBcDhcp6Sarr ( - IN PXEBC_PRIVATE_DATA *Private, - IN EFI_DHCP6_PROTOCOL *Dhcp6 + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_DHCP6_PROTOCOL *Dhcp6 ) { - EFI_PXE_BASE_CODE_MODE *PxeMode; - EFI_DHCP6_CONFIG_DATA Config; - EFI_DHCP6_MODE_DATA Mode; - EFI_DHCP6_RETRANSMISSION *Retransmit; - EFI_DHCP6_PACKET_OPTION *OptList[PXEBC_DHCP6_OPTION_MAX_NUM]; - UINT8 Buffer[PXEBC_DHCP6_OPTION_MAX_SIZE]; - UINT32 OptCount; - EFI_STATUS Status; - EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; - EFI_STATUS TimerStatus; - EFI_EVENT Timer; - UINT64 GetMappingTimeOut; - UINTN DataSize; - EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits; - - Status = EFI_SUCCESS; - PxeMode = Private->PxeBc.Mode; - Ip6Cfg = Private->Ip6Cfg; - Timer = NULL; + EFI_PXE_BASE_CODE_MODE *PxeMode; + EFI_DHCP6_CONFIG_DATA Config; + EFI_DHCP6_MODE_DATA Mode; + EFI_DHCP6_RETRANSMISSION *Retransmit; + EFI_DHCP6_PACKET_OPTION *OptList[PXEBC_DHCP6_OPTION_MAX_NUM]; + UINT8 Buffer[PXEBC_DHCP6_OPTION_MAX_SIZE]; + UINT32 OptCount; + EFI_STATUS Status; + EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; + EFI_STATUS TimerStatus; + EFI_EVENT Timer; + UINT64 GetMappingTimeOut; + UINTN DataSize; + EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits; + + Status = EFI_SUCCESS; + PxeMode = Private->PxeBc.Mode; + Ip6Cfg = Private->Ip6Cfg; + Timer = NULL; // // Build option list for the request packet. // - OptCount = PxeBcBuildDhcp6Options (Private, OptList, Buffer); - ASSERT (OptCount> 0); + OptCount = PxeBcBuildDhcp6Options (Private, OptList, Buffer); + ASSERT (OptCount > 0); Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION)); if (Retransmit == NULL) { @@ -2004,7 +2295,6 @@ PxeBcDhcp6Sarr ( ZeroMem (Private->OfferCount, sizeof (Private->OfferCount)); ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex)); - // // Start DHCPv6 S.A.R.R. process to acquire IPv6 address. // @@ -2020,12 +2310,12 @@ PxeBcDhcp6Sarr ( // Get Duplicate Address Detection Transmits count. // DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS); - Status = Ip6Cfg->GetData ( - Ip6Cfg, - Ip6ConfigDataTypeDupAddrDetectTransmits, - &DataSize, - &DadXmits - ); + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeDupAddrDetectTransmits, + &DataSize, + &DadXmits + ); if (EFI_ERROR (Status)) { Dhcp6->Configure (Dhcp6, NULL); return Status; @@ -2038,7 +2328,7 @@ PxeBcDhcp6Sarr ( } GetMappingTimeOut = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + PXEBC_DAD_ADDITIONAL_DELAY; - Status = gBS->SetTimer (Timer, TimerRelative, GetMappingTimeOut); + Status = gBS->SetTimer (Timer, TimerRelative, GetMappingTimeOut); if (EFI_ERROR (Status)) { gBS->CloseEvent (Timer); Dhcp6->Configure (Dhcp6, NULL); @@ -2046,19 +2336,20 @@ PxeBcDhcp6Sarr ( } do { - TimerStatus = gBS->CheckEvent (Timer); if (!EFI_ERROR (TimerStatus)) { Status = Dhcp6->Start (Dhcp6); } } while (TimerStatus == EFI_NOT_READY); - + gBS->CloseEvent (Timer); } + if (EFI_ERROR (Status)) { if (Status == EFI_ICMP_ERROR) { PxeMode->IcmpErrorReceived = TRUE; } + Dhcp6->Configure (Dhcp6, NULL); return Status; } @@ -2072,15 +2363,22 @@ PxeBcDhcp6Sarr ( return Status; } - ASSERT (Mode.Ia->State == Dhcp6Bound); + ASSERT ((Mode.Ia != NULL) && (Mode.Ia->State == Dhcp6Bound)); // // DHCP6 doesn't have an option to specify the router address on the subnet, the only way to get the // router address in IP6 is the router discovery mechanism (the RS and RA, which only be handled when // the IP policy is Automatic). So we just hold the station IP address here and leave the IP policy as - // Automatic, until we get the server IP address. This could let IP6 driver finish the router discovery + // Automatic, until we get the server IP address. This could let IP6 driver finish the router discovery // to find a valid router address. // CopyMem (&Private->TmpStationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS)); + if (Mode.ClientId != NULL) { + FreePool (Mode.ClientId); + } + + if (Mode.Ia != NULL) { + FreePool (Mode.Ia); + } // // Check the selected offer whether BINL retry is needed. @@ -2090,6 +2388,6 @@ PxeBcDhcp6Sarr ( Dhcp6->Stop (Dhcp6); return Status; } - + return EFI_SUCCESS; }