Home | History | Annotate | Download | only in UefiPxeBcDxe
      1 /** @file
      2   Functions implementation related with DHCPv4 for UefiPxeBc Driver.
      3 
      4   Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php.
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "PxeBcImpl.h"
     17 
     18 //
     19 // This is a map from the interested DHCP4 option tags' index to the tag value.
     20 //
     21 UINT8 mInterestedDhcp4Tags[PXEBC_DHCP4_TAG_INDEX_MAX] = {
     22   PXEBC_DHCP4_TAG_BOOTFILE_LEN,
     23   PXEBC_DHCP4_TAG_VENDOR,
     24   PXEBC_DHCP4_TAG_OVERLOAD,
     25   PXEBC_DHCP4_TAG_MSG_TYPE,
     26   PXEBC_DHCP4_TAG_SERVER_ID,
     27   PXEBC_DHCP4_TAG_CLASS_ID,
     28   PXEBC_DHCP4_TAG_BOOTFILE
     29 };
     30 
     31 //
     32 // There are 4 times retries with the value of 4, 8, 16 and 32, refers to PXE2.1 spec.
     33 //
     34 UINT32 mPxeDhcpTimeout[4] = {4, 8, 16, 32};
     35 
     36 
     37 /**
     38   Parse a certain dhcp4 option by OptTag in Buffer, and return with start pointer.
     39 
     40   @param[in]  Buffer              Pointer to the option buffer.
     41   @param[in]  Length              Length of the option buffer.
     42   @param[in]  OptTag              Tag of the required option.
     43 
     44   @retval     NULL                Failed to find the required option.
     45   @retval     Others              The position of the required option.
     46 
     47 **/
     48 EFI_DHCP4_PACKET_OPTION *
     49 PxeBcParseDhcp4Options (
     50   IN UINT8                      *Buffer,
     51   IN UINT32                     Length,
     52   IN UINT8                      OptTag
     53   )
     54 {
     55   EFI_DHCP4_PACKET_OPTION       *Option;
     56   UINT32                        Offset;
     57 
     58   Option  = (EFI_DHCP4_PACKET_OPTION *) Buffer;
     59   Offset  = 0;
     60 
     61   while (Offset < Length && Option->OpCode != PXEBC_DHCP4_TAG_EOP) {
     62 
     63     if (Option->OpCode == OptTag) {
     64       //
     65       // Found the required option.
     66       //
     67       return Option;
     68     }
     69 
     70     //
     71     // Skip the current option to the next.
     72     //
     73     if (Option->OpCode == PXEBC_DHCP4_TAG_PAD) {
     74       Offset++;
     75     } else {
     76       Offset += Option->Length + 2;
     77     }
     78 
     79     Option = (EFI_DHCP4_PACKET_OPTION *) (Buffer + Offset);
     80   }
     81 
     82   return NULL;
     83 }
     84 
     85 
     86 /**
     87   Parse the PXE vender options and extract the information from them.
     88 
     89   @param[in]  Dhcp4Option        Pointer to vendor options in buffer.
     90   @param[in]  VendorOption       Pointer to structure to store information in vendor options.
     91 
     92 **/
     93 VOID
     94 PxeBcParseVendorOptions (
     95   IN EFI_DHCP4_PACKET_OPTION    *Dhcp4Option,
     96   IN PXEBC_VENDOR_OPTION        *VendorOption
     97   )
     98 {
     99   UINT32                        *BitMap;
    100   UINT8                         VendorOptionLen;
    101   EFI_DHCP4_PACKET_OPTION       *PxeOption;
    102   UINT8                         Offset;
    103 
    104   BitMap          = VendorOption->BitMap;
    105   VendorOptionLen = Dhcp4Option->Length;
    106   PxeOption       = (EFI_DHCP4_PACKET_OPTION *) &Dhcp4Option->Data[0];
    107   Offset          = 0;
    108 
    109   ASSERT (PxeOption != NULL);
    110 
    111   while ((Offset < VendorOptionLen) && (PxeOption->OpCode != PXEBC_DHCP4_TAG_EOP)) {
    112     //
    113     // Parse all the interesting PXE vendor options one by one.
    114     //
    115     switch (PxeOption->OpCode) {
    116 
    117     case PXEBC_VENDOR_TAG_MTFTP_IP:
    118 
    119       CopyMem (&VendorOption->MtftpIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
    120       break;
    121 
    122     case PXEBC_VENDOR_TAG_MTFTP_CPORT:
    123 
    124       CopyMem (&VendorOption->MtftpCPort, PxeOption->Data, sizeof (VendorOption->MtftpCPort));
    125       break;
    126 
    127     case PXEBC_VENDOR_TAG_MTFTP_SPORT:
    128 
    129       CopyMem (&VendorOption->MtftpSPort, PxeOption->Data, sizeof (VendorOption->MtftpSPort));
    130       break;
    131 
    132     case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT:
    133 
    134       VendorOption->MtftpTimeout = *PxeOption->Data;
    135       break;
    136 
    137     case PXEBC_VENDOR_TAG_MTFTP_DELAY:
    138 
    139       VendorOption->MtftpDelay = *PxeOption->Data;
    140       break;
    141 
    142     case PXEBC_VENDOR_TAG_DISCOVER_CTRL:
    143 
    144       VendorOption->DiscoverCtrl = *PxeOption->Data;
    145       break;
    146 
    147     case PXEBC_VENDOR_TAG_DISCOVER_MCAST:
    148 
    149       CopyMem (&VendorOption->DiscoverMcastIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
    150       break;
    151 
    152     case PXEBC_VENDOR_TAG_BOOT_SERVERS:
    153 
    154       VendorOption->BootSvrLen  = PxeOption->Length;
    155       VendorOption->BootSvr     = (PXEBC_BOOT_SVR_ENTRY *) PxeOption->Data;
    156       break;
    157 
    158     case PXEBC_VENDOR_TAG_BOOT_MENU:
    159 
    160       VendorOption->BootMenuLen = PxeOption->Length;
    161       VendorOption->BootMenu    = (PXEBC_BOOT_MENU_ENTRY *) PxeOption->Data;
    162       break;
    163 
    164     case PXEBC_VENDOR_TAG_MENU_PROMPT:
    165 
    166       VendorOption->MenuPromptLen = PxeOption->Length;
    167       VendorOption->MenuPrompt    = (PXEBC_MENU_PROMPT *) PxeOption->Data;
    168       break;
    169 
    170     case PXEBC_VENDOR_TAG_MCAST_ALLOC:
    171 
    172       CopyMem (&VendorOption->McastIpBase, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
    173       CopyMem (&VendorOption->McastIpBlock, PxeOption->Data + 4, sizeof (VendorOption->McastIpBlock));
    174       CopyMem (&VendorOption->McastIpRange, PxeOption->Data + 6, sizeof (VendorOption->McastIpRange));
    175       break;
    176 
    177     case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES:
    178 
    179       VendorOption->CredTypeLen = PxeOption->Length;
    180       VendorOption->CredType    = (UINT32 *) PxeOption->Data;
    181       break;
    182 
    183     case PXEBC_VENDOR_TAG_BOOT_ITEM:
    184 
    185       CopyMem (&VendorOption->BootSrvType, PxeOption->Data, sizeof (VendorOption->BootSrvType));
    186       CopyMem (&VendorOption->BootSrvLayer, PxeOption->Data + 2, sizeof (VendorOption->BootSrvLayer));
    187       break;
    188 
    189     default:
    190       //
    191       // Not interesting PXE vendor options.
    192       //
    193       break;
    194     }
    195 
    196     //
    197     // Set the bit map for the special PXE options.
    198     //
    199     SET_VENDOR_OPTION_BIT_MAP (BitMap, PxeOption->OpCode);
    200 
    201     //
    202     // Continue to the next option.
    203     //
    204     if (PxeOption->OpCode == PXEBC_DHCP4_TAG_PAD) {
    205       Offset++;
    206     } else {
    207       Offset = (UINT8) (Offset + PxeOption->Length + 2);
    208     }
    209 
    210     PxeOption = (EFI_DHCP4_PACKET_OPTION *) (Dhcp4Option->Data + Offset);
    211   }
    212 }
    213 
    214 
    215 /**
    216   Build the options buffer for the DHCPv4 request packet.
    217 
    218   @param[in]  Private             Pointer to PxeBc private data.
    219   @param[out] OptList             Pointer to the option pointer array.
    220   @param[in]  Buffer              Pointer to the buffer to contain the option list.
    221   @param[in]  NeedMsgType         If TRUE, it is necessary to include the Msg type option.
    222                                   Otherwise, it is not necessary.
    223 
    224   @return     Index               The count of the built-in options.
    225 
    226 **/
    227 UINT32
    228 PxeBcBuildDhcp4Options (
    229   IN  PXEBC_PRIVATE_DATA       *Private,
    230   OUT EFI_DHCP4_PACKET_OPTION  **OptList,
    231   IN  UINT8                    *Buffer,
    232   IN  BOOLEAN                  NeedMsgType
    233   )
    234 {
    235   UINT32                       Index;
    236   PXEBC_DHCP4_OPTION_ENTRY     OptEnt;
    237   UINT16                       Value;
    238 
    239   Index      = 0;
    240   OptList[0] = (EFI_DHCP4_PACKET_OPTION *) Buffer;
    241 
    242   if (NeedMsgType) {
    243     //
    244     // Append message type.
    245     //
    246     OptList[Index]->OpCode  = PXEBC_DHCP4_TAG_MSG_TYPE;
    247     OptList[Index]->Length  = 1;
    248     OptEnt.Mesg             = (PXEBC_DHCP4_OPTION_MESG *) OptList[Index]->Data;
    249     OptEnt.Mesg->Type       = PXEBC_DHCP4_MSG_TYPE_REQUEST;
    250     Index++;
    251     OptList[Index]          = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
    252 
    253     //
    254     // Append max message size.
    255     //
    256     OptList[Index]->OpCode  = PXEBC_DHCP4_TAG_MAXMSG;
    257     OptList[Index]->Length  = (UINT8) sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE);
    258     OptEnt.MaxMesgSize      = (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE *) OptList[Index]->Data;
    259     Value                   = NTOHS (PXEBC_DHCP4_PACKET_MAX_SIZE - 8);
    260     CopyMem (&OptEnt.MaxMesgSize->Size, &Value, sizeof (UINT16));
    261     Index++;
    262     OptList[Index]          = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
    263   }
    264 
    265   //
    266   // Append parameter request list option.
    267   //
    268   OptList[Index]->OpCode    = PXEBC_DHCP4_TAG_PARA_LIST;
    269   OptList[Index]->Length    = 35;
    270   OptEnt.Para               = (PXEBC_DHCP4_OPTION_PARA *) OptList[Index]->Data;
    271   OptEnt.Para->ParaList[0]  = PXEBC_DHCP4_TAG_NETMASK;
    272   OptEnt.Para->ParaList[1]  = PXEBC_DHCP4_TAG_TIME_OFFSET;
    273   OptEnt.Para->ParaList[2]  = PXEBC_DHCP4_TAG_ROUTER;
    274   OptEnt.Para->ParaList[3]  = PXEBC_DHCP4_TAG_TIME_SERVER;
    275   OptEnt.Para->ParaList[4]  = PXEBC_DHCP4_TAG_NAME_SERVER;
    276   OptEnt.Para->ParaList[5]  = PXEBC_DHCP4_TAG_DNS_SERVER;
    277   OptEnt.Para->ParaList[6]  = PXEBC_DHCP4_TAG_HOSTNAME;
    278   OptEnt.Para->ParaList[7]  = PXEBC_DHCP4_TAG_BOOTFILE_LEN;
    279   OptEnt.Para->ParaList[8]  = PXEBC_DHCP4_TAG_DOMAINNAME;
    280   OptEnt.Para->ParaList[9]  = PXEBC_DHCP4_TAG_ROOTPATH;
    281   OptEnt.Para->ParaList[10] = PXEBC_DHCP4_TAG_EXTEND_PATH;
    282   OptEnt.Para->ParaList[11] = PXEBC_DHCP4_TAG_EMTU;
    283   OptEnt.Para->ParaList[12] = PXEBC_DHCP4_TAG_TTL;
    284   OptEnt.Para->ParaList[13] = PXEBC_DHCP4_TAG_BROADCAST;
    285   OptEnt.Para->ParaList[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN;
    286   OptEnt.Para->ParaList[15] = PXEBC_DHCP4_TAG_NIS_SERVER;
    287   OptEnt.Para->ParaList[16] = PXEBC_DHCP4_TAG_NTP_SERVER;
    288   OptEnt.Para->ParaList[17] = PXEBC_DHCP4_TAG_VENDOR;
    289   OptEnt.Para->ParaList[18] = PXEBC_DHCP4_TAG_REQUEST_IP;
    290   OptEnt.Para->ParaList[19] = PXEBC_DHCP4_TAG_LEASE;
    291   OptEnt.Para->ParaList[20] = PXEBC_DHCP4_TAG_SERVER_ID;
    292   OptEnt.Para->ParaList[21] = PXEBC_DHCP4_TAG_T1;
    293   OptEnt.Para->ParaList[22] = PXEBC_DHCP4_TAG_T2;
    294   OptEnt.Para->ParaList[23] = PXEBC_DHCP4_TAG_CLASS_ID;
    295   OptEnt.Para->ParaList[24] = PXEBC_DHCP4_TAG_TFTP;
    296   OptEnt.Para->ParaList[25] = PXEBC_DHCP4_TAG_BOOTFILE;
    297   OptEnt.Para->ParaList[26] = PXEBC_PXE_DHCP4_TAG_UUID;
    298   OptEnt.Para->ParaList[27] = 0x80;
    299   OptEnt.Para->ParaList[28] = 0x81;
    300   OptEnt.Para->ParaList[29] = 0x82;
    301   OptEnt.Para->ParaList[30] = 0x83;
    302   OptEnt.Para->ParaList[31] = 0x84;
    303   OptEnt.Para->ParaList[32] = 0x85;
    304   OptEnt.Para->ParaList[33] = 0x86;
    305   OptEnt.Para->ParaList[34] = 0x87;
    306   Index++;
    307   OptList[Index]            = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
    308 
    309   //
    310   // Append UUID/Guid-based client identifier option
    311   //
    312   OptList[Index]->OpCode  = PXEBC_PXE_DHCP4_TAG_UUID;
    313   OptList[Index]->Length  = (UINT8) sizeof (PXEBC_DHCP4_OPTION_UUID);
    314   OptEnt.Uuid             = (PXEBC_DHCP4_OPTION_UUID *) OptList[Index]->Data;
    315   OptEnt.Uuid->Type       = 0;
    316   Index++;
    317   OptList[Index]          = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
    318 
    319   if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) OptEnt.Uuid->Guid))) {
    320     //
    321     // Zero the Guid to indicate NOT programable if failed to get system Guid.
    322     //
    323     ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));
    324   }
    325 
    326   //
    327   // Append client network device interface option
    328   //
    329   OptList[Index]->OpCode  = PXEBC_PXE_DHCP4_TAG_UNDI;
    330   OptList[Index]->Length  = (UINT8) sizeof (PXEBC_DHCP4_OPTION_UNDI);
    331   OptEnt.Undi             = (PXEBC_DHCP4_OPTION_UNDI *) OptList[Index]->Data;
    332 
    333   if (Private->Nii != NULL) {
    334     OptEnt.Undi->Type     = Private->Nii->Type;
    335     OptEnt.Undi->MajorVer = Private->Nii->MajorVer;
    336     OptEnt.Undi->MinorVer = Private->Nii->MinorVer;
    337   } else {
    338     OptEnt.Undi->Type     = DEFAULT_UNDI_TYPE;
    339     OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;
    340     OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;
    341   }
    342 
    343   Index++;
    344   OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
    345 
    346   //
    347   // Append client system architecture option
    348   //
    349   OptList[Index]->OpCode  = PXEBC_PXE_DHCP4_TAG_ARCH;
    350   OptList[Index]->Length  = (UINT8) sizeof (PXEBC_DHCP4_OPTION_ARCH);
    351   OptEnt.Arch             = (PXEBC_DHCP4_OPTION_ARCH *) OptList[Index]->Data;
    352   Value                   = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE);
    353   CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));
    354   Index++;
    355   OptList[Index]          = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
    356 
    357   //
    358   // Append vendor class identify option
    359   //
    360   OptList[Index]->OpCode  = PXEBC_DHCP4_TAG_CLASS_ID;
    361   OptList[Index]->Length  = (UINT8) sizeof (PXEBC_DHCP4_OPTION_CLID);
    362   OptEnt.Clid             = (PXEBC_DHCP4_OPTION_CLID *) OptList[Index]->Data;
    363   CopyMem (
    364     OptEnt.Clid,
    365     DEFAULT_CLASS_ID_DATA,
    366     sizeof (PXEBC_DHCP4_OPTION_CLID)
    367     );
    368   PxeBcUintnToAscDecWithFormat (
    369     EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE,
    370     OptEnt.Clid->ArchitectureType,
    371     sizeof (OptEnt.Clid->ArchitectureType)
    372     );
    373 
    374   if (Private->Nii != NULL) {
    375     CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));
    376     PxeBcUintnToAscDecWithFormat (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));
    377     PxeBcUintnToAscDecWithFormat (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));
    378   }
    379 
    380   Index++;
    381 
    382   return Index;
    383 }
    384 
    385 
    386 /**
    387   Create a template DHCPv4 packet as a seed.
    388 
    389   @param[out] Seed           Pointer to the seed packet.
    390   @param[in]  Udp4           Pointer to EFI_UDP4_PROTOCOL.
    391 
    392 **/
    393 VOID
    394 PxeBcSeedDhcp4Packet (
    395   OUT EFI_DHCP4_PACKET       *Seed,
    396   IN  EFI_UDP4_PROTOCOL      *Udp4
    397   )
    398 {
    399   EFI_SIMPLE_NETWORK_MODE    Mode;
    400   EFI_DHCP4_HEADER           *Header;
    401 
    402   //
    403   // Get IfType and HwAddressSize from SNP mode data.
    404   //
    405   Udp4->GetModeData (Udp4, NULL, NULL, NULL, &Mode);
    406 
    407   Seed->Size            = sizeof (EFI_DHCP4_PACKET);
    408   Seed->Length          = sizeof (Seed->Dhcp4);
    409   Header                = &Seed->Dhcp4.Header;
    410   ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));
    411   Header->OpCode        = PXEBC_DHCP4_OPCODE_REQUEST;
    412   Header->HwType        = Mode.IfType;
    413   Header->HwAddrLen     = (UINT8) Mode.HwAddressSize;
    414   CopyMem (Header->ClientHwAddr, &Mode.CurrentAddress, Header->HwAddrLen);
    415 
    416   Seed->Dhcp4.Magik     = PXEBC_DHCP4_MAGIC;
    417   Seed->Dhcp4.Option[0] = PXEBC_DHCP4_TAG_EOP;
    418 }
    419 
    420 
    421 /**
    422   Cache the DHCPv4 packet.
    423 
    424   @param[in]  Dst          Pointer to the cache buffer for DHCPv4 packet.
    425   @param[in]  Src          Pointer to the DHCPv4 packet to be cached.
    426 
    427 **/
    428 VOID
    429 PxeBcCacheDhcp4Packet (
    430   IN EFI_DHCP4_PACKET     *Dst,
    431   IN EFI_DHCP4_PACKET     *Src
    432   )
    433 {
    434   ASSERT (Dst->Size >= Src->Length);
    435 
    436   CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length);
    437   Dst->Length = Src->Length;
    438 }
    439 
    440 
    441 /**
    442   Parse the cached DHCPv4 packet, including all the options.
    443 
    444   @param[in]  Cache4           Pointer to cached DHCPv4 packet.
    445 
    446   @retval     EFI_SUCCESS      Parsed the DHCPv4 packet successfully.
    447   @retval     EFI_DEVICE_ERROR Failed to parse and invalid packet.
    448 
    449 **/
    450 EFI_STATUS
    451 PxeBcParseDhcp4Packet (
    452   IN PXEBC_DHCP4_PACKET_CACHE    *Cache4
    453   )
    454 {
    455   EFI_DHCP4_PACKET               *Offer;
    456   EFI_DHCP4_PACKET_OPTION        **Options;
    457   EFI_DHCP4_PACKET_OPTION        *Option;
    458   PXEBC_OFFER_TYPE               OfferType;
    459   UINTN                          Index;
    460   BOOLEAN                        IsProxyOffer;
    461   BOOLEAN                        IsPxeOffer;
    462   UINT8                          *Ptr8;
    463 
    464   IsProxyOffer = FALSE;
    465   IsPxeOffer   = FALSE;
    466 
    467   ZeroMem (Cache4->OptList, sizeof (Cache4->OptList));
    468   ZeroMem (&Cache4->VendorOpt, sizeof (Cache4->VendorOpt));
    469 
    470   Offer   = &Cache4->Packet.Offer;
    471   Options = Cache4->OptList;
    472 
    473   //
    474   // Parse DHCPv4 options in this offer, and store the pointers.
    475   // First, try to parse DHCPv4 options from the DHCP optional parameters field.
    476   //
    477   for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
    478     Options[Index] = PxeBcParseDhcp4Options (
    479                        Offer->Dhcp4.Option,
    480                        GET_OPTION_BUFFER_LEN (Offer),
    481                        mInterestedDhcp4Tags[Index]
    482                        );
    483   }
    484   //
    485   // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132.
    486   // If yes, try to parse options from the BootFileName field, then ServerName field.
    487   //
    488   Option = Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD];
    489   if (Option != NULL) {
    490     if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_FILE) != 0) {
    491       for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
    492         if (Options[Index] == NULL) {
    493           Options[Index] = PxeBcParseDhcp4Options (
    494                              (UINT8 *) Offer->Dhcp4.Header.BootFileName,
    495                              sizeof (Offer->Dhcp4.Header.BootFileName),
    496                              mInterestedDhcp4Tags[Index]
    497                              );
    498         }
    499       }
    500     }
    501     if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_SERVER_NAME) != 0) {
    502       for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
    503         if (Options[Index] == NULL) {
    504           Options[Index] = PxeBcParseDhcp4Options (
    505                              (UINT8 *) Offer->Dhcp4.Header.ServerName,
    506                              sizeof (Offer->Dhcp4.Header.ServerName),
    507                              mInterestedDhcp4Tags[Index]
    508                              );
    509         }
    510       }
    511     }
    512   }
    513 
    514   //
    515   // The offer with zero "yiaddr" is a proxy offer.
    516   //
    517   if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) {
    518     IsProxyOffer = TRUE;
    519   }
    520 
    521   //
    522   // The offer with "PXEClient" is a PXE offer.
    523   //
    524   Option = Options[PXEBC_DHCP4_TAG_INDEX_CLASS_ID];
    525   if ((Option != NULL) && (Option->Length >= 9) &&
    526       (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) {
    527     IsPxeOffer = TRUE;
    528   }
    529 
    530   //
    531   // Parse PXE vendor options in this offer, and store the contents/pointers.
    532   //
    533   Option = Options[PXEBC_DHCP4_TAG_INDEX_VENDOR];
    534   if (IsPxeOffer && Option != NULL) {
    535     PxeBcParseVendorOptions (Option, &Cache4->VendorOpt);
    536   }
    537 
    538   //
    539   // Parse PXE boot file name:
    540   // According to PXE spec, boot file name should be read from DHCP option 67 (bootfile name) if present.
    541   // Otherwise, read from boot file field in DHCP header.
    542   //
    543   if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
    544     //
    545     // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null
    546     // terminated string. So force to append null terminated character at the end of string.
    547     //
    548     Ptr8 =  (UINT8*)&Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data[0];
    549     Ptr8 += Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Length;
    550     if (*(Ptr8 - 1) != '\0') {
    551       *Ptr8 = '\0';
    552     }
    553   } else if (Offer->Dhcp4.Header.BootFileName[0] != 0) {
    554     //
    555     // If the bootfile is not present and bootfilename is present in DHCPv4 packet, just parse it.
    556     // Do not count dhcp option header here, or else will destroy the serverhostname.
    557     //
    558     Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *)
    559                                                 (&Offer->Dhcp4.Header.BootFileName[0] -
    560                                                 OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0]));
    561 
    562   }
    563 
    564   //
    565   // Determine offer type of the DHCPv4 packet.
    566   //
    567   Option = Options[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE];
    568   if (Option == NULL || Option->Data[0] == 0) {
    569     //
    570     // It's a Bootp offer.
    571     //
    572     OfferType = PxeOfferTypeBootp;
    573 
    574     Option    = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE];
    575     if (Option == NULL) {
    576       //
    577       // If the Bootp offer without bootfilename, discard it.
    578       //
    579       return EFI_DEVICE_ERROR;
    580     }
    581   } else {
    582 
    583     if (IS_VALID_DISCOVER_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {
    584       //
    585       // It's a PXE10 offer with PXEClient and discover vendor option.
    586       //
    587       OfferType = IsProxyOffer ? PxeOfferTypeProxyPxe10 : PxeOfferTypeDhcpPxe10;
    588     } else if (IS_VALID_MTFTP_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) {
    589       //
    590       // It's a WFM11a offer with PXEClient and mtftp vendor option.
    591       // But multi-cast download is not supported currently, so discard it.
    592       //
    593       return EFI_DEVICE_ERROR;
    594     } else if (IsPxeOffer) {
    595       //
    596       // It's a BINL offer only with PXEClient.
    597       //
    598       OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl;
    599     } else {
    600       //
    601       // It's a DHCPv4 only offer, which is a pure DHCPv4 offer packet.
    602       //
    603       OfferType = PxeOfferTypeDhcpOnly;
    604     }
    605   }
    606 
    607   Cache4->OfferType = OfferType;
    608 
    609   return EFI_SUCCESS;
    610 }
    611 
    612 
    613 /**
    614   Cache the DHCPv4 ack packet, and parse it on demand.
    615 
    616   @param[in]  Private             Pointer to PxeBc private data.
    617   @param[in]  Ack                 Pointer to the DHCPv4 ack packet.
    618   @param[in]  Verified            If TRUE, parse the ACK packet and store info into mode data.
    619 
    620 **/
    621 VOID
    622 PxeBcCopyDhcp4Ack (
    623   IN PXEBC_PRIVATE_DATA   *Private,
    624   IN EFI_DHCP4_PACKET     *Ack,
    625   IN BOOLEAN              Verified
    626   )
    627 {
    628   EFI_PXE_BASE_CODE_MODE  *Mode;
    629 
    630   Mode = Private->PxeBc.Mode;
    631 
    632   PxeBcCacheDhcp4Packet (&Private->DhcpAck.Dhcp4.Packet.Ack, Ack);
    633 
    634   if (Verified) {
    635     //
    636     // Parse the ack packet and store it into mode data if needed.
    637     //
    638     PxeBcParseDhcp4Packet (&Private->DhcpAck.Dhcp4);
    639     CopyMem (&Mode->DhcpAck.Dhcpv4, &Ack->Dhcp4, Ack->Length);
    640     Mode->DhcpAckReceived = TRUE;
    641   }
    642 }
    643 
    644 
    645 /**
    646   Cache the DHCPv4 proxy offer packet according to the received order.
    647 
    648   @param[in]  Private               Pointer to PxeBc private data.
    649   @param[in]  OfferIndex            The received order of offer packets.
    650 
    651 **/
    652 VOID
    653 PxeBcCopyProxyOffer (
    654   IN PXEBC_PRIVATE_DATA   *Private,
    655   IN UINT32               OfferIndex
    656   )
    657 {
    658   EFI_PXE_BASE_CODE_MODE  *Mode;
    659   EFI_DHCP4_PACKET        *Offer;
    660 
    661   ASSERT (OfferIndex < Private->OfferNum);
    662   ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM);
    663 
    664   Mode  = Private->PxeBc.Mode;
    665   Offer = &Private->OfferBuffer[OfferIndex].Dhcp4.Packet.Offer;
    666 
    667   //
    668   // Cache the proxy offer packet and parse it.
    669   //
    670   PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Offer);
    671   PxeBcParseDhcp4Packet (&Private->ProxyOffer.Dhcp4);
    672 
    673   //
    674   // Store this packet into mode data.
    675   //
    676   CopyMem (&Mode->ProxyOffer.Dhcpv4, &Offer->Dhcp4, Offer->Length);
    677   Mode->ProxyOfferReceived = TRUE;
    678 }
    679 
    680 
    681 /**
    682   Retry to request bootfile name by the BINL offer.
    683 
    684   @param[in]  Private              Pointer to PxeBc private data.
    685   @param[in]  Index                The received order of offer packets.
    686 
    687   @retval     EFI_SUCCESS          Successfully retried to request bootfile name.
    688   @retval     EFI_DEVICE_ERROR     Failed to retry bootfile name.
    689 
    690 **/
    691 EFI_STATUS
    692 PxeBcRetryBinlOffer (
    693   IN PXEBC_PRIVATE_DATA     *Private,
    694   IN UINT32                 Index
    695   )
    696 {
    697   EFI_DHCP4_PACKET          *Offer;
    698   EFI_IP_ADDRESS            ServerIp;
    699   EFI_STATUS                Status;
    700   PXEBC_DHCP4_PACKET_CACHE  *Cache4;
    701   EFI_DHCP4_PACKET          *Reply;
    702 
    703   ASSERT (Index < PXEBC_OFFER_MAX_NUM);
    704   ASSERT (Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpBinl ||
    705           Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeProxyBinl);
    706 
    707   Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
    708 
    709   //
    710   // Prefer to siaddr in header as next server address. If it's zero, then use option 54.
    711   //
    712   if (Offer->Dhcp4.Header.ServerAddr.Addr[0] == 0) {
    713     CopyMem (
    714       &ServerIp.Addr[0],
    715       Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
    716       sizeof (EFI_IPv4_ADDRESS)
    717       );
    718   } else {
    719     CopyMem (
    720       &ServerIp.Addr[0],
    721       &Offer->Dhcp4.Header.ServerAddr,
    722       sizeof (EFI_IPv4_ADDRESS)
    723       );
    724   }
    725 
    726   Private->IsDoDiscover = FALSE;
    727   Cache4                = &Private->ProxyOffer.Dhcp4;
    728   Reply                 = &Cache4->Packet.Offer;
    729 
    730   //
    731   // Send another request packet for bootfile name.
    732   //
    733   Status = PxeBcDhcp4Discover (
    734              Private,
    735              0,
    736              NULL,
    737              FALSE,
    738              &ServerIp,
    739              0,
    740              NULL
    741              );
    742   if (EFI_ERROR (Status)) {
    743     return Status;
    744   }
    745 
    746   //
    747   // Parse the reply for the last request packet.
    748   //
    749   Status = PxeBcParseDhcp4Packet (Cache4);
    750   if (EFI_ERROR (Status)) {
    751     return Status;
    752   }
    753 
    754   if (Cache4->OfferType != PxeOfferTypeProxyPxe10 &&
    755       Cache4->OfferType != PxeOfferTypeProxyWfm11a &&
    756       Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
    757     //
    758     // This BINL ack doesn't have discovery option set or multicast option set
    759     // or bootfile name specified.
    760     //
    761     return EFI_DEVICE_ERROR;
    762   }
    763 
    764   //
    765   // Store the reply into mode data.
    766   //
    767   Private->PxeBc.Mode->ProxyOfferReceived = TRUE;
    768   CopyMem (&Private->PxeBc.Mode->ProxyOffer.Dhcpv4, &Reply->Dhcp4, Reply->Length);
    769 
    770   return EFI_SUCCESS;
    771 }
    772 
    773 
    774 /**
    775   Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount.
    776 
    777   @param[in]  Private               Pointer to PxeBc private data.
    778   @param[in]  RcvdOffer             Pointer to the received offer packet.
    779 
    780 **/
    781 VOID
    782 PxeBcCacheDhcp4Offer (
    783   IN PXEBC_PRIVATE_DATA     *Private,
    784   IN EFI_DHCP4_PACKET       *RcvdOffer
    785   )
    786 {
    787   PXEBC_DHCP4_PACKET_CACHE  *Cache4;
    788   EFI_DHCP4_PACKET          *Offer;
    789   PXEBC_OFFER_TYPE          OfferType;
    790 
    791   ASSERT (Private->OfferNum < PXEBC_OFFER_MAX_NUM);
    792   Cache4 = &Private->OfferBuffer[Private->OfferNum].Dhcp4;
    793   Offer  = &Cache4->Packet.Offer;
    794 
    795   //
    796   // Cache the content of DHCPv4 packet firstly.
    797   //
    798   PxeBcCacheDhcp4Packet (Offer, RcvdOffer);
    799 
    800   //
    801   // Validate the DHCPv4 packet, and parse the options and offer type.
    802   //
    803   if (EFI_ERROR (PxeBcParseDhcp4Packet (Cache4))) {
    804     return;
    805   }
    806 
    807   //
    808   // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
    809   //
    810   OfferType = Cache4->OfferType;
    811   ASSERT (OfferType < PxeOfferTypeMax);
    812 
    813   if (OfferType == PxeOfferTypeBootp) {
    814     //
    815     // It's a Bootp offer, only cache the first one, and discard the others.
    816     //
    817     if (Private->OfferCount[OfferType] == 0) {
    818       Private->OfferIndex[OfferType][0] = Private->OfferNum;
    819       Private->OfferCount[OfferType]    = 1;
    820     } else {
    821       return;
    822     }
    823   } else {
    824     ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM);
    825     if (IS_PROXY_DHCP_OFFER (Offer)) {
    826       //
    827       // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
    828       //
    829       Private->IsProxyRecved = TRUE;
    830 
    831       if (OfferType == PxeOfferTypeProxyBinl) {
    832         //
    833         // Cache all proxy BINL offers.
    834         //
    835         Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
    836         Private->OfferCount[OfferType]++;
    837       } else if (Private->OfferCount[OfferType] > 0) {
    838         //
    839         // Only cache the first PXE10/WFM11a offer, and discard the others.
    840         //
    841         Private->OfferIndex[OfferType][0] = Private->OfferNum;
    842         Private->OfferCount[OfferType]    = 1;
    843       } else {
    844         return ;
    845       }
    846     } else {
    847       //
    848       // It's a DHCPv4 offer with yiaddr, and cache them all.
    849       //
    850       Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
    851       Private->OfferCount[OfferType]++;
    852     }
    853   }
    854 
    855   Private->OfferNum++;
    856 }
    857 
    858 
    859 /**
    860   Select an DHCPv4 offer, and record SelectIndex and SelectProxyType.
    861 
    862   @param[in]  Private             Pointer to PxeBc private data.
    863 
    864 **/
    865 VOID
    866 PxeBcSelectDhcp4Offer (
    867   IN PXEBC_PRIVATE_DATA       *Private
    868   )
    869 {
    870   UINT32                      Index;
    871   UINT32                      OfferIndex;
    872   EFI_DHCP4_PACKET            *Offer;
    873 
    874   Private->SelectIndex = 0;
    875 
    876   if (Private->IsOfferSorted) {
    877     //
    878     // Select offer by default policy.
    879     //
    880     if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) {
    881       //
    882       // 1. DhcpPxe10 offer
    883       //
    884       Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1;
    885 
    886     } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) {
    887       //
    888       // 2. DhcpWfm11a offer
    889       //
    890       Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1;
    891 
    892     } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
    893                Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) {
    894       //
    895       // 3. DhcpOnly offer and ProxyPxe10 offer.
    896       //
    897       Private->SelectIndex     = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
    898       Private->SelectProxyType = PxeOfferTypeProxyPxe10;
    899 
    900     } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
    901                Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) {
    902       //
    903       // 4. DhcpOnly offer and ProxyWfm11a offer.
    904       //
    905       Private->SelectIndex     = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
    906       Private->SelectProxyType = PxeOfferTypeProxyWfm11a;
    907 
    908     } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) {
    909       //
    910       // 5. DhcpBinl offer.
    911       //
    912       Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1;
    913 
    914     } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
    915                Private->OfferCount[PxeOfferTypeProxyBinl] > 0) {
    916       //
    917       // 6. DhcpOnly offer and ProxyBinl offer.
    918       //
    919       Private->SelectIndex     = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
    920       Private->SelectProxyType = PxeOfferTypeProxyBinl;
    921 
    922     } else {
    923       //
    924       // 7. DhcpOnly offer with bootfilename.
    925       //
    926       for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) {
    927         OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index];
    928         if (Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
    929           Private->SelectIndex = OfferIndex + 1;
    930           break;
    931         }
    932       }
    933       //
    934       // 8. Bootp offer with bootfilename.
    935       //
    936       OfferIndex = Private->OfferIndex[PxeOfferTypeBootp][0];
    937       if (Private->SelectIndex == 0 &&
    938           Private->OfferCount[PxeOfferTypeBootp] > 0 &&
    939           Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
    940         Private->SelectIndex = OfferIndex + 1;
    941       }
    942     }
    943   } else {
    944     //
    945     // Select offer by received order.
    946     //
    947     for (Index = 0; Index < Private->OfferNum; Index++) {
    948 
    949       Offer = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
    950 
    951       if (IS_PROXY_DHCP_OFFER (Offer)) {
    952         //
    953         // Skip proxy offers
    954         //
    955         continue;
    956       }
    957 
    958       if (!Private->IsProxyRecved &&
    959           Private->OfferBuffer[Index].Dhcp4.OfferType == PxeOfferTypeDhcpOnly &&
    960           Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
    961         //
    962         // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
    963         //
    964         continue;
    965       }
    966 
    967       //
    968       // Record the index of the select offer.
    969       //
    970       Private->SelectIndex = Index + 1;
    971       break;
    972     }
    973   }
    974 }
    975 
    976 
    977 /**
    978   Handle the DHCPv4 offer packet.
    979 
    980   @param[in]  Private             Pointer to PxeBc private data.
    981 
    982   @retval     EFI_SUCCESS         Handled the DHCPv4 offer packet successfully.
    983   @retval     EFI_NO_RESPONSE     No response to the following request packet.
    984   @retval     EFI_NOT_FOUND       No boot filename received.
    985 
    986 **/
    987 EFI_STATUS
    988 PxeBcHandleDhcp4Offer (
    989   IN PXEBC_PRIVATE_DATA     *Private
    990   )
    991 {
    992   PXEBC_DHCP4_PACKET_CACHE  *Cache4;
    993   EFI_DHCP4_PACKET_OPTION   **Options;
    994   UINT32                    Index;
    995   EFI_DHCP4_PACKET          *Offer;
    996   PXEBC_OFFER_TYPE          OfferType;
    997   UINT32                    ProxyIndex;
    998   UINT32                    SelectIndex;
    999   EFI_STATUS                Status;
   1000   EFI_PXE_BASE_CODE_MODE    *Mode;
   1001   EFI_DHCP4_PACKET          *Ack;
   1002 
   1003   ASSERT (Private->SelectIndex > 0);
   1004   SelectIndex = (UINT32) (Private->SelectIndex - 1);
   1005   ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM);
   1006   Cache4      = &Private->OfferBuffer[SelectIndex].Dhcp4;
   1007   Options     = Cache4->OptList;
   1008   Status      = EFI_SUCCESS;
   1009 
   1010   if (Cache4->OfferType == PxeOfferTypeDhcpBinl) {
   1011     //
   1012     // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
   1013     //
   1014     if (EFI_ERROR (PxeBcRetryBinlOffer (Private, SelectIndex))) {
   1015       Status = EFI_NO_RESPONSE;
   1016     }
   1017   } else if (Cache4->OfferType == PxeOfferTypeDhcpOnly) {
   1018 
   1019     if (Private->IsProxyRecved) {
   1020       //
   1021       // DhcpOnly offer is selected, so need try to request bootfile name.
   1022       //
   1023       ProxyIndex = 0;
   1024       if (Private->IsOfferSorted) {
   1025         //
   1026         // The proxy offer should be determined if select by default policy.
   1027         // IsOfferSorted means all offers are labeled by OfferIndex.
   1028         //
   1029         ASSERT (Private->SelectProxyType < PxeOfferTypeMax);
   1030         ASSERT (Private->OfferCount[Private->SelectProxyType] > 0);
   1031 
   1032         if (Private->SelectProxyType == PxeOfferTypeProxyBinl) {
   1033           //
   1034           // Try all the cached ProxyBinl offer one by one to request bootfile name.
   1035           //
   1036           for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) {
   1037             ASSERT (Index < PXEBC_OFFER_MAX_NUM);
   1038             ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index];
   1039             if (!EFI_ERROR (PxeBcRetryBinlOffer (Private, ProxyIndex))) {
   1040               break;
   1041             }
   1042           }
   1043           if (Index == Private->OfferCount[Private->SelectProxyType]) {
   1044             Status = EFI_NO_RESPONSE;
   1045           }
   1046         } else {
   1047           //
   1048           // For other proxy offers, only one is buffered.
   1049           //
   1050           ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
   1051         }
   1052       } else {
   1053         //
   1054         // The proxy offer should not be determined if select by received order.
   1055         //
   1056         Status = EFI_NO_RESPONSE;
   1057 
   1058         for (Index = 0; Index < Private->OfferNum; Index++) {
   1059           ASSERT (Index < PXEBC_OFFER_MAX_NUM);
   1060           Offer     = &Private->OfferBuffer[Index].Dhcp4.Packet.Offer;
   1061           OfferType = Private->OfferBuffer[Index].Dhcp4.OfferType;
   1062           if (!IS_PROXY_DHCP_OFFER (Offer)) {
   1063             //
   1064             // Skip non proxy DHCPv4 offers.
   1065             //
   1066             continue;
   1067           }
   1068 
   1069           if (OfferType == PxeOfferTypeProxyBinl) {
   1070             //
   1071             // Try all the cached ProxyBinl offer one by one to request bootfile name.
   1072             //
   1073             if (EFI_ERROR (PxeBcRetryBinlOffer (Private, Index))) {
   1074               continue;
   1075             }
   1076           }
   1077 
   1078           Private->SelectProxyType = OfferType;
   1079           ProxyIndex               = Index;
   1080           Status                   = EFI_SUCCESS;
   1081           break;
   1082         }
   1083       }
   1084 
   1085       if (!EFI_ERROR (Status) && Private->SelectProxyType != PxeOfferTypeProxyBinl) {
   1086         //
   1087         // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
   1088         //
   1089         PxeBcCopyProxyOffer (Private, ProxyIndex);
   1090       }
   1091     } else {
   1092       //
   1093       //  Othewise, the bootfile name must be included in DhcpOnly offer.
   1094       //
   1095       if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
   1096         Status = EFI_NOT_FOUND;
   1097       }
   1098     }
   1099   }
   1100 
   1101   if (!EFI_ERROR (Status)) {
   1102     //
   1103     // All PXE boot information is ready by now.
   1104     //
   1105     Mode  = Private->PxeBc.Mode;
   1106     Offer = &Cache4->Packet.Offer;
   1107     Ack   = &Private->DhcpAck.Dhcp4.Packet.Ack;
   1108     if (Cache4->OfferType == PxeOfferTypeBootp) {
   1109       //
   1110       // Bootp is a special case that only 2 packets involved instead of 4. So the bootp's reply
   1111       // should be taken as ack.
   1112       //
   1113       Ack = Offer;
   1114     }
   1115 
   1116     PxeBcCopyDhcp4Ack (Private, Ack, TRUE);
   1117     Mode->DhcpDiscoverValid = TRUE;
   1118   }
   1119 
   1120   return Status;
   1121 }
   1122 
   1123 
   1124 /**
   1125   EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
   1126   to intercept events that occurred in the configuration process.
   1127 
   1128   @param[in]  This              Pointer to the EFI DHCPv4 Protocol.
   1129   @param[in]  Context           Pointer to the context set by EFI_DHCP4_PROTOCOL.Configure().
   1130   @param[in]  CurrentState      The current operational state of the EFI DHCPv4 Protocol driver.
   1131   @param[in]  Dhcp4Event        The event that occurs in the current state, which usually means a
   1132                                 state transition.
   1133   @param[in]  Packet            The DHCPv4 packet that is going to be sent or already received.
   1134   @param[out] NewPacket         The packet that is used to replace the above Packet.
   1135 
   1136   @retval EFI_SUCCESS           Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
   1137   @retval EFI_NOT_READY         Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
   1138                                 driver will continue to wait for more DHCPOFFER packets until the
   1139                                 retry timeout expires.
   1140   @retval EFI_ABORTED           Tells the EFI DHCPv4 Protocol driver to abort the current process
   1141                                 and return to the Dhcp4Init or Dhcp4InitReboot state.
   1142 
   1143 **/
   1144 EFI_STATUS
   1145 EFIAPI
   1146 PxeBcDhcp4CallBack (
   1147   IN  EFI_DHCP4_PROTOCOL               *This,
   1148   IN  VOID                             *Context,
   1149   IN  EFI_DHCP4_STATE                  CurrentState,
   1150   IN  EFI_DHCP4_EVENT                  Dhcp4Event,
   1151   IN  EFI_DHCP4_PACKET                 *Packet            OPTIONAL,
   1152   OUT EFI_DHCP4_PACKET                 **NewPacket        OPTIONAL
   1153   )
   1154 {
   1155   PXEBC_PRIVATE_DATA                   *Private;
   1156   EFI_PXE_BASE_CODE_MODE               *Mode;
   1157   EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL  *Callback;
   1158   EFI_DHCP4_PACKET_OPTION              *MaxMsgSize;
   1159   UINT16                               Value;
   1160   EFI_STATUS                           Status;
   1161   BOOLEAN                              Received;
   1162 
   1163   if ((Dhcp4Event != Dhcp4RcvdOffer) &&
   1164       (Dhcp4Event != Dhcp4SelectOffer) &&
   1165       (Dhcp4Event != Dhcp4SendDiscover) &&
   1166       (Dhcp4Event != Dhcp4RcvdAck)) {
   1167     return EFI_SUCCESS;
   1168   }
   1169 
   1170   Private   = (PXEBC_PRIVATE_DATA *) Context;
   1171   Mode      = Private->PxeBc.Mode;
   1172   Callback  = Private->PxeBcCallback;
   1173 
   1174   //
   1175   // Override the Maximum DHCP Message Size.
   1176   //
   1177   MaxMsgSize = PxeBcParseDhcp4Options (
   1178                  Packet->Dhcp4.Option,
   1179                  GET_OPTION_BUFFER_LEN (Packet),
   1180                  PXEBC_DHCP4_TAG_MAXMSG
   1181                  );
   1182   if (MaxMsgSize != NULL) {
   1183     Value = HTONS (PXEBC_DHCP4_PACKET_MAX_SIZE - 8);
   1184     CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));
   1185   }
   1186 
   1187   //
   1188   // Callback to user if any packets sent or received.
   1189   //
   1190   if (Dhcp4Event != Dhcp4SelectOffer && Callback != NULL) {
   1191     Received = (BOOLEAN) (Dhcp4Event == Dhcp4RcvdOffer || Dhcp4Event == Dhcp4RcvdAck);
   1192     Status = Callback->Callback (
   1193                          Callback,
   1194                          Private->Function,
   1195                          Received,
   1196                          Packet->Length,
   1197                          (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp4
   1198                          );
   1199     if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
   1200       return EFI_ABORTED;
   1201     }
   1202   }
   1203 
   1204   Status = EFI_SUCCESS;
   1205 
   1206   switch (Dhcp4Event) {
   1207 
   1208   case Dhcp4SendDiscover:
   1209     //
   1210     // Cache the DHCPv4 discover packet to mode data directly.
   1211     // It need to check SendGuid as well as Dhcp4SendRequest.
   1212     //
   1213     CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp4, Packet->Length);
   1214 
   1215   case Dhcp4SendRequest:
   1216     if (Mode->SendGUID) {
   1217       //
   1218       // Send the system Guid instead of the MAC address as the hardware address if required.
   1219       //
   1220       if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Packet->Dhcp4.Header.ClientHwAddr))) {
   1221         //
   1222         // Zero the Guid to indicate NOT programable if failed to get system Guid.
   1223         //
   1224         ZeroMem (Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));
   1225       }
   1226       Packet->Dhcp4.Header.HwAddrLen = (UINT8) sizeof (EFI_GUID);
   1227     }
   1228     break;
   1229 
   1230   case Dhcp4RcvdOffer:
   1231     Status = EFI_NOT_READY;
   1232     if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) {
   1233       //
   1234       // Cache the DHCPv4 offers to OfferBuffer[] for select later, and record
   1235       // the OfferIndex and OfferCount.
   1236       //
   1237       PxeBcCacheDhcp4Offer (Private, Packet);
   1238     }
   1239     break;
   1240 
   1241   case Dhcp4SelectOffer:
   1242     //
   1243     // Select offer by the default policy or by order, and record the SelectIndex
   1244     // and SelectProxyType.
   1245     //
   1246     PxeBcSelectDhcp4Offer (Private);
   1247 
   1248     if (Private->SelectIndex == 0) {
   1249       Status = EFI_ABORTED;
   1250     } else {
   1251       *NewPacket = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4.Packet.Offer;
   1252     }
   1253     break;
   1254 
   1255   case Dhcp4RcvdAck:
   1256     //
   1257     // Cache the DHCPv4 ack to Private->Dhcp4Ack, but it's not the final ack in mode data
   1258     // without verification.
   1259     //
   1260     ASSERT (Private->SelectIndex != 0);
   1261 
   1262     PxeBcCopyDhcp4Ack (Private, Packet, FALSE);
   1263     break;
   1264 
   1265   default:
   1266     break;
   1267   }
   1268 
   1269   return Status;
   1270 }
   1271 
   1272 
   1273 /**
   1274   Build and send out the request packet for the bootfile, and parse the reply.
   1275 
   1276   @param[in]  Private               Pointer to PxeBc private data.
   1277   @param[in]  Type                  PxeBc option boot item type.
   1278   @param[in]  Layer                 Pointer to option boot item layer.
   1279   @param[in]  UseBis                Use BIS or not.
   1280   @param[in]  DestIp                Pointer to the server address.
   1281   @param[in]  IpCount               The total count of the server address.
   1282   @param[in]  SrvList               Pointer to EFI_PXE_BASE_CODE_SRVLIST.
   1283 
   1284   @retval     EFI_SUCCESS           Successfully discovered boot file.
   1285   @retval     EFI_OUT_OF_RESOURCES  Failed to allocate resource.
   1286   @retval     EFI_NOT_FOUND         Can't get the PXE reply packet.
   1287   @retval     Others                Failed to discover boot file.
   1288 
   1289 **/
   1290 EFI_STATUS
   1291 PxeBcDhcp4Discover (
   1292   IN  PXEBC_PRIVATE_DATA              *Private,
   1293   IN  UINT16                          Type,
   1294   IN  UINT16                          *Layer,
   1295   IN  BOOLEAN                         UseBis,
   1296   IN  EFI_IP_ADDRESS                  *DestIp,
   1297   IN  UINT16                          IpCount,
   1298   IN  EFI_PXE_BASE_CODE_SRVLIST       *SrvList
   1299   )
   1300 {
   1301   EFI_PXE_BASE_CODE_UDP_PORT          Sport;
   1302   EFI_PXE_BASE_CODE_MODE              *Mode;
   1303   EFI_DHCP4_PROTOCOL                  *Dhcp4;
   1304   EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN    Token;
   1305   BOOLEAN                             IsBCast;
   1306   EFI_STATUS                          Status;
   1307   UINT16                              RepIndex;
   1308   UINT16                              SrvIndex;
   1309   UINT16                              TryIndex;
   1310   EFI_DHCP4_LISTEN_POINT              ListenPoint;
   1311   EFI_DHCP4_PACKET                    *Response;
   1312   UINT8                               Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];
   1313   EFI_DHCP4_PACKET_OPTION             *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];
   1314   UINT32                              OptCount;
   1315   EFI_DHCP4_PACKET_OPTION             *PxeOpt;
   1316   PXEBC_OPTION_BOOT_ITEM              *PxeBootItem;
   1317   UINT8                               VendorOptLen;
   1318   UINT32                              Xid;
   1319 
   1320   Mode      = Private->PxeBc.Mode;
   1321   Dhcp4     = Private->Dhcp4;
   1322   Status    = EFI_SUCCESS;
   1323 
   1324   ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));
   1325 
   1326   //
   1327   // Use broadcast if destination address not specified.
   1328   //
   1329   if (DestIp == NULL) {
   1330     Sport   = PXEBC_DHCP4_S_PORT;
   1331     IsBCast = TRUE;
   1332   } else {
   1333     Sport   = PXEBC_BS_DISCOVER_PORT;
   1334     IsBCast = FALSE;
   1335   }
   1336 
   1337   if (!UseBis && Layer != NULL) {
   1338     *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;
   1339   }
   1340 
   1341   //
   1342   // Build all the options for the request packet.
   1343   //
   1344   OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, TRUE);
   1345 
   1346   if (Private->IsDoDiscover) {
   1347     //
   1348     // Add vendor option of PXE_BOOT_ITEM
   1349     //
   1350     VendorOptLen      = (UINT8) ((sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1);
   1351     OptList[OptCount] = AllocateZeroPool (VendorOptLen);
   1352     if (OptList[OptCount] == NULL) {
   1353       return EFI_OUT_OF_RESOURCES;
   1354     }
   1355 
   1356     OptList[OptCount]->OpCode     = PXEBC_DHCP4_TAG_VENDOR;
   1357     OptList[OptCount]->Length     = (UINT8) (VendorOptLen - 2);
   1358     PxeOpt                        = (EFI_DHCP4_PACKET_OPTION *) OptList[OptCount]->Data;
   1359     PxeOpt->OpCode                = PXEBC_VENDOR_TAG_BOOT_ITEM;
   1360     PxeOpt->Length                = (UINT8) sizeof (PXEBC_OPTION_BOOT_ITEM);
   1361     PxeBootItem                   = (PXEBC_OPTION_BOOT_ITEM *) PxeOpt->Data;
   1362     PxeBootItem->Type             = HTONS (Type);
   1363     PxeOpt->Data[PxeOpt->Length]  = PXEBC_DHCP4_TAG_EOP;
   1364 
   1365     if (Layer != NULL) {
   1366       PxeBootItem->Layer          = HTONS (*Layer);
   1367     }
   1368 
   1369     OptCount++;
   1370   }
   1371 
   1372   //
   1373   // Build the request packet with seed packet and option list.
   1374   //
   1375   Status = Dhcp4->Build (
   1376                     Dhcp4,
   1377                     &Private->SeedPacket,
   1378                     0,
   1379                     NULL,
   1380                     OptCount,
   1381                     OptList,
   1382                     &Token.Packet
   1383                     );
   1384   //
   1385   // Free the vendor option of PXE_BOOT_ITEM.
   1386   //
   1387   if (Private->IsDoDiscover) {
   1388     FreePool (OptList[OptCount - 1]);
   1389   }
   1390 
   1391   if (EFI_ERROR (Status)) {
   1392     return Status;
   1393   }
   1394 
   1395   if (Mode->SendGUID) {
   1396     if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Token.Packet->Dhcp4.Header.ClientHwAddr))) {
   1397       //
   1398       // Zero the Guid to indicate NOT programable if failed to get system Guid.
   1399       //
   1400       ZeroMem (Token.Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID));
   1401     }
   1402     Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8)  sizeof (EFI_GUID);
   1403   }
   1404 
   1405   //
   1406   // Set fields of the token for the request packet.
   1407   //
   1408   Xid                                 = NET_RANDOM (NetRandomInitSeed ());
   1409   Token.Packet->Dhcp4.Header.Xid      = HTONL (Xid);
   1410   Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16) ((IsBCast) ? 0x8000 : 0x0));
   1411   CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
   1412 
   1413   Token.RemotePort = Sport;
   1414 
   1415   if (IsBCast) {
   1416     SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);
   1417   } else {
   1418     CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));
   1419   }
   1420 
   1421   CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));
   1422 
   1423   if (!IsBCast) {
   1424     Token.ListenPointCount            = 1;
   1425     Token.ListenPoints                = &ListenPoint;
   1426     Token.ListenPoints[0].ListenPort  = PXEBC_BS_DISCOVER_PORT;
   1427     CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof(EFI_IPv4_ADDRESS));
   1428     CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof(EFI_IPv4_ADDRESS));
   1429   }
   1430 
   1431   //
   1432   // Send out the request packet to discover the bootfile.
   1433   //
   1434   for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) {
   1435 
   1436     Token.TimeoutValue                  = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex);
   1437     Token.Packet->Dhcp4.Header.Seconds  = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * (TryIndex - 1));
   1438 
   1439     Status = Dhcp4->TransmitReceive (Dhcp4, &Token);
   1440     if (Token.Status != EFI_TIMEOUT) {
   1441       break;
   1442     }
   1443   }
   1444 
   1445   if (TryIndex > PXEBC_BOOT_REQUEST_RETRIES) {
   1446     //
   1447     // No server response our PXE request
   1448     //
   1449     Status = EFI_TIMEOUT;
   1450   }
   1451 
   1452   if (!EFI_ERROR (Status)) {
   1453 
   1454     RepIndex  = 0;
   1455     SrvIndex  = 0;
   1456     Response  = Token.ResponseList;
   1457     //
   1458     // Find the right PXE Reply according to server address.
   1459     //
   1460     while (RepIndex < Token.ResponseCount) {
   1461 
   1462       while (SrvIndex < IpCount) {
   1463         if (SrvList[SrvIndex].AcceptAnyResponse) {
   1464           break;
   1465         }
   1466         if ((SrvList[SrvIndex].Type == Type) &&
   1467             EFI_IP4_EQUAL (&Response->Dhcp4.Header.ServerAddr, &SrvList[SrvIndex].IpAddr)) {
   1468           break;
   1469         }
   1470         SrvIndex++;
   1471       }
   1472 
   1473       if ((IpCount != SrvIndex) || (IpCount == 0)) {
   1474         break;
   1475       }
   1476 
   1477       SrvIndex = 0;
   1478       RepIndex++;
   1479 
   1480       Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size);
   1481     }
   1482 
   1483     if (RepIndex < Token.ResponseCount) {
   1484       //
   1485       // Cache the right PXE reply packet here, set valid flag later.
   1486       // Especially for PXE discover packet, store it into mode data here.
   1487       //
   1488       if (Private->IsDoDiscover) {
   1489         PxeBcCacheDhcp4Packet (&Private->PxeReply.Dhcp4.Packet.Ack, Response);
   1490         CopyMem (&Mode->PxeDiscover, &Token.Packet->Dhcp4, Token.Packet->Length);
   1491       } else {
   1492         PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Response);
   1493       }
   1494     } else {
   1495       //
   1496       // Not found the right PXE reply packet.
   1497       //
   1498       Status = EFI_NOT_FOUND;
   1499     }
   1500     if (Token.ResponseList != NULL) {
   1501       FreePool (Token.ResponseList);
   1502     }
   1503   }
   1504 
   1505   FreePool (Token.Packet);
   1506   return Status;
   1507 }
   1508 
   1509 /**
   1510   Switch the Ip4 policy to static.
   1511 
   1512   @param[in]  Private             The pointer to PXEBC_PRIVATE_DATA.
   1513 
   1514   @retval     EFI_SUCCESS         The policy is already configured to static.
   1515   @retval     Others              Other error as indicated..
   1516 
   1517 **/
   1518 EFI_STATUS
   1519 PxeBcSetIp4Policy (
   1520   IN PXEBC_PRIVATE_DATA            *Private
   1521   )
   1522 {
   1523   EFI_STATUS                   Status;
   1524   EFI_IP4_CONFIG2_PROTOCOL     *Ip4Config2;
   1525   EFI_IP4_CONFIG2_POLICY       Policy;
   1526   UINTN                        DataSize;
   1527 
   1528   Ip4Config2 = Private->Ip4Config2;
   1529   DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
   1530   Status = Ip4Config2->GetData (
   1531                        Ip4Config2,
   1532                        Ip4Config2DataTypePolicy,
   1533                        &DataSize,
   1534                        &Policy
   1535                        );
   1536   if (EFI_ERROR (Status)) {
   1537     return Status;
   1538   }
   1539 
   1540   if (Policy != Ip4Config2PolicyStatic) {
   1541     Policy = Ip4Config2PolicyStatic;
   1542     Status= Ip4Config2->SetData (
   1543                           Ip4Config2,
   1544                           Ip4Config2DataTypePolicy,
   1545                           sizeof (EFI_IP4_CONFIG2_POLICY),
   1546                           &Policy
   1547                           );
   1548     if (EFI_ERROR (Status)) {
   1549       return Status;
   1550     }
   1551   }
   1552 
   1553   return  EFI_SUCCESS;
   1554 }
   1555 
   1556 /**
   1557   Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other PXE boot information.
   1558 
   1559   @param[in]  Private           Pointer to PxeBc private data.
   1560   @param[in]  Dhcp4             Pointer to the EFI_DHCP4_PROTOCOL
   1561 
   1562   @retval EFI_SUCCESS           The D.O.R.A process successfully finished.
   1563   @retval Others                Failed to finish the D.O.R.A process.
   1564 
   1565 **/
   1566 EFI_STATUS
   1567 PxeBcDhcp4Dora (
   1568   IN PXEBC_PRIVATE_DATA        *Private,
   1569   IN EFI_DHCP4_PROTOCOL        *Dhcp4
   1570   )
   1571 {
   1572   EFI_PXE_BASE_CODE_MODE       *PxeMode;
   1573   EFI_DHCP4_CONFIG_DATA        Config;
   1574   EFI_DHCP4_MODE_DATA          Mode;
   1575   EFI_DHCP4_PACKET_OPTION      *OptList[PXEBC_DHCP4_OPTION_MAX_NUM];
   1576   UINT8                        Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE];
   1577   UINT32                       OptCount;
   1578   EFI_STATUS                   Status;
   1579 
   1580   ASSERT (Dhcp4 != NULL);
   1581 
   1582   Status   = EFI_SUCCESS;
   1583   PxeMode  = Private->PxeBc.Mode;
   1584 
   1585   //
   1586   // Build option list for the request packet.
   1587   //
   1588   OptCount = PxeBcBuildDhcp4Options (Private, OptList, Buffer, FALSE);
   1589   ASSERT (OptCount> 0);
   1590 
   1591   ZeroMem (&Mode, sizeof (EFI_DHCP4_MODE_DATA));
   1592   ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
   1593 
   1594   Config.OptionCount      = OptCount;
   1595   Config.OptionList       = OptList;
   1596   Config.Dhcp4Callback    = PxeBcDhcp4CallBack;
   1597   Config.CallbackContext  = Private;
   1598   Config.DiscoverTryCount = PXEBC_DHCP_RETRIES;
   1599   Config.DiscoverTimeout  = mPxeDhcpTimeout;
   1600 
   1601   //
   1602   // Configure the DHCPv4 instance for PXE boot.
   1603   //
   1604   Status = Dhcp4->Configure (Dhcp4, &Config);
   1605   if (EFI_ERROR (Status)) {
   1606     goto ON_EXIT;
   1607   }
   1608 
   1609   //
   1610   // Initialize the record fields for DHCPv4 offer in private data.
   1611   //
   1612   Private->IsProxyRecved = FALSE;
   1613   Private->OfferNum      = 0;
   1614   ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
   1615   ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
   1616 
   1617   //
   1618   // Start DHCPv4 D.O.R.A. process to acquire IPv4 address. This may
   1619   // have already been done, thus do not leave in error if the return
   1620   // code is EFI_ALREADY_STARTED.
   1621   //
   1622   Status = Dhcp4->Start (Dhcp4, NULL);
   1623   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
   1624     if (Status == EFI_ICMP_ERROR) {
   1625       PxeMode->IcmpErrorReceived = TRUE;
   1626     }
   1627     goto ON_EXIT;
   1628   }
   1629 
   1630   //
   1631   // Get the acquired IPv4 address and store them.
   1632   //
   1633   Status = Dhcp4->GetModeData (Dhcp4, &Mode);
   1634   if (EFI_ERROR (Status)) {
   1635     goto ON_EXIT;
   1636   }
   1637 
   1638   ASSERT (Mode.State == Dhcp4Bound);
   1639 
   1640   CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
   1641   CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
   1642   CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
   1643   CopyMem (&PxeMode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
   1644   CopyMem (&PxeMode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
   1645 
   1646   Status = PxeBcFlushStationIp (Private, &Private->StationIp, &Private->SubnetMask);
   1647   if (EFI_ERROR (Status)) {
   1648     goto ON_EXIT;
   1649   }
   1650 
   1651   //
   1652   // Check the selected offer whether BINL retry is needed.
   1653   //
   1654   Status = PxeBcHandleDhcp4Offer (Private);
   1655 
   1656   AsciiPrint ("\n  Station IP address is ");
   1657 
   1658   PxeBcShowIp4Addr (&Private->StationIp.v4);
   1659   AsciiPrint ("\n");
   1660 
   1661 ON_EXIT:
   1662   if (EFI_ERROR (Status)) {
   1663     Dhcp4->Stop (Dhcp4);
   1664     Dhcp4->Configure (Dhcp4, NULL);
   1665   } else {
   1666     ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA));
   1667     Dhcp4->Configure (Dhcp4, &Config);
   1668     Private->IsAddressOk = TRUE;
   1669   }
   1670 
   1671   return Status;
   1672 }
   1673