Home | History | Annotate | Download | only in UefiPxeBcDxe
      1 /** @file
      2   Functions implementation related with DHCPv6 for UefiPxeBc Driver.
      3 
      4   (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
      5   Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
      6 
      7   This program and the accompanying materials
      8   are licensed and made available under the terms and conditions of the BSD License
      9   which accompanies this distribution.  The full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php.
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "PxeBcImpl.h"
     18 
     19 //
     20 // Well-known multi-cast address defined in section-24.1 of rfc-3315
     21 //
     22 //   ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2
     23 //
     24 EFI_IPv6_ADDRESS   mAllDhcpRelayAndServersAddress = {{0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}};
     25 
     26 /**
     27   Parse out a DHCPv6 option by OptTag, and find the position in buffer.
     28 
     29   @param[in]  Buffer        The pointer to the option buffer.
     30   @param[in]  Length        Length of the option buffer.
     31   @param[in]  OptTag        The required option tag.
     32 
     33   @retval     NULL          Failed to parse the required option.
     34   @retval     Others        The postion of the required option in buffer.
     35 
     36 **/
     37 EFI_DHCP6_PACKET_OPTION *
     38 PxeBcParseDhcp6Options (
     39   IN UINT8                       *Buffer,
     40   IN UINT32                      Length,
     41   IN UINT16                      OptTag
     42   )
     43 {
     44   EFI_DHCP6_PACKET_OPTION        *Option;
     45   UINT32                         Offset;
     46 
     47   Option  = (EFI_DHCP6_PACKET_OPTION *) Buffer;
     48   Offset  = 0;
     49 
     50   //
     51   // OpLen and OpCode here are both stored in network order.
     52   //
     53   while (Offset < Length) {
     54 
     55     if (NTOHS (Option->OpCode) == OptTag) {
     56 
     57       return Option;
     58     }
     59 
     60     Offset += (NTOHS(Option->OpLen) + 4);
     61     Option  = (EFI_DHCP6_PACKET_OPTION *) (Buffer + Offset);
     62   }
     63 
     64   return NULL;
     65 }
     66 
     67 
     68 /**
     69   Build the options buffer for the DHCPv6 request packet.
     70 
     71   @param[in]  Private             The pointer to PxeBc private data.
     72   @param[out] OptList             The pointer to the option pointer array.
     73   @param[in]  Buffer              The pointer to the buffer to contain the option list.
     74 
     75   @return     Index               The count of the built-in options.
     76 
     77 **/
     78 UINT32
     79 PxeBcBuildDhcp6Options (
     80   IN  PXEBC_PRIVATE_DATA           *Private,
     81   OUT EFI_DHCP6_PACKET_OPTION      **OptList,
     82   IN  UINT8                        *Buffer
     83   )
     84 {
     85   PXEBC_DHCP6_OPTION_ENTRY         OptEnt;
     86   UINT32                           Index;
     87   UINT16                           Value;
     88 
     89   Index       = 0;
     90   OptList[0]  = (EFI_DHCP6_PACKET_OPTION *) Buffer;
     91 
     92   //
     93   // Append client option request option
     94   //
     95   OptList[Index]->OpCode     = HTONS (PXEBC_DHCP6_OPT_ORO);
     96   OptList[Index]->OpLen      = HTONS (4);
     97   OptEnt.Oro                 = (PXEBC_DHCP6_OPTION_ORO *) OptList[Index]->Data;
     98   OptEnt.Oro->OpCode[0]      = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_URL);
     99   OptEnt.Oro->OpCode[1]      = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_PARAM);
    100   Index++;
    101   OptList[Index]             = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);
    102 
    103   //
    104   // Append client network device interface option
    105   //
    106   OptList[Index]->OpCode     = HTONS (PXEBC_DHCP6_OPT_UNDI);
    107   OptList[Index]->OpLen      = HTONS ((UINT16)3);
    108   OptEnt.Undi                = (PXEBC_DHCP6_OPTION_UNDI *) OptList[Index]->Data;
    109 
    110   if (Private->Nii != NULL) {
    111     OptEnt.Undi->Type        = Private->Nii->Type;
    112     OptEnt.Undi->MajorVer    = Private->Nii->MajorVer;
    113     OptEnt.Undi->MinorVer    = Private->Nii->MinorVer;
    114   } else {
    115     OptEnt.Undi->Type        = DEFAULT_UNDI_TYPE;
    116     OptEnt.Undi->MajorVer    = DEFAULT_UNDI_MAJOR;
    117     OptEnt.Undi->MinorVer    = DEFAULT_UNDI_MINOR;
    118   }
    119 
    120   Index++;
    121   OptList[Index]             = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);
    122 
    123   //
    124   // Append client system architecture option
    125   //
    126   OptList[Index]->OpCode     = HTONS (PXEBC_DHCP6_OPT_ARCH);
    127   OptList[Index]->OpLen      = HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTION_ARCH));
    128   OptEnt.Arch                = (PXEBC_DHCP6_OPTION_ARCH *) OptList[Index]->Data;
    129   Value                      = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE);
    130   CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));
    131   Index++;
    132   OptList[Index]             = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);
    133 
    134   //
    135   // Append vendor class option to store the PXE class identifier.
    136   //
    137   OptList[Index]->OpCode       = HTONS (PXEBC_DHCP6_OPT_VENDOR_CLASS);
    138   OptList[Index]->OpLen        = HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS));
    139   OptEnt.VendorClass           = (PXEBC_DHCP6_OPTION_VENDOR_CLASS *) OptList[Index]->Data;
    140   OptEnt.VendorClass->Vendor   = HTONL (PXEBC_DHCP6_ENTERPRISE_NUM);
    141   OptEnt.VendorClass->ClassLen = HTONS ((UINT16) sizeof (PXEBC_CLASS_ID));
    142   CopyMem (
    143     &OptEnt.VendorClass->ClassId,
    144     DEFAULT_CLASS_ID_DATA,
    145     sizeof (PXEBC_CLASS_ID)
    146     );
    147   PxeBcUintnToAscDecWithFormat (
    148     EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE,
    149     OptEnt.VendorClass->ClassId.ArchitectureType,
    150     sizeof (OptEnt.VendorClass->ClassId.ArchitectureType)
    151     );
    152 
    153   if (Private->Nii != NULL) {
    154     CopyMem (
    155       OptEnt.VendorClass->ClassId.InterfaceName,
    156       Private->Nii->StringId,
    157       sizeof (OptEnt.VendorClass->ClassId.InterfaceName)
    158       );
    159     PxeBcUintnToAscDecWithFormat (
    160       Private->Nii->MajorVer,
    161       OptEnt.VendorClass->ClassId.UndiMajor,
    162       sizeof (OptEnt.VendorClass->ClassId.UndiMajor)
    163       );
    164     PxeBcUintnToAscDecWithFormat (
    165       Private->Nii->MinorVer,
    166       OptEnt.VendorClass->ClassId.UndiMinor,
    167       sizeof (OptEnt.VendorClass->ClassId.UndiMinor)
    168       );
    169   }
    170 
    171   Index++;
    172 
    173   return Index;
    174 }
    175 
    176 
    177 /**
    178   Cache the DHCPv6 packet.
    179 
    180   @param[in]  Dst          The pointer to the cache buffer for DHCPv6 packet.
    181   @param[in]  Src          The pointer to the DHCPv6 packet to be cached.
    182 
    183 **/
    184 VOID
    185 PxeBcCacheDhcp6Packet (
    186   IN EFI_DHCP6_PACKET          *Dst,
    187   IN EFI_DHCP6_PACKET          *Src
    188   )
    189 {
    190   ASSERT (Dst->Size >= Src->Length);
    191 
    192   CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length);
    193   Dst->Length = Src->Length;
    194 }
    195 
    196 
    197 /**
    198   Free all the nodes in the list for boot file.
    199 
    200   @param[in]  Head            The pointer to the head of list.
    201 
    202 **/
    203 VOID
    204 PxeBcFreeBootFileOption (
    205   IN LIST_ENTRY               *Head
    206   )
    207 {
    208   LIST_ENTRY                  *Entry;
    209   LIST_ENTRY                  *NextEntry;
    210   PXEBC_DHCP6_OPTION_NODE     *Node;
    211 
    212   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, Head) {
    213     Node = NET_LIST_USER_STRUCT (Entry, PXEBC_DHCP6_OPTION_NODE, Link);
    214     RemoveEntryList (Entry);
    215     FreePool (Node);
    216   }
    217 }
    218 
    219 
    220 /**
    221   Parse the Boot File URL option.
    222 
    223   @param[out]     FileName     The pointer to the boot file name.
    224   @param[in, out] SrvAddr      The pointer to the boot server address.
    225   @param[in]      BootFile     The pointer to the boot file URL option data.
    226   @param[in]      Length       The length of the boot file URL option data.
    227 
    228   @retval EFI_ABORTED     User cancel operation.
    229   @retval EFI_SUCCESS     Selected the boot menu successfully.
    230   @retval EFI_NOT_READY   Read the input key from the keybroad has not finish.
    231 
    232 **/
    233 EFI_STATUS
    234 PxeBcExtractBootFileUrl (
    235      OUT UINT8               **FileName,
    236   IN OUT EFI_IPv6_ADDRESS    *SrvAddr,
    237   IN     CHAR8               *BootFile,
    238   IN     UINT16              Length
    239   )
    240 {
    241   UINT16                     PrefixLen;
    242   CHAR8                      *BootFileNamePtr;
    243   CHAR8                      *BootFileName;
    244   UINT16                     BootFileNameLen;
    245   CHAR8                      *TmpStr;
    246   CHAR8                      TmpChar;
    247   CHAR8                      *ServerAddressOption;
    248   CHAR8                      *ServerAddress;
    249   CHAR8                      *ModeStr;
    250   EFI_STATUS                 Status;
    251 
    252   //
    253   // The format of the Boot File URL option is:
    254   //
    255   //  0                   1                   2                   3
    256   //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    257   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    258   // |       OPT_BOOTFILE_URL        |            option-len         |
    259   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    260   // |                                                               |
    261   // .                  bootfile-url  (variable length)              .
    262   // |                                                               |
    263   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    264   //
    265 
    266   //
    267   // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile-url format
    268   // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME
    269   // As an example where the BOOTFILE_NAME is the EFI loader and
    270   // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.
    271   //
    272   PrefixLen = (UINT16) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX);
    273 
    274   if (Length <= PrefixLen ||
    275       CompareMem (BootFile, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX, PrefixLen) != 0) {
    276     return EFI_NOT_FOUND;
    277   }
    278 
    279   BootFile = BootFile + PrefixLen;
    280   Length   = (UINT16) (Length - PrefixLen);
    281 
    282   TmpStr = (CHAR8 *) AllocateZeroPool (Length + 1);
    283   if (TmpStr == NULL) {
    284     return EFI_OUT_OF_RESOURCES;
    285   }
    286 
    287   CopyMem (TmpStr, BootFile, Length);
    288   TmpStr[Length] = '\0';
    289 
    290   //
    291   // Get the part of SERVER_ADDRESS string.
    292   //
    293   ServerAddressOption = TmpStr;
    294   if (*ServerAddressOption != PXEBC_ADDR_START_DELIMITER) {
    295     FreePool (TmpStr);
    296     return EFI_INVALID_PARAMETER;
    297   }
    298 
    299   ServerAddressOption ++;
    300   ServerAddress = ServerAddressOption;
    301   while (*ServerAddress != '\0' && *ServerAddress != PXEBC_ADDR_END_DELIMITER) {
    302     ServerAddress++;
    303   }
    304 
    305   if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) {
    306     FreePool (TmpStr);
    307     return EFI_INVALID_PARAMETER;
    308   }
    309 
    310   *ServerAddress = '\0';
    311 
    312   //
    313   // Convert the string of server address to Ipv6 address format and store it.
    314   //
    315   Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr);
    316   if (EFI_ERROR (Status)) {
    317     FreePool (TmpStr);
    318     return Status;
    319   }
    320 
    321   //
    322   // Get the part of BOOTFILE_NAME string.
    323   //
    324   BootFileNamePtr = (CHAR8*)((UINTN)ServerAddress + 1);
    325   if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) {
    326     FreePool (TmpStr);
    327     return EFI_INVALID_PARAMETER;
    328   }
    329 
    330   ++BootFileNamePtr;
    331   BootFileNameLen = (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1);
    332   if (BootFileNameLen != 0 || FileName != NULL) {
    333     //
    334     // Remove trailing mode=octet if present and ignore.  All other modes are
    335     // invalid for netboot6, so reject them.
    336     //
    337     ModeStr = AsciiStrStr (BootFileNamePtr, ";mode=octet");
    338     if (ModeStr != NULL && *(ModeStr + AsciiStrLen (";mode=octet")) == '\0') {
    339       *ModeStr = '\0';
    340     } else if (AsciiStrStr (BootFileNamePtr, ";mode=") != NULL) {
    341       return EFI_INVALID_PARAMETER;
    342     }
    343 
    344     //
    345     // Extract boot file name from URL.
    346     //
    347     BootFileName = (CHAR8 *) AllocateZeroPool (BootFileNameLen);
    348     if (BootFileName == NULL) {
    349       FreePool (TmpStr);
    350       return EFI_OUT_OF_RESOURCES;
    351     }
    352     *FileName = (UINT8*) BootFileName;
    353 
    354     //
    355     // Decode percent-encoding in boot file name.
    356     //
    357     while (*BootFileNamePtr != '\0') {
    358       if (*BootFileNamePtr == '%') {
    359         TmpChar = *(BootFileNamePtr+ 3);
    360         *(BootFileNamePtr+ 3) = '\0';
    361         *BootFileName = (UINT8) AsciiStrHexToUintn ((CHAR8*)(BootFileNamePtr + 1));
    362         BootFileName++;
    363         *(BootFileNamePtr+ 3) = TmpChar;
    364         BootFileNamePtr += 3;
    365       } else {
    366         *BootFileName = *BootFileNamePtr;
    367         BootFileName++;
    368         BootFileNamePtr++;
    369       }
    370     }
    371     *BootFileName = '\0';
    372   }
    373 
    374   FreePool (TmpStr);
    375 
    376   return EFI_SUCCESS;
    377 }
    378 
    379 
    380 /**
    381   Parse the Boot File Parameter option.
    382 
    383   @param[in]  BootFilePara      The pointer to boot file parameter option data.
    384   @param[out] BootFileSize      The pointer to the parsed boot file size.
    385 
    386   @retval EFI_SUCCESS     Successfully obtained the boot file size from parameter option.
    387   @retval EFI_NOT_FOUND   Failed to extract the boot file size from parameter option.
    388 
    389 **/
    390 EFI_STATUS
    391 PxeBcExtractBootFileParam (
    392   IN  CHAR8                  *BootFilePara,
    393   OUT UINT16                 *BootFileSize
    394   )
    395 {
    396   UINT16                     Length;
    397   UINT8                      Index;
    398   UINT8                      Digit;
    399   UINT32                     Size;
    400 
    401   CopyMem (&Length, BootFilePara, sizeof (UINT16));
    402   Length = NTOHS (Length);
    403 
    404   //
    405   // The BootFile Size should be 1~5 byte ASCII strings
    406   //
    407   if (Length < 1 || Length > 5) {
    408     return EFI_NOT_FOUND;
    409   }
    410 
    411   //
    412   // Extract the value of BootFile Size.
    413   //
    414   BootFilePara = BootFilePara + sizeof (UINT16);
    415   Size         = 0;
    416   for (Index = 0; Index < Length; Index++) {
    417     if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit, *(BootFilePara + Index)))) {
    418       return EFI_NOT_FOUND;
    419     }
    420 
    421     Size = (Size + Digit) * 10;
    422   }
    423 
    424   Size = Size / 10;
    425   if (Size > PXEBC_DHCP6_MAX_BOOT_FILE_SIZE) {
    426     return EFI_NOT_FOUND;
    427   }
    428 
    429   *BootFileSize = (UINT16) Size;
    430   return EFI_SUCCESS;
    431 }
    432 
    433 
    434 /**
    435   Parse the cached DHCPv6 packet, including all the options.
    436 
    437   @param[in]  Cache6           The pointer to a cached DHCPv6 packet.
    438 
    439   @retval     EFI_SUCCESS      Parsed the DHCPv6 packet successfully.
    440   @retval     EFI_DEVICE_ERROR Failed to parse and invalid the packet.
    441 
    442 **/
    443 EFI_STATUS
    444 PxeBcParseDhcp6Packet (
    445   IN PXEBC_DHCP6_PACKET_CACHE  *Cache6
    446   )
    447 {
    448   EFI_DHCP6_PACKET             *Offer;
    449   EFI_DHCP6_PACKET_OPTION      **Options;
    450   EFI_DHCP6_PACKET_OPTION      *Option;
    451   PXEBC_OFFER_TYPE             OfferType;
    452   BOOLEAN                      IsProxyOffer;
    453   BOOLEAN                      IsPxeOffer;
    454   UINT32                       Offset;
    455   UINT32                       Length;
    456   UINT32                       EnterpriseNum;
    457 
    458   IsProxyOffer = TRUE;
    459   IsPxeOffer   = FALSE;
    460   Offer        = &Cache6->Packet.Offer;
    461   Options      = Cache6->OptList;
    462 
    463   ZeroMem (Cache6->OptList, sizeof (Cache6->OptList));
    464 
    465   Option  = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option);
    466   Offset  = 0;
    467   Length  = GET_DHCP6_OPTION_SIZE (Offer);
    468 
    469   //
    470   // OpLen and OpCode here are both stored in network order, since they are from original packet.
    471   //
    472   while (Offset < Length) {
    473 
    474     if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_IA_NA) {
    475       Options[PXEBC_DHCP6_IDX_IA_NA] = Option;
    476     } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_BOOT_FILE_URL) {
    477       //
    478       // The server sends this option to inform the client about an URL to a boot file.
    479       //
    480       Options[PXEBC_DHCP6_IDX_BOOT_FILE_URL] = Option;
    481     } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_BOOT_FILE_PARAM) {
    482       Options[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] = Option;
    483     } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_VENDOR_CLASS) {
    484       Options[PXEBC_DHCP6_IDX_VENDOR_CLASS] = Option;
    485     }
    486 
    487     Offset += (NTOHS (Option->OpLen) + 4);
    488     Option  = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option + Offset);
    489   }
    490 
    491   //
    492   // The offer with assigned client address is NOT a proxy offer.
    493   // An ia_na option, embeded with valid ia_addr option and a status_code of success.
    494   //
    495   Option = Options[PXEBC_DHCP6_IDX_IA_NA];
    496   if (Option != NULL) {
    497     Option = PxeBcParseDhcp6Options (
    498                Option->Data + 12,
    499                NTOHS (Option->OpLen),
    500                PXEBC_DHCP6_OPT_STATUS_CODE
    501                );
    502     if ((Option != NULL && Option->Data[0] == 0) || (Option == NULL)) {
    503       IsProxyOffer = FALSE;
    504     }
    505   }
    506 
    507   //
    508   // The offer with "PXEClient" is a pxe offer.
    509   //
    510   Option        = Options[PXEBC_DHCP6_IDX_VENDOR_CLASS];
    511   EnterpriseNum = HTONL(PXEBC_DHCP6_ENTERPRISE_NUM);
    512 
    513   if (Option != NULL &&
    514       NTOHS(Option->OpLen) >= 13 &&
    515       CompareMem (Option->Data, &EnterpriseNum, sizeof (UINT32)) == 0 &&
    516       CompareMem (&Option->Data[6], DEFAULT_CLASS_ID_DATA, 9) == 0) {
    517     IsPxeOffer = TRUE;
    518   }
    519 
    520   //
    521   // Determine offer type of the dhcp6 packet.
    522   //
    523   if (IsPxeOffer) {
    524     //
    525     // It's a binl offer only with PXEClient.
    526     //
    527     OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl;
    528   } else {
    529     //
    530     // It's a dhcp only offer, which is a pure dhcp6 offer packet.
    531     //
    532     OfferType = PxeOfferTypeDhcpOnly;
    533   }
    534 
    535   Cache6->OfferType = OfferType;
    536 
    537   return EFI_SUCCESS;
    538 }
    539 
    540 
    541 /**
    542   Cache the DHCPv6 ack packet, and parse it on demand.
    543 
    544   @param[in]  Private             The pointer to PxeBc private data.
    545   @param[in]  Ack                 The pointer to the DHCPv6 ack packet.
    546   @param[in]  Verified            If TRUE, parse the ACK packet and store info into mode data.
    547 
    548 **/
    549 VOID
    550 PxeBcCopyDhcp6Ack (
    551   IN PXEBC_PRIVATE_DATA   *Private,
    552   IN EFI_DHCP6_PACKET     *Ack,
    553   IN BOOLEAN              Verified
    554   )
    555 {
    556   EFI_PXE_BASE_CODE_MODE  *Mode;
    557 
    558   Mode = Private->PxeBc.Mode;
    559 
    560   PxeBcCacheDhcp6Packet (&Private->DhcpAck.Dhcp6.Packet.Ack, Ack);
    561 
    562   if (Verified) {
    563     //
    564     // Parse the ack packet and store it into mode data if needed.
    565     //
    566     PxeBcParseDhcp6Packet (&Private->DhcpAck.Dhcp6);
    567     CopyMem (&Mode->DhcpAck.Dhcpv6, &Ack->Dhcp6, Ack->Length);
    568     Mode->DhcpAckReceived = TRUE;
    569   }
    570 }
    571 
    572 
    573 /**
    574   Cache the DHCPv6 proxy offer packet according to the received order.
    575 
    576   @param[in]  Private               The pointer to PxeBc private data.
    577   @param[in]  OfferIndex            The received order of offer packets.
    578 
    579 **/
    580 VOID
    581 PxeBcCopyDhcp6Proxy (
    582   IN PXEBC_PRIVATE_DATA     *Private,
    583   IN UINT32                 OfferIndex
    584   )
    585 {
    586   EFI_PXE_BASE_CODE_MODE    *Mode;
    587   EFI_DHCP6_PACKET          *Offer;
    588 
    589   ASSERT (OfferIndex < Private->OfferNum);
    590   ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM);
    591 
    592   Mode  = Private->PxeBc.Mode;
    593   Offer = &Private->OfferBuffer[OfferIndex].Dhcp6.Packet.Offer;
    594 
    595   //
    596   // Cache the proxy offer packet and parse it.
    597   //
    598   PxeBcCacheDhcp6Packet (&Private->ProxyOffer.Dhcp6.Packet.Offer, Offer);
    599   PxeBcParseDhcp6Packet (&Private->ProxyOffer.Dhcp6);
    600 
    601   //
    602   // Store this packet into mode data.
    603   //
    604   CopyMem (&Mode->ProxyOffer.Dhcpv6, &Offer->Dhcp6, Offer->Length);
    605   Mode->ProxyOfferReceived = TRUE;
    606 }
    607 
    608 /**
    609   Seek the address of the first byte of the option header.
    610 
    611   @param[in]  Buf           The pointer to the buffer.
    612   @param[in]  SeekLen       The length to seek.
    613   @param[in]  OptType       The option type.
    614 
    615   @retval     NULL          If it failed to seek the option.
    616   @retval     others        The position to the option.
    617 
    618 **/
    619 UINT8 *
    620 PxeBcDhcp6SeekOption (
    621   IN UINT8           *Buf,
    622   IN UINT32          SeekLen,
    623   IN UINT16          OptType
    624   )
    625 {
    626   UINT8              *Cursor;
    627   UINT8              *Option;
    628   UINT16             DataLen;
    629   UINT16             OpCode;
    630 
    631   Option = NULL;
    632   Cursor = Buf;
    633 
    634   while (Cursor < Buf + SeekLen) {
    635     OpCode = ReadUnaligned16 ((UINT16 *) Cursor);
    636     if (OpCode == HTONS (OptType)) {
    637       Option = Cursor;
    638       break;
    639     }
    640     DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2)));
    641     Cursor += (DataLen + 4);
    642   }
    643 
    644   return Option;
    645 }
    646 
    647 
    648 /**
    649   Build and send out the request packet for the bootfile, and parse the reply.
    650 
    651   @param[in]  Private               The pointer to PxeBc private data.
    652   @param[in]  Index                 PxeBc option boot item type.
    653 
    654   @retval     EFI_SUCCESS           Successfully discovered the boot file.
    655   @retval     EFI_OUT_OF_RESOURCES  Failed to allocate resources.
    656   @retval     EFI_NOT_FOUND         Can't get the PXE reply packet.
    657   @retval     Others                Failed to discover the boot file.
    658 
    659 **/
    660 EFI_STATUS
    661 PxeBcRequestBootService (
    662   IN  PXEBC_PRIVATE_DATA              *Private,
    663   IN  UINT32                          Index
    664   )
    665 {
    666   EFI_PXE_BASE_CODE_UDP_PORT          SrcPort;
    667   EFI_PXE_BASE_CODE_UDP_PORT          DestPort;
    668   EFI_PXE_BASE_CODE_PROTOCOL          *PxeBc;
    669   EFI_PXE_BASE_CODE_DHCPV6_PACKET     *Discover;
    670   UINTN                               DiscoverLen;
    671   EFI_DHCP6_PACKET                    *Request;
    672   UINTN                               RequestLen;
    673   EFI_DHCP6_PACKET                    *Reply;
    674   UINT8                               *RequestOpt;
    675   UINT8                               *DiscoverOpt;
    676   UINTN                               ReadSize;
    677   UINT16                              OpFlags;
    678   UINT16                              OpCode;
    679   UINT16                              OpLen;
    680   EFI_STATUS                          Status;
    681   EFI_DHCP6_PACKET                    *ProxyOffer;
    682   UINT8                               *Option;
    683 
    684   PxeBc       = &Private->PxeBc;
    685   Request     = Private->Dhcp6Request;
    686   ProxyOffer = &Private->OfferBuffer[Index].Dhcp6.Packet.Offer;
    687   SrcPort     = PXEBC_BS_DISCOVER_PORT;
    688   DestPort    = PXEBC_BS_DISCOVER_PORT;
    689   OpFlags     = 0;
    690 
    691   if (Request == NULL) {
    692     return EFI_DEVICE_ERROR;
    693   }
    694 
    695   Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET));
    696   if (Discover == NULL) {
    697     return EFI_OUT_OF_RESOURCES;
    698   }
    699 
    700   //
    701   // Build the request packet by the cached request packet before.
    702   //
    703   Discover->TransactionId = ProxyOffer->Dhcp6.Header.TransactionId;
    704   Discover->MessageType   = Request->Dhcp6.Header.MessageType;
    705   RequestOpt              = Request->Dhcp6.Option;
    706   DiscoverOpt             = Discover->DhcpOptions;
    707   DiscoverLen             = sizeof (EFI_DHCP6_HEADER);
    708   RequestLen              = DiscoverLen;
    709 
    710   //
    711   // Find Server ID Option from ProxyOffer.
    712   //
    713   Option = PxeBcDhcp6SeekOption (
    714              ProxyOffer->Dhcp6.Option,
    715              ProxyOffer->Length - 4,
    716              PXEBC_DHCP6_OPT_SERVER_ID
    717              );
    718   if (Option == NULL) {
    719     return EFI_NOT_FOUND;
    720   }
    721 
    722   //
    723   // Add Server ID Option.
    724   //
    725   OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) Option)->OpLen);
    726   CopyMem (DiscoverOpt, Option, OpLen + 4);
    727   DiscoverOpt += (OpLen + 4);
    728   DiscoverLen += (OpLen + 4);
    729 
    730   while (RequestLen < Request->Length) {
    731     OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode);
    732     OpLen  = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpLen);
    733     if (OpCode != EFI_DHCP6_IA_TYPE_NA &&
    734         OpCode != EFI_DHCP6_IA_TYPE_TA &&
    735         OpCode != PXEBC_DHCP6_OPT_SERVER_ID
    736         ) {
    737       //
    738       // Copy all the options except IA option and Server ID
    739       //
    740       CopyMem (DiscoverOpt, RequestOpt, OpLen + 4);
    741       DiscoverOpt += (OpLen + 4);
    742       DiscoverLen += (OpLen + 4);
    743     }
    744     RequestOpt += (OpLen + 4);
    745     RequestLen += (OpLen + 4);
    746   }
    747 
    748   //
    749   // Update Elapsed option in the package
    750   //
    751   Option = PxeBcDhcp6SeekOption (
    752              Discover->DhcpOptions,
    753              (UINT32)(RequestLen - 4),
    754              PXEBC_DHCP6_OPT_ELAPSED_TIME
    755              );
    756   if (Option != NULL) {
    757     CalcElapsedTime (Private);
    758     WriteUnaligned16 ((UINT16*)(Option + 4), HTONS((UINT16) Private->ElapsedTime));
    759   }
    760 
    761   Status = PxeBc->UdpWrite (
    762                     PxeBc,
    763                     OpFlags,
    764                     &Private->ServerIp,
    765                     &DestPort,
    766                     NULL,
    767                     &Private->StationIp,
    768                     &SrcPort,
    769                     NULL,
    770                     NULL,
    771                     &DiscoverLen,
    772                     (VOID *) Discover
    773                     );
    774 
    775   if (EFI_ERROR (Status)) {
    776     return Status;
    777   }
    778 
    779   //
    780   // Cache the right PXE reply packet here, set valid flag later.
    781   // Especially for PXE discover packet, store it into mode data here.
    782   //
    783   Reply = &Private->ProxyOffer.Dhcp6.Packet.Offer;
    784   ReadSize = (UINTN) Reply->Size;
    785 
    786   //
    787   // Start Udp6Read instance
    788   //
    789   Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);
    790   if (EFI_ERROR (Status)) {
    791     return Status;
    792   }
    793 
    794   Status = PxeBc->UdpRead (
    795                     PxeBc,
    796                     EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP,
    797                     NULL,
    798                     &SrcPort,
    799                     &Private->ServerIp,
    800                     &DestPort,
    801                     NULL,
    802                     NULL,
    803                     &ReadSize,
    804                     (VOID *) &Reply->Dhcp6
    805                     );
    806   //
    807   // Stop Udp6Read instance
    808   //
    809   Private->Udp6Read->Configure (Private->Udp6Read, NULL);
    810 
    811   if (EFI_ERROR (Status)) {
    812     return Status;
    813   }
    814 
    815   //
    816   // Update length
    817   //
    818   Reply->Length = (UINT32) ReadSize;
    819 
    820   return EFI_SUCCESS;
    821 }
    822 
    823 
    824 /**
    825   Retry to request bootfile name by the BINL offer.
    826 
    827   @param[in]  Private              The pointer to PxeBc private data.
    828   @param[in]  Index                The received order of offer packets.
    829 
    830   @retval     EFI_SUCCESS          Successfully retried a request for the bootfile name.
    831   @retval     EFI_DEVICE_ERROR     Failed to retry the bootfile name.
    832 
    833 **/
    834 EFI_STATUS
    835 PxeBcRetryDhcp6Binl (
    836   IN PXEBC_PRIVATE_DATA  *Private,
    837   IN UINT32              Index
    838   )
    839 {
    840   EFI_PXE_BASE_CODE_MODE    *Mode;
    841   PXEBC_DHCP6_PACKET_CACHE  *Offer;
    842   PXEBC_DHCP6_PACKET_CACHE  *Cache6;
    843   EFI_STATUS                Status;
    844 
    845   ASSERT (Index < PXEBC_OFFER_MAX_NUM);
    846   ASSERT (Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeDhcpBinl ||
    847           Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeProxyBinl);
    848 
    849   Mode                  = Private->PxeBc.Mode;
    850   Private->IsDoDiscover = FALSE;
    851   Offer                 = &Private->OfferBuffer[Index].Dhcp6;
    852   if (Offer->OfferType == PxeOfferTypeDhcpBinl) {
    853     //
    854     // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead.
    855     //
    856     CopyMem (
    857       &Private->ServerIp.v6,
    858       &mAllDhcpRelayAndServersAddress,
    859       sizeof (EFI_IPv6_ADDRESS)
    860       );
    861   } else {
    862     ASSERT (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);
    863     //
    864     // Parse out the next server address from the last offer, and store it
    865     //
    866     Status = PxeBcExtractBootFileUrl (
    867                &Private->BootFileName,
    868                &Private->ServerIp.v6,
    869                (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),
    870                NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen)
    871                );
    872     if (EFI_ERROR (Status)) {
    873       return Status;
    874     }
    875   }
    876 
    877   //
    878   // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.
    879   //
    880   Status = PxeBcRequestBootService (Private, Index);
    881 
    882   if (EFI_ERROR (Status)) {
    883     return Status;
    884   }
    885 
    886   Cache6 = &Private->ProxyOffer.Dhcp6;
    887   Status = PxeBcParseDhcp6Packet (Cache6);
    888   if (EFI_ERROR (Status)) {
    889     return Status;
    890   }
    891 
    892   if (Cache6->OfferType != PxeOfferTypeProxyPxe10 &&
    893       Cache6->OfferType != PxeOfferTypeProxyWfm11a &&
    894       Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) {
    895     //
    896     // This BINL ack doesn't have discovery option set or multicast option set
    897     // or bootfile name specified.
    898     //
    899     return EFI_DEVICE_ERROR;
    900   }
    901 
    902   Mode->ProxyOfferReceived = TRUE;
    903   CopyMem (
    904     &Mode->ProxyOffer.Dhcpv6,
    905     &Cache6->Packet.Offer.Dhcp6,
    906     Cache6->Packet.Offer.Length
    907     );
    908 
    909   return EFI_SUCCESS;
    910 }
    911 
    912 
    913 /**
    914   Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
    915 
    916   @param[in]  Private               The pointer to PXEBC_PRIVATE_DATA.
    917   @param[in]  RcvdOffer             The pointer to the received offer packet.
    918 
    919 **/
    920 VOID
    921 PxeBcCacheDhcp6Offer (
    922   IN PXEBC_PRIVATE_DATA     *Private,
    923   IN EFI_DHCP6_PACKET       *RcvdOffer
    924   )
    925 {
    926   PXEBC_DHCP6_PACKET_CACHE  *Cache6;
    927   EFI_DHCP6_PACKET          *Offer;
    928   PXEBC_OFFER_TYPE          OfferType;
    929 
    930   Cache6 = &Private->OfferBuffer[Private->OfferNum].Dhcp6;
    931   Offer  = &Cache6->Packet.Offer;
    932 
    933   //
    934   // Cache the content of DHCPv6 packet firstly.
    935   //
    936   PxeBcCacheDhcp6Packet (Offer, RcvdOffer);
    937 
    938   //
    939   // Validate the DHCPv6 packet, and parse the options and offer type.
    940   //
    941   if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6))) {
    942     return ;
    943   }
    944 
    945   //
    946   // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
    947   //
    948   OfferType = Cache6->OfferType;
    949   ASSERT (OfferType < PxeOfferTypeMax);
    950   ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM);
    951 
    952   if (IS_PROXY_OFFER (OfferType)) {
    953     //
    954     // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
    955     //
    956     Private->IsProxyRecved = TRUE;
    957 
    958     if (OfferType == PxeOfferTypeProxyBinl) {
    959       //
    960       // Cache all proxy BINL offers.
    961       //
    962       Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
    963       Private->OfferCount[OfferType]++;
    964     } else if (Private->OfferCount[OfferType] > 0) {
    965       //
    966       // Only cache the first PXE10/WFM11a offer, and discard the others.
    967       //
    968       Private->OfferIndex[OfferType][0] = Private->OfferNum;
    969       Private->OfferCount[OfferType]    = 1;
    970     } else {
    971       return;
    972     }
    973   } else {
    974     //
    975     // It's a DHCPv6 offer with yiaddr, and cache them all.
    976     //
    977     Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
    978     Private->OfferCount[OfferType]++;
    979   }
    980 
    981   Private->OfferNum++;
    982 }
    983 
    984 
    985 /**
    986   Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.
    987 
    988   @param[in]  Private             The pointer to PXEBC_PRIVATE_DATA.
    989 
    990 **/
    991 VOID
    992 PxeBcSelectDhcp6Offer (
    993   IN PXEBC_PRIVATE_DATA     *Private
    994   )
    995 {
    996   UINT32                Index;
    997   UINT32                OfferIndex;
    998   PXEBC_OFFER_TYPE      OfferType;
    999 
   1000   Private->SelectIndex = 0;
   1001 
   1002   if (Private->IsOfferSorted) {
   1003     //
   1004     // Select offer by default policy.
   1005     //
   1006     if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) {
   1007       //
   1008       // 1. DhcpPxe10 offer
   1009       //
   1010       Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1;
   1011 
   1012     } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) {
   1013       //
   1014       // 2. DhcpWfm11a offer
   1015       //
   1016       Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1;
   1017 
   1018     } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
   1019                Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) {
   1020       //
   1021       // 3. DhcpOnly offer and ProxyPxe10 offer.
   1022       //
   1023       Private->SelectIndex     = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
   1024       Private->SelectProxyType = PxeOfferTypeProxyPxe10;
   1025 
   1026     } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
   1027                Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) {
   1028       //
   1029       // 4. DhcpOnly offer and ProxyWfm11a offer.
   1030       //
   1031       Private->SelectIndex     = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
   1032       Private->SelectProxyType = PxeOfferTypeProxyWfm11a;
   1033 
   1034     } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) {
   1035       //
   1036       // 5. DhcpBinl offer.
   1037       //
   1038       Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1;
   1039 
   1040     } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
   1041                Private->OfferCount[PxeOfferTypeProxyBinl] > 0) {
   1042       //
   1043       // 6. DhcpOnly offer and ProxyBinl offer.
   1044       //
   1045       Private->SelectIndex     = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
   1046       Private->SelectProxyType = PxeOfferTypeProxyBinl;
   1047 
   1048     } else {
   1049       //
   1050       // 7. DhcpOnly offer with bootfilename.
   1051       //
   1052       for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) {
   1053         OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index];
   1054         if (Private->OfferBuffer[OfferIndex].Dhcp6.OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL) {
   1055           Private->SelectIndex = OfferIndex + 1;
   1056           break;
   1057         }
   1058       }
   1059     }
   1060   } else {
   1061     //
   1062     // Select offer by received order.
   1063     //
   1064     for (Index = 0; Index < Private->OfferNum; Index++) {
   1065 
   1066       OfferType = Private->OfferBuffer[Index].Dhcp6.OfferType;
   1067 
   1068       if (IS_PROXY_OFFER (OfferType)) {
   1069         //
   1070         // Skip proxy offers
   1071         //
   1072         continue;
   1073       }
   1074 
   1075       if (!Private->IsProxyRecved &&
   1076           OfferType == PxeOfferTypeDhcpOnly &&
   1077           Private->OfferBuffer[Index].Dhcp6.OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) {
   1078         //
   1079         // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
   1080         //
   1081         continue;
   1082       }
   1083 
   1084       Private->SelectIndex = Index + 1;
   1085       break;
   1086     }
   1087   }
   1088 }
   1089 
   1090 
   1091 /**
   1092   Handle the DHCPv6 offer packet.
   1093 
   1094   @param[in]  Private             The pointer to PXEBC_PRIVATE_DATA.
   1095 
   1096   @retval     EFI_SUCCESS         Handled the DHCPv6 offer packet successfully.
   1097   @retval     EFI_NO_RESPONSE     No response to the following request packet.
   1098 
   1099 **/
   1100 EFI_STATUS
   1101 PxeBcHandleDhcp6Offer (
   1102   IN PXEBC_PRIVATE_DATA            *Private
   1103   )
   1104 {
   1105   PXEBC_DHCP6_PACKET_CACHE         *Cache6;
   1106   EFI_STATUS                       Status;
   1107   PXEBC_OFFER_TYPE                 OfferType;
   1108   UINT32                           ProxyIndex;
   1109   UINT32                           SelectIndex;
   1110   UINT32                           Index;
   1111 
   1112   ASSERT (Private->SelectIndex > 0);
   1113   SelectIndex = (UINT32) (Private->SelectIndex - 1);
   1114   ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM);
   1115   Cache6      = &Private->OfferBuffer[SelectIndex].Dhcp6;
   1116   Status      = EFI_SUCCESS;
   1117 
   1118   if (Cache6->OfferType == PxeOfferTypeDhcpBinl) {
   1119     //
   1120     // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
   1121     //
   1122     if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, SelectIndex))) {
   1123       Status = EFI_NO_RESPONSE;
   1124     }
   1125   } else if (Cache6->OfferType == PxeOfferTypeDhcpOnly) {
   1126 
   1127     if (Private->IsProxyRecved) {
   1128       //
   1129       // DhcpOnly offer is selected, so need try to request bootfilename.
   1130       //
   1131       ProxyIndex = 0;
   1132       if (Private->IsOfferSorted) {
   1133         //
   1134         // The proxy offer should be determined if select by default policy.
   1135         // IsOfferSorted means all offers are labeled by OfferIndex.
   1136         //
   1137         ASSERT (Private->OfferCount[Private->SelectProxyType] > 0);
   1138 
   1139         if (Private->SelectProxyType == PxeOfferTypeProxyBinl) {
   1140           //
   1141           // Try all the cached ProxyBinl offer one by one to request bootfilename.
   1142           //
   1143           for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) {
   1144 
   1145             ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index];
   1146             if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private, ProxyIndex))) {
   1147               break;
   1148             }
   1149           }
   1150           if (Index == Private->OfferCount[Private->SelectProxyType]) {
   1151             Status = EFI_NO_RESPONSE;
   1152           }
   1153         } else {
   1154           //
   1155           // For other proxy offers (pxe10 or wfm11a), only one is buffered.
   1156           //
   1157           ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
   1158         }
   1159       } else {
   1160         //
   1161         // The proxy offer should not be determined if select by received order.
   1162         //
   1163         Status = EFI_NO_RESPONSE;
   1164 
   1165         for (Index = 0; Index < Private->OfferNum; Index++) {
   1166 
   1167           OfferType = Private->OfferBuffer[Index].Dhcp6.OfferType;
   1168 
   1169           if (!IS_PROXY_OFFER (OfferType)) {
   1170             //
   1171             // Skip non proxy dhcp offers.
   1172             //
   1173             continue;
   1174           }
   1175 
   1176           if (OfferType == PxeOfferTypeProxyBinl) {
   1177             //
   1178             // Try all the cached ProxyBinl offer one by one to request bootfilename.
   1179             //
   1180             if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, Index))) {
   1181               continue;
   1182             }
   1183           }
   1184 
   1185           Private->SelectProxyType = OfferType;
   1186           ProxyIndex               = Index;
   1187           Status                   = EFI_SUCCESS;
   1188           break;
   1189         }
   1190       }
   1191 
   1192       if (!EFI_ERROR (Status) && Private->SelectProxyType != PxeOfferTypeProxyBinl) {
   1193         //
   1194         // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
   1195         //
   1196         PxeBcCopyDhcp6Proxy (Private, ProxyIndex);
   1197       }
   1198     } else {
   1199       //
   1200       //  Othewise, the bootfilename must be included in DhcpOnly offer.
   1201       //
   1202       ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);
   1203     }
   1204   }
   1205 
   1206   if (!EFI_ERROR (Status)) {
   1207     //
   1208     // All PXE boot information is ready by now.
   1209     //
   1210     PxeBcCopyDhcp6Ack (Private, &Private->DhcpAck.Dhcp6.Packet.Ack, TRUE);
   1211     Private->PxeBc.Mode->DhcpDiscoverValid = TRUE;
   1212   }
   1213 
   1214   return Status;
   1215 }
   1216 
   1217 
   1218 /**
   1219   Unregister the address by Ip6Config protocol.
   1220 
   1221   @param[in]  Private             The pointer to PXEBC_PRIVATE_DATA.
   1222 
   1223 **/
   1224 VOID
   1225 PxeBcUnregisterIp6Address (
   1226   IN PXEBC_PRIVATE_DATA           *Private
   1227   )
   1228 {
   1229   if (Private->Ip6Policy != PXEBC_IP6_POLICY_MAX) {
   1230     //
   1231     // PXE driver change the policy of IP6 driver, it's a chance to recover.
   1232     // Keep the point and there is no enough requirements to do recovery.
   1233     //
   1234   }
   1235 }
   1236 
   1237 /**
   1238   Check whether IP driver could route the message which will be sent to ServerIp address.
   1239 
   1240   This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
   1241   route is found in IP6 route table, the address will be filed in GatewayAddr and return.
   1242 
   1243   @param[in]  Private             The pointer to PXEBC_PRIVATE_DATA.
   1244   @param[in]  TimeOutInSecond     Timeout value in seconds.
   1245   @param[out] GatewayAddr         Pointer to store the gateway IP address.
   1246 
   1247   @retval     EFI_SUCCESS         Found a valid gateway address successfully.
   1248   @retval     EFI_TIMEOUT         The operation is time out.
   1249   @retval     Other               Unexpect error happened.
   1250 
   1251 **/
   1252 EFI_STATUS
   1253 PxeBcCheckRouteTable (
   1254   IN  PXEBC_PRIVATE_DATA            *Private,
   1255   IN  UINTN                         TimeOutInSecond,
   1256   OUT EFI_IPv6_ADDRESS              *GatewayAddr
   1257   )
   1258 {
   1259   EFI_STATUS                       Status;
   1260   EFI_IP6_PROTOCOL                 *Ip6;
   1261   EFI_IP6_MODE_DATA                Ip6ModeData;
   1262   UINTN                            Index;
   1263   EFI_EVENT                        TimeOutEvt;
   1264   UINTN                            RetryCount;
   1265   BOOLEAN                          GatewayIsFound;
   1266 
   1267   ASSERT (GatewayAddr != NULL);
   1268   ASSERT (Private != NULL);
   1269 
   1270   Ip6            = Private->Ip6;
   1271   GatewayIsFound = FALSE;
   1272   RetryCount     = 0;
   1273   TimeOutEvt     = NULL;
   1274   ZeroMem (GatewayAddr, sizeof (EFI_IPv6_ADDRESS));
   1275 
   1276   while (TRUE) {
   1277     Status = Ip6->GetModeData (Ip6, &Ip6ModeData, NULL, NULL);
   1278     if (EFI_ERROR (Status)) {
   1279       goto ON_EXIT;
   1280     }
   1281 
   1282     //
   1283     // Find out the gateway address which can route the message which send to ServerIp.
   1284     //
   1285     for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) {
   1286       if (NetIp6IsNetEqual (&Private->ServerIp.v6, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) {
   1287         IP6_COPY_ADDRESS (GatewayAddr, &Ip6ModeData.RouteTable[Index].Gateway);
   1288         GatewayIsFound = TRUE;
   1289         break;
   1290       }
   1291     }
   1292 
   1293     if (Ip6ModeData.AddressList != NULL) {
   1294       FreePool (Ip6ModeData.AddressList);
   1295     }
   1296     if (Ip6ModeData.GroupTable != NULL) {
   1297       FreePool (Ip6ModeData.GroupTable);
   1298     }
   1299     if (Ip6ModeData.RouteTable != NULL) {
   1300       FreePool (Ip6ModeData.RouteTable);
   1301     }
   1302     if (Ip6ModeData.NeighborCache != NULL) {
   1303       FreePool (Ip6ModeData.NeighborCache);
   1304     }
   1305     if (Ip6ModeData.PrefixTable != NULL) {
   1306       FreePool (Ip6ModeData.PrefixTable);
   1307     }
   1308     if (Ip6ModeData.IcmpTypeList != NULL) {
   1309       FreePool (Ip6ModeData.IcmpTypeList);
   1310     }
   1311 
   1312     if (GatewayIsFound || RetryCount == TimeOutInSecond) {
   1313       break;
   1314     }
   1315 
   1316     RetryCount++;
   1317 
   1318     //
   1319     // Delay 1 second then recheck it again.
   1320     //
   1321     if (TimeOutEvt == NULL) {
   1322       Status = gBS->CreateEvent (
   1323                       EVT_TIMER,
   1324                       TPL_CALLBACK,
   1325                       NULL,
   1326                       NULL,
   1327                       &TimeOutEvt
   1328                       );
   1329       if (EFI_ERROR (Status)) {
   1330         goto ON_EXIT;
   1331       }
   1332     }
   1333 
   1334     Status = gBS->SetTimer (TimeOutEvt, TimerRelative, TICKS_PER_SECOND);
   1335     if (EFI_ERROR (Status)) {
   1336       goto ON_EXIT;
   1337     }
   1338     while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {
   1339       Ip6->Poll (Ip6);
   1340     }
   1341   }
   1342 
   1343 ON_EXIT:
   1344   if (TimeOutEvt != NULL) {
   1345     gBS->CloseEvent (TimeOutEvt);
   1346   }
   1347 
   1348   if (GatewayIsFound) {
   1349     Status = EFI_SUCCESS;
   1350   } else if (RetryCount == TimeOutInSecond) {
   1351     Status = EFI_TIMEOUT;
   1352   }
   1353 
   1354   return Status;
   1355 }
   1356 
   1357 /**
   1358   Register the ready station address and gateway by Ip6Config protocol.
   1359 
   1360   @param[in]  Private             The pointer to PXEBC_PRIVATE_DATA.
   1361   @param[in]  Address             The pointer to the ready address.
   1362 
   1363   @retval     EFI_SUCCESS         Registered the address succesfully.
   1364   @retval     Others              Failed to register the address.
   1365 
   1366 **/
   1367 EFI_STATUS
   1368 PxeBcRegisterIp6Address (
   1369   IN PXEBC_PRIVATE_DATA            *Private,
   1370   IN EFI_IPv6_ADDRESS              *Address
   1371   )
   1372 {
   1373   EFI_IP6_PROTOCOL                 *Ip6;
   1374   EFI_IP6_CONFIG_PROTOCOL          *Ip6Cfg;
   1375   EFI_IP6_CONFIG_POLICY            Policy;
   1376   EFI_IP6_CONFIG_MANUAL_ADDRESS    CfgAddr;
   1377   EFI_IPv6_ADDRESS                 GatewayAddr;
   1378   UINTN                            DataSize;
   1379   EFI_EVENT                        MappedEvt;
   1380   EFI_STATUS                       Status;
   1381   BOOLEAN                          NoGateway;
   1382   EFI_IPv6_ADDRESS                 *Ip6Addr;
   1383   UINTN                            Index;
   1384 
   1385   Status     = EFI_SUCCESS;
   1386   MappedEvt  = NULL;
   1387   Ip6Addr    = NULL;
   1388   DataSize   = sizeof (EFI_IP6_CONFIG_POLICY);
   1389   Ip6Cfg     = Private->Ip6Cfg;
   1390   Ip6        = Private->Ip6;
   1391   NoGateway  = FALSE;
   1392 
   1393   ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
   1394   CopyMem (&CfgAddr.Address, Address, sizeof (EFI_IPv6_ADDRESS));
   1395 
   1396   Status = Ip6->Configure (Ip6, &Private->Ip6CfgData);
   1397   if (EFI_ERROR (Status)) {
   1398     goto ON_EXIT;
   1399   }
   1400 
   1401   //
   1402   // Retrieve the gateway address from IP6 route table.
   1403   //
   1404   Status = PxeBcCheckRouteTable (Private, PXEBC_IP6_ROUTE_TABLE_TIMEOUT, &GatewayAddr);
   1405   if (EFI_ERROR (Status)) {
   1406     NoGateway = TRUE;
   1407   }
   1408 
   1409   //
   1410   // There is no channel between IP6 and PXE driver about address setting,
   1411   // so it has to set the new address by Ip6ConfigProtocol manually.
   1412   //
   1413   Policy = Ip6ConfigPolicyManual;
   1414   Status = Ip6Cfg->SetData (
   1415                      Ip6Cfg,
   1416                      Ip6ConfigDataTypePolicy,
   1417                      sizeof(EFI_IP6_CONFIG_POLICY),
   1418                      &Policy
   1419                      );
   1420   if (EFI_ERROR (Status)) {
   1421     //
   1422     // There is no need to recover later.
   1423     //
   1424     Private->Ip6Policy = PXEBC_IP6_POLICY_MAX;
   1425     goto ON_EXIT;
   1426   }
   1427 
   1428   //
   1429   // Create a notify event to set address flag when DAD if IP6 driver succeeded.
   1430   //
   1431   Status = gBS->CreateEvent (
   1432                   EVT_NOTIFY_SIGNAL,
   1433                   TPL_NOTIFY,
   1434                   PxeBcCommonNotify,
   1435                   &Private->IsAddressOk,
   1436                   &MappedEvt
   1437                   );
   1438   if (EFI_ERROR (Status)) {
   1439     goto ON_EXIT;
   1440   }
   1441 
   1442   Private->IsAddressOk = FALSE;
   1443   Status = Ip6Cfg->RegisterDataNotify (
   1444                      Ip6Cfg,
   1445                      Ip6ConfigDataTypeManualAddress,
   1446                      MappedEvt
   1447                      );
   1448   if (EFI_ERROR(Status)) {
   1449     goto ON_EXIT;
   1450   }
   1451 
   1452   Status = Ip6Cfg->SetData (
   1453                      Ip6Cfg,
   1454                      Ip6ConfigDataTypeManualAddress,
   1455                      sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS),
   1456                      &CfgAddr
   1457                      );
   1458   if (EFI_ERROR(Status) && Status != EFI_NOT_READY) {
   1459     goto ON_EXIT;
   1460   } else if (Status == EFI_NOT_READY) {
   1461     //
   1462     // Poll the network until the asynchronous process is finished.
   1463     //
   1464     while (!Private->IsAddressOk) {
   1465       Ip6->Poll (Ip6);
   1466     }
   1467     //
   1468     // Check whether the IP6 address setting is successed.
   1469     //
   1470     DataSize = 0;
   1471     Status = Ip6Cfg->GetData (
   1472                        Ip6Cfg,
   1473                        Ip6ConfigDataTypeManualAddress,
   1474                        &DataSize,
   1475                        NULL
   1476                        );
   1477     if (Status != EFI_BUFFER_TOO_SMALL || DataSize == 0) {
   1478       Status = EFI_DEVICE_ERROR;
   1479       goto ON_EXIT;
   1480     }
   1481 
   1482     Ip6Addr = AllocatePool (DataSize);
   1483     if (Ip6Addr == NULL) {
   1484       return EFI_OUT_OF_RESOURCES;
   1485     }
   1486     Status = Ip6Cfg->GetData (
   1487                        Ip6Cfg,
   1488                        Ip6ConfigDataTypeManualAddress,
   1489                        &DataSize,
   1490                        (VOID*) Ip6Addr
   1491                        );
   1492     if (EFI_ERROR (Status)) {
   1493       Status = EFI_DEVICE_ERROR;
   1494       goto ON_EXIT;
   1495     }
   1496 
   1497     for (Index = 0; Index < DataSize / sizeof (EFI_IPv6_ADDRESS); Index++) {
   1498       if (CompareMem (Ip6Addr + Index, Address, sizeof (EFI_IPv6_ADDRESS)) == 0) {
   1499         break;
   1500       }
   1501     }
   1502     if (Index == DataSize / sizeof (EFI_IPv6_ADDRESS)) {
   1503       Status = EFI_ABORTED;
   1504       goto ON_EXIT;
   1505     }
   1506   }
   1507 
   1508   //
   1509   // Set the default gateway address back if needed.
   1510   //
   1511   if (!NoGateway && !NetIp6IsUnspecifiedAddr (&GatewayAddr)) {
   1512     Status = Ip6Cfg->SetData (
   1513                        Ip6Cfg,
   1514                        Ip6ConfigDataTypeGateway,
   1515                        sizeof (EFI_IPv6_ADDRESS),
   1516                        &GatewayAddr
   1517                        );
   1518     if (EFI_ERROR (Status)) {
   1519       goto ON_EXIT;
   1520     }
   1521   }
   1522 
   1523 ON_EXIT:
   1524   if (MappedEvt != NULL) {
   1525     Ip6Cfg->UnregisterDataNotify (
   1526               Ip6Cfg,
   1527               Ip6ConfigDataTypeManualAddress,
   1528               MappedEvt
   1529               );
   1530     gBS->CloseEvent (MappedEvt);
   1531   }
   1532   if (Ip6Addr != NULL) {
   1533     FreePool (Ip6Addr);
   1534   }
   1535   return Status;
   1536 }
   1537 
   1538 /**
   1539   Set the IP6 policy to Automatic.
   1540 
   1541   @param[in]  Private             The pointer to PXEBC_PRIVATE_DATA.
   1542 
   1543   @retval     EFI_SUCCESS         Switch the IP policy succesfully.
   1544   @retval     Others              Unexpect error happened.
   1545 
   1546 **/
   1547 EFI_STATUS
   1548 PxeBcSetIp6Policy (
   1549   IN PXEBC_PRIVATE_DATA            *Private
   1550   )
   1551 {
   1552   EFI_IP6_CONFIG_POLICY            Policy;
   1553   EFI_STATUS                       Status;
   1554   EFI_IP6_CONFIG_PROTOCOL          *Ip6Cfg;
   1555   UINTN                            DataSize;
   1556 
   1557   Ip6Cfg      = Private->Ip6Cfg;
   1558   DataSize    = sizeof (EFI_IP6_CONFIG_POLICY);
   1559 
   1560   //
   1561   // Get and store the current policy of IP6 driver.
   1562   //
   1563   Status = Ip6Cfg->GetData (
   1564                      Ip6Cfg,
   1565                      Ip6ConfigDataTypePolicy,
   1566                      &DataSize,
   1567                      &Private->Ip6Policy
   1568                      );
   1569   if (EFI_ERROR (Status)) {
   1570     return Status;
   1571   }
   1572 
   1573   if (Private->Ip6Policy == Ip6ConfigPolicyManual) {
   1574     Policy = Ip6ConfigPolicyAutomatic;
   1575     Status = Ip6Cfg->SetData (
   1576                        Ip6Cfg,
   1577                        Ip6ConfigDataTypePolicy,
   1578                        sizeof(EFI_IP6_CONFIG_POLICY),
   1579                        &Policy
   1580                        );
   1581     if (EFI_ERROR (Status)) {
   1582       //
   1583       // There is no need to recover later.
   1584       //
   1585       Private->Ip6Policy = PXEBC_IP6_POLICY_MAX;
   1586     }
   1587   }
   1588 
   1589   return Status;
   1590 }
   1591 
   1592 /**
   1593   This function will register the station IP address and flush IP instance to start using the new IP address.
   1594 
   1595   @param[in]  Private             The pointer to PXEBC_PRIVATE_DATA.
   1596 
   1597   @retval     EFI_SUCCESS         The new IP address has been configured successfully.
   1598   @retval     Others              Failed to configure the address.
   1599 
   1600 **/
   1601 EFI_STATUS
   1602 PxeBcSetIp6Address (
   1603   IN  PXEBC_PRIVATE_DATA              *Private
   1604   )
   1605 {
   1606   EFI_STATUS                  Status;
   1607   EFI_DHCP6_PROTOCOL          *Dhcp6;
   1608 
   1609   Dhcp6 = Private->Dhcp6;
   1610 
   1611   CopyMem (&Private->StationIp.v6, &Private->TmpStationIp.v6, sizeof (EFI_IPv6_ADDRESS));
   1612   CopyMem (&Private->PxeBc.Mode->StationIp.v6, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));
   1613 
   1614   Status = PxeBcRegisterIp6Address (Private, &Private->StationIp.v6);
   1615   if (EFI_ERROR (Status)) {
   1616     Dhcp6->Stop (Dhcp6);
   1617     return Status;
   1618   }
   1619 
   1620   Status = PxeBcFlushStationIp (Private, &Private->StationIp, NULL);
   1621   if (EFI_ERROR (Status)) {
   1622     PxeBcUnregisterIp6Address (Private);
   1623     Dhcp6->Stop (Dhcp6);
   1624     return Status;
   1625   }
   1626 
   1627   AsciiPrint ("\n  Station IP address is ");
   1628   PxeBcShowIp6Addr (&Private->StationIp.v6);
   1629 
   1630   return EFI_SUCCESS;
   1631 }
   1632 
   1633 /**
   1634   EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
   1635   to intercept events that occurred in the configuration process.
   1636 
   1637   @param[in]  This              The pointer to the EFI DHCPv6 Protocol.
   1638   @param[in]  Context           The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
   1639   @param[in]  CurrentState      The current operational state of the EFI DHCPv Protocol driver.
   1640   @param[in]  Dhcp6Event        The event that occurs in the current state, which usually means a
   1641                                 state transition.
   1642   @param[in]  Packet            The DHCPv6 packet that is going to be sent or was already received.
   1643   @param[out] NewPacket         The packet that is used to replace the Packet above.
   1644 
   1645   @retval EFI_SUCCESS           Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
   1646   @retval EFI_NOT_READY         Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
   1647                                 driver will continue to wait for more packets.
   1648   @retval EFI_ABORTED           Told the EFI DHCPv6 Protocol driver to abort the current process.
   1649 
   1650 **/
   1651 EFI_STATUS
   1652 EFIAPI
   1653 PxeBcDhcp6CallBack (
   1654   IN  EFI_DHCP6_PROTOCOL           *This,
   1655   IN  VOID                         *Context,
   1656   IN  EFI_DHCP6_STATE              CurrentState,
   1657   IN  EFI_DHCP6_EVENT              Dhcp6Event,
   1658   IN  EFI_DHCP6_PACKET             *Packet,
   1659   OUT EFI_DHCP6_PACKET             **NewPacket     OPTIONAL
   1660   )
   1661 {
   1662   PXEBC_PRIVATE_DATA                  *Private;
   1663   EFI_PXE_BASE_CODE_MODE              *Mode;
   1664   EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;
   1665   EFI_DHCP6_PACKET                    *SelectAd;
   1666   EFI_STATUS                          Status;
   1667   BOOLEAN                             Received;
   1668 
   1669   if ((Dhcp6Event != Dhcp6RcvdAdvertise) &&
   1670       (Dhcp6Event != Dhcp6SelectAdvertise) &&
   1671       (Dhcp6Event != Dhcp6SendSolicit) &&
   1672       (Dhcp6Event != Dhcp6SendRequest) &&
   1673       (Dhcp6Event != Dhcp6RcvdReply)) {
   1674     return EFI_SUCCESS;
   1675   }
   1676 
   1677   ASSERT (Packet != NULL);
   1678 
   1679   Private   = (PXEBC_PRIVATE_DATA *) Context;
   1680   Mode      = Private->PxeBc.Mode;
   1681   Callback  = Private->PxeBcCallback;
   1682 
   1683   //
   1684   // Callback to user when any traffic ocurred if has.
   1685   //
   1686   if (Dhcp6Event != Dhcp6SelectAdvertise && Callback != NULL) {
   1687     Received = (BOOLEAN) (Dhcp6Event == Dhcp6RcvdAdvertise || Dhcp6Event == Dhcp6RcvdReply);
   1688     Status = Callback->Callback (
   1689                          Callback,
   1690                          Private->Function,
   1691                          Received,
   1692                          Packet->Length,
   1693                          (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp6
   1694                          );
   1695     if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
   1696       return EFI_ABORTED;
   1697     }
   1698   }
   1699 
   1700   Status = EFI_SUCCESS;
   1701 
   1702   switch (Dhcp6Event) {
   1703 
   1704   case Dhcp6SendSolicit:
   1705     //
   1706     // Record the first Solicate msg time
   1707     //
   1708     if (Private->SolicitTimes == 0) {
   1709       CalcElapsedTime (Private);
   1710       Private->SolicitTimes++;
   1711     }
   1712     //
   1713     // Cache the dhcp discover packet to mode data directly.
   1714     //
   1715     CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp6, Packet->Length);
   1716     break;
   1717 
   1718   case Dhcp6RcvdAdvertise:
   1719     Status = EFI_NOT_READY;
   1720     if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) {
   1721       //
   1722       // Cache the dhcp offers to OfferBuffer[] for select later, and record
   1723       // the OfferIndex and OfferCount.
   1724       //
   1725       PxeBcCacheDhcp6Offer (Private, Packet);
   1726     }
   1727     break;
   1728 
   1729   case Dhcp6SendRequest:
   1730     //
   1731     // Store the request packet as seed packet for discover.
   1732     //
   1733     if (Private->Dhcp6Request != NULL) {
   1734       FreePool (Private->Dhcp6Request);
   1735     }
   1736     Private->Dhcp6Request = AllocateZeroPool (Packet->Size);
   1737     if (Private->Dhcp6Request != NULL) {
   1738       CopyMem (Private->Dhcp6Request, Packet, Packet->Size);
   1739     }
   1740     break;
   1741 
   1742   case Dhcp6SelectAdvertise:
   1743     //
   1744     // Select offer by the default policy or by order, and record the SelectIndex
   1745     // and SelectProxyType.
   1746     //
   1747     PxeBcSelectDhcp6Offer (Private);
   1748 
   1749     if (Private->SelectIndex == 0) {
   1750       Status = EFI_ABORTED;
   1751     } else {
   1752       ASSERT (NewPacket != NULL);
   1753       SelectAd   = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer;
   1754       *NewPacket = AllocateZeroPool (SelectAd->Size);
   1755       ASSERT (*NewPacket != NULL);
   1756       CopyMem (*NewPacket, SelectAd, SelectAd->Size);
   1757     }
   1758     break;
   1759 
   1760   case Dhcp6RcvdReply:
   1761     //
   1762     // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
   1763     // without verification.
   1764     //
   1765     ASSERT (Private->SelectIndex != 0);
   1766     PxeBcCopyDhcp6Ack (Private, Packet, FALSE);
   1767     break;
   1768 
   1769   default:
   1770     ASSERT (0);
   1771   }
   1772 
   1773   return Status;
   1774 }
   1775 
   1776 
   1777 /**
   1778   Build and send out the request packet for the bootfile, and parse the reply.
   1779 
   1780   @param[in]  Private               The pointer to PxeBc private data.
   1781   @param[in]  Type                  PxeBc option boot item type.
   1782   @param[in]  Layer                 The pointer to option boot item layer.
   1783   @param[in]  UseBis                Use BIS or not.
   1784   @param[in]  DestIp                The pointer to the server address.
   1785 
   1786   @retval     EFI_SUCCESS           Successfully discovered the boot file.
   1787   @retval     EFI_OUT_OF_RESOURCES  Failed to allocate resources.
   1788   @retval     EFI_NOT_FOUND         Can't get the PXE reply packet.
   1789   @retval     Others                Failed to discover the boot file.
   1790 
   1791 **/
   1792 EFI_STATUS
   1793 PxeBcDhcp6Discover (
   1794   IN  PXEBC_PRIVATE_DATA              *Private,
   1795   IN  UINT16                          Type,
   1796   IN  UINT16                          *Layer,
   1797   IN  BOOLEAN                         UseBis,
   1798   IN  EFI_IP_ADDRESS                  *DestIp
   1799   )
   1800 {
   1801   EFI_PXE_BASE_CODE_UDP_PORT          SrcPort;
   1802   EFI_PXE_BASE_CODE_UDP_PORT          DestPort;
   1803   EFI_PXE_BASE_CODE_MODE              *Mode;
   1804   EFI_PXE_BASE_CODE_PROTOCOL          *PxeBc;
   1805   EFI_PXE_BASE_CODE_DHCPV6_PACKET     *Discover;
   1806   UINTN                               DiscoverLen;
   1807   EFI_DHCP6_PACKET                    *Request;
   1808   UINTN                               RequestLen;
   1809   EFI_DHCP6_PACKET                    *Reply;
   1810   UINT8                               *RequestOpt;
   1811   UINT8                               *DiscoverOpt;
   1812   UINTN                               ReadSize;
   1813   UINT16                              OpCode;
   1814   UINT16                              OpLen;
   1815   UINT32                              Xid;
   1816   EFI_STATUS                          Status;
   1817 
   1818   PxeBc       = &Private->PxeBc;
   1819   Mode        = PxeBc->Mode;
   1820   Request     = Private->Dhcp6Request;
   1821   SrcPort     = PXEBC_BS_DISCOVER_PORT;
   1822   DestPort    = PXEBC_BS_DISCOVER_PORT;
   1823 
   1824   if (!UseBis && Layer != NULL) {
   1825     *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;
   1826   }
   1827 
   1828   if (Request == NULL) {
   1829     return EFI_DEVICE_ERROR;
   1830   }
   1831 
   1832   Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET));
   1833   if (Discover == NULL) {
   1834     return EFI_OUT_OF_RESOURCES;
   1835   }
   1836 
   1837   //
   1838   // Build the discover packet by the cached request packet before.
   1839   //
   1840   Xid                     = NET_RANDOM (NetRandomInitSeed ());
   1841   Discover->TransactionId = HTONL (Xid);
   1842   Discover->MessageType   = Request->Dhcp6.Header.MessageType;
   1843   RequestOpt              = Request->Dhcp6.Option;
   1844   DiscoverOpt             = Discover->DhcpOptions;
   1845   DiscoverLen             = sizeof (EFI_DHCP6_HEADER);
   1846   RequestLen              = DiscoverLen;
   1847 
   1848   while (RequestLen < Request->Length) {
   1849     OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode);
   1850     OpLen  = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpLen);
   1851     if (OpCode != EFI_DHCP6_IA_TYPE_NA &&
   1852         OpCode != EFI_DHCP6_IA_TYPE_TA) {
   1853       //
   1854       // Copy all the options except IA option.
   1855       //
   1856       CopyMem (DiscoverOpt, RequestOpt, OpLen + 4);
   1857       DiscoverOpt += (OpLen + 4);
   1858       DiscoverLen += (OpLen + 4);
   1859     }
   1860     RequestOpt += (OpLen + 4);
   1861     RequestLen += (OpLen + 4);
   1862   }
   1863 
   1864   Status = PxeBc->UdpWrite (
   1865                     PxeBc,
   1866                     0,
   1867                     &Private->ServerIp,
   1868                     &DestPort,
   1869                     NULL,
   1870                     &Private->StationIp,
   1871                     &SrcPort,
   1872                     NULL,
   1873                     NULL,
   1874                     &DiscoverLen,
   1875                     (VOID *) Discover
   1876                     );
   1877   if (EFI_ERROR (Status)) {
   1878     return Status;
   1879   }
   1880 
   1881   //
   1882   // Cache the right PXE reply packet here, set valid flag later.
   1883   // Especially for PXE discover packet, store it into mode data here.
   1884   //
   1885   if (Private->IsDoDiscover) {
   1886     CopyMem (&Mode->PxeDiscover.Dhcpv6, Discover, DiscoverLen);
   1887     Reply = &Private->PxeReply.Dhcp6.Packet.Ack;
   1888   } else {
   1889     Reply = &Private->ProxyOffer.Dhcp6.Packet.Offer;
   1890   }
   1891   ReadSize = (UINTN) Reply->Size;
   1892 
   1893   //
   1894   // Start Udp6Read instance
   1895   //
   1896   Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);
   1897   if (EFI_ERROR (Status)) {
   1898     return Status;
   1899   }
   1900 
   1901   Status = PxeBc->UdpRead (
   1902                     PxeBc,
   1903                     EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP,
   1904                     NULL,
   1905                     &SrcPort,
   1906                     &Private->ServerIp,
   1907                     &DestPort,
   1908                     NULL,
   1909                     NULL,
   1910                     &ReadSize,
   1911                     (VOID *) &Reply->Dhcp6
   1912                     );
   1913   //
   1914   // Stop Udp6Read instance
   1915   //
   1916   Private->Udp6Read->Configure (Private->Udp6Read, NULL);
   1917   if (EFI_ERROR (Status)) {
   1918     return Status;
   1919   }
   1920 
   1921   return EFI_SUCCESS;
   1922 }
   1923 
   1924 
   1925 /**
   1926   Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
   1927 
   1928   @param[in]  Private           The pointer to PxeBc private data.
   1929   @param[in]  Dhcp6             The pointer to the EFI_DHCP6_PROTOCOL
   1930 
   1931   @retval EFI_SUCCESS           The S.A.R.R. process successfully finished.
   1932   @retval Others                Failed to finish the S.A.R.R. process.
   1933 
   1934 **/
   1935 EFI_STATUS
   1936 PxeBcDhcp6Sarr (
   1937   IN PXEBC_PRIVATE_DATA            *Private,
   1938   IN EFI_DHCP6_PROTOCOL            *Dhcp6
   1939   )
   1940 {
   1941   EFI_PXE_BASE_CODE_MODE           *PxeMode;
   1942   EFI_DHCP6_CONFIG_DATA            Config;
   1943   EFI_DHCP6_MODE_DATA              Mode;
   1944   EFI_DHCP6_RETRANSMISSION         *Retransmit;
   1945   EFI_DHCP6_PACKET_OPTION          *OptList[PXEBC_DHCP6_OPTION_MAX_NUM];
   1946   UINT8                            Buffer[PXEBC_DHCP6_OPTION_MAX_SIZE];
   1947   UINT32                           OptCount;
   1948   EFI_STATUS                       Status;
   1949   EFI_IP6_CONFIG_PROTOCOL          *Ip6Cfg;
   1950   EFI_STATUS                       TimerStatus;
   1951   EFI_EVENT                        Timer;
   1952   UINT64                           GetMappingTimeOut;
   1953   UINTN                            DataSize;
   1954   EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS    DadXmits;
   1955 
   1956   Status     = EFI_SUCCESS;
   1957   PxeMode    = Private->PxeBc.Mode;
   1958   Ip6Cfg     = Private->Ip6Cfg;
   1959   Timer      = NULL;
   1960 
   1961   //
   1962   // Build option list for the request packet.
   1963   //
   1964   OptCount   = PxeBcBuildDhcp6Options (Private, OptList, Buffer);
   1965   ASSERT (OptCount> 0);
   1966 
   1967   Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION));
   1968   if (Retransmit == NULL) {
   1969     return EFI_OUT_OF_RESOURCES;
   1970   }
   1971 
   1972   ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA));
   1973   ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA));
   1974 
   1975   Config.OptionCount           = OptCount;
   1976   Config.OptionList            = OptList;
   1977   Config.Dhcp6Callback         = PxeBcDhcp6CallBack;
   1978   Config.CallbackContext       = Private;
   1979   Config.IaInfoEvent           = NULL;
   1980   Config.RapidCommit           = FALSE;
   1981   Config.ReconfigureAccept     = FALSE;
   1982   Config.IaDescriptor.IaId     = Private->IaId;
   1983   Config.IaDescriptor.Type     = EFI_DHCP6_IA_TYPE_NA;
   1984   Config.SolicitRetransmission = Retransmit;
   1985   Retransmit->Irt              = 4;
   1986   Retransmit->Mrc              = 4;
   1987   Retransmit->Mrt              = 32;
   1988   Retransmit->Mrd              = 60;
   1989 
   1990   //
   1991   // Configure the DHCPv6 instance for PXE boot.
   1992   //
   1993   Status = Dhcp6->Configure (Dhcp6, &Config);
   1994   FreePool (Retransmit);
   1995   if (EFI_ERROR (Status)) {
   1996     return Status;
   1997   }
   1998 
   1999   //
   2000   // Initialize the record fields for DHCPv6 offer in private data.
   2001   //
   2002   Private->IsProxyRecved = FALSE;
   2003   Private->OfferNum      = 0;
   2004   Private->SelectIndex   = 0;
   2005   ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
   2006   ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
   2007 
   2008 
   2009   //
   2010   // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
   2011   //
   2012   Status = Dhcp6->Start (Dhcp6);
   2013   if (Status == EFI_NO_MAPPING) {
   2014     //
   2015     // IP6 Linklocal address is not available for use, so stop current Dhcp process
   2016     // and wait for duplicate address detection to finish.
   2017     //
   2018     Dhcp6->Stop (Dhcp6);
   2019 
   2020     //
   2021     // Get Duplicate Address Detection Transmits count.
   2022     //
   2023     DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);
   2024     Status = Ip6Cfg->GetData (
   2025                        Ip6Cfg,
   2026                        Ip6ConfigDataTypeDupAddrDetectTransmits,
   2027                        &DataSize,
   2028                        &DadXmits
   2029                        );
   2030     if (EFI_ERROR (Status)) {
   2031       Dhcp6->Configure (Dhcp6, NULL);
   2032       return Status;
   2033     }
   2034 
   2035     Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
   2036     if (EFI_ERROR (Status)) {
   2037       Dhcp6->Configure (Dhcp6, NULL);
   2038       return Status;
   2039     }
   2040 
   2041     GetMappingTimeOut = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + PXEBC_DAD_ADDITIONAL_DELAY;
   2042     Status = gBS->SetTimer (Timer, TimerRelative, GetMappingTimeOut);
   2043     if (EFI_ERROR (Status)) {
   2044       gBS->CloseEvent (Timer);
   2045       Dhcp6->Configure (Dhcp6, NULL);
   2046       return Status;
   2047     }
   2048 
   2049     do {
   2050 
   2051       TimerStatus = gBS->CheckEvent (Timer);
   2052       if (!EFI_ERROR (TimerStatus)) {
   2053         Status = Dhcp6->Start (Dhcp6);
   2054       }
   2055     } while (TimerStatus == EFI_NOT_READY);
   2056 
   2057     gBS->CloseEvent (Timer);
   2058   }
   2059   if (EFI_ERROR (Status)) {
   2060     if (Status == EFI_ICMP_ERROR) {
   2061       PxeMode->IcmpErrorReceived = TRUE;
   2062     }
   2063     Dhcp6->Configure (Dhcp6, NULL);
   2064     return Status;
   2065   }
   2066 
   2067   //
   2068   // Get the acquired IPv6 address and store them.
   2069   //
   2070   Status = Dhcp6->GetModeData (Dhcp6, &Mode, NULL);
   2071   if (EFI_ERROR (Status)) {
   2072     Dhcp6->Stop (Dhcp6);
   2073     return Status;
   2074   }
   2075 
   2076   ASSERT (Mode.Ia->State == Dhcp6Bound);
   2077   //
   2078   // DHCP6 doesn't have an option to specify the router address on the subnet, the only way to get the
   2079   // router address in IP6 is the router discovery mechanism (the RS and RA, which only be handled when
   2080   // the IP policy is Automatic). So we just hold the station IP address here and leave the IP policy as
   2081   // Automatic, until we get the server IP address. This could let IP6 driver finish the router discovery
   2082   // to find a valid router address.
   2083   //
   2084   CopyMem (&Private->TmpStationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS));
   2085 
   2086   //
   2087   // Check the selected offer whether BINL retry is needed.
   2088   //
   2089   Status = PxeBcHandleDhcp6Offer (Private);
   2090   if (EFI_ERROR (Status)) {
   2091     Dhcp6->Stop (Dhcp6);
   2092     return Status;
   2093   }
   2094 
   2095   return EFI_SUCCESS;
   2096 }
   2097