Home | History | Annotate | Download | only in UefiPxeBcDxe
      1 /** @file
      2   Support for PxeBc dhcp functions.
      3 
      4 Copyright (c) 2013, Red Hat, Inc.
      5 Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
      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 
     17 #include "PxeBcImpl.h"
     18 
     19 //
     20 // This is a map from the interested DHCP4 option tags' index to the tag value.
     21 //
     22 UINT8 mInterestedDhcp4Tags[PXEBC_DHCP4_TAG_INDEX_MAX] = {
     23   PXEBC_DHCP4_TAG_BOOTFILE_LEN,
     24   PXEBC_DHCP4_TAG_VENDOR,
     25   PXEBC_DHCP4_TAG_OVERLOAD,
     26   PXEBC_DHCP4_TAG_MSG_TYPE,
     27   PXEBC_DHCP4_TAG_SERVER_ID,
     28   PXEBC_DHCP4_TAG_CLASS_ID,
     29   PXEBC_DHCP4_TAG_BOOTFILE
     30 };
     31 
     32 
     33 /**
     34   This function initialize the DHCP4 message instance.
     35 
     36   This function will pad each item of dhcp4 message packet.
     37 
     38   @param  Seed    Pointer to the message instance of the DHCP4 packet.
     39   @param  Udp4    Pointer to the EFI_UDP4_PROTOCOL instance.
     40 
     41 **/
     42 VOID
     43 PxeBcInitSeedPacket (
     44   IN EFI_DHCP4_PACKET  *Seed,
     45   IN EFI_UDP4_PROTOCOL *Udp4
     46   )
     47 {
     48   EFI_SIMPLE_NETWORK_MODE Mode;
     49   EFI_DHCP4_HEADER        *Header;
     50 
     51   Udp4->GetModeData (Udp4, NULL, NULL, NULL, &Mode);
     52 
     53   Seed->Size    = sizeof (EFI_DHCP4_PACKET);
     54   Seed->Length  = sizeof (Seed->Dhcp4);
     55 
     56   Header        = &Seed->Dhcp4.Header;
     57 
     58   ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));
     59   Header->OpCode    = PXEBC_DHCP4_OPCODE_REQUEST;
     60   Header->HwType    = Mode.IfType;
     61   Header->HwAddrLen = (UINT8) Mode.HwAddressSize;
     62   CopyMem (Header->ClientHwAddr, &Mode.CurrentAddress, Header->HwAddrLen);
     63 
     64   Seed->Dhcp4.Magik     = PXEBC_DHCP4_MAGIC;
     65   Seed->Dhcp4.Option[0] = PXEBC_DHCP4_TAG_EOP;
     66 }
     67 
     68 
     69 /**
     70   Copy the DCHP4 packet from srouce to destination.
     71 
     72   @param  Dst   Pointer to the EFI_DHCP4_PROTOCOL instance.
     73   @param  Src   Pointer to the EFI_DHCP4_PROTOCOL instance.
     74 
     75 **/
     76 VOID
     77 PxeBcCopyEfiDhcp4Packet (
     78   IN EFI_DHCP4_PACKET  *Dst,
     79   IN EFI_DHCP4_PACKET  *Src
     80   )
     81 {
     82   ASSERT (Dst->Size >= Src->Length);
     83 
     84   CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length);
     85   Dst->Length = Src->Length;
     86 }
     87 
     88 
     89 /**
     90   Copy the dhcp4 packet to the PxeBc private data and parse the dhcp4 packet.
     91 
     92   @param  Private       Pointer to PxeBc private data.
     93   @param  OfferIndex    Index of cached packets as complements of pxe mode data,
     94                         the index is maximum offer number.
     95 
     96 **/
     97 VOID
     98 PxeBcCopyProxyOffer (
     99   IN PXEBC_PRIVATE_DATA  *Private,
    100   IN UINT32              OfferIndex
    101   )
    102 {
    103   EFI_PXE_BASE_CODE_MODE  *Mode;
    104   EFI_DHCP4_PACKET        *Offer;
    105 
    106   ASSERT (OfferIndex < Private->NumOffers);
    107   ASSERT (OfferIndex < PXEBC_MAX_OFFER_NUM);
    108 
    109   Mode  = Private->PxeBc.Mode;
    110   Offer = &Private->Dhcp4Offers[OfferIndex].Packet.Offer;
    111 
    112   PxeBcCopyEfiDhcp4Packet (&Private->ProxyOffer.Packet.Offer, Offer);
    113   CopyMem (&Mode->ProxyOffer, &Offer->Dhcp4, Offer->Length);
    114   Mode->ProxyOfferReceived = TRUE;
    115 
    116   PxeBcParseCachedDhcpPacket (&Private->ProxyOffer);
    117 }
    118 
    119 
    120 /**
    121   Parse the cached dhcp packet.
    122 
    123   @param  CachedPacket  Pointer to cached dhcp packet.
    124 
    125   @retval TRUE          Succeed to parse and validation.
    126   @retval FALSE         Fail to parse or validation.
    127 
    128 **/
    129 BOOLEAN
    130 PxeBcParseCachedDhcpPacket (
    131   IN PXEBC_CACHED_DHCP4_PACKET  *CachedPacket
    132   )
    133 {
    134   EFI_DHCP4_PACKET        *Offer;
    135   EFI_DHCP4_PACKET_OPTION **Options;
    136   EFI_DHCP4_PACKET_OPTION *Option;
    137   UINT8                   OfferType;
    138   UINTN                   Index;
    139   UINT8                   *Ptr8;
    140 
    141   CachedPacket->IsPxeOffer = FALSE;
    142   ZeroMem (CachedPacket->Dhcp4Option, sizeof (CachedPacket->Dhcp4Option));
    143   ZeroMem (&CachedPacket->PxeVendorOption, sizeof (CachedPacket->PxeVendorOption));
    144 
    145   Offer   = &CachedPacket->Packet.Offer;
    146   Options = CachedPacket->Dhcp4Option;
    147 
    148   //
    149   // Parse interested dhcp options and store their pointers in CachedPacket->Dhcp4Option.
    150   // First, try to parse DHCPv4 options from the DHCP optional parameters field.
    151   //
    152   for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
    153     Options[Index] = PxeBcParseExtendOptions (
    154                        Offer->Dhcp4.Option,
    155                        GET_OPTION_BUFFER_LEN (Offer),
    156                        mInterestedDhcp4Tags[Index]
    157                        );
    158   }
    159   //
    160   // Second, Check if bootfilename and serverhostname is overloaded to carry DHCP options refers to rfc-2132.
    161   // If yes, try to parse options from the BootFileName field, then ServerName field.
    162   //
    163   Option = Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD];
    164   if (Option != NULL) {
    165     if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_FILE) != 0) {
    166       for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
    167         if (Options[Index] == NULL) {
    168           Options[Index] = PxeBcParseExtendOptions (
    169                              (UINT8 *) Offer->Dhcp4.Header.BootFileName,
    170                              sizeof (Offer->Dhcp4.Header.BootFileName),
    171                              mInterestedDhcp4Tags[Index]
    172                              );
    173         }
    174       }
    175     }
    176     if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_SERVER_NAME) != 0) {
    177       for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {
    178         if (Options[Index] == NULL) {
    179           Options[Index] = PxeBcParseExtendOptions (
    180                              (UINT8 *) Offer->Dhcp4.Header.ServerName,
    181                              sizeof (Offer->Dhcp4.Header.ServerName),
    182                              mInterestedDhcp4Tags[Index]
    183                              );
    184         }
    185       }
    186     }
    187   }
    188 
    189   //
    190   // Check whether is an offer with PXEClient or not.
    191   //
    192   Option = Options[PXEBC_DHCP4_TAG_INDEX_CLASS_ID];
    193   if ((Option != NULL) && (Option->Length >= 9) &&
    194     (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) {
    195 
    196     CachedPacket->IsPxeOffer = TRUE;
    197   }
    198 
    199   //
    200   // Parse pxe vendor options and store their content/pointers in CachedPacket->PxeVendorOption.
    201   //
    202   Option = Options[PXEBC_DHCP4_TAG_INDEX_VENDOR];
    203   if (CachedPacket->IsPxeOffer && (Option != NULL)) {
    204 
    205     if (!PxeBcParseVendorOptions (Option, &CachedPacket->PxeVendorOption)) {
    206       return FALSE;
    207     }
    208   }
    209 
    210 
    211   //
    212   // Parse PXE boot file name:
    213   // According to PXE spec, boot file name should be read from DHCP option 67 (bootfile name) if present.
    214   // Otherwise, read from boot file field in DHCP header.
    215   //
    216   if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
    217     //
    218     // RFC 2132, Section 9.5 does not strictly state Bootfile name (option 67) is null
    219     // terminated string. So force to append null terminated character at the end of string.
    220     //
    221     Ptr8 =  (UINT8*)&Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data[0];
    222     Ptr8 += Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Length;
    223     if (*(Ptr8 - 1) != '\0') {
    224       *Ptr8 = '\0';
    225     }
    226   } else if (Offer->Dhcp4.Header.BootFileName[0] != 0) {
    227     //
    228     // If the bootfile is not present and bootfilename is present in dhcp packet, just parse it.
    229     // And do not count dhcp option header, or else will destroy the serverhostname.
    230     //
    231     Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *) (&Offer->Dhcp4.Header.BootFileName[0] -
    232                                             OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0]));
    233 
    234   }
    235 
    236   //
    237   // Determine offer type of the dhcp packet.
    238   //
    239   Option = Options[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE];
    240   if ((Option == NULL) || (Option->Data[0] == 0)) {
    241     //
    242     // It's a bootp offer
    243     //
    244     Option = CachedPacket->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE];
    245     if (Option == NULL) {
    246       //
    247       // bootp offer without bootfilename, discard it.
    248       //
    249       return FALSE;
    250     }
    251 
    252     OfferType = DHCP4_PACKET_TYPE_BOOTP;
    253 
    254   } else {
    255 
    256     if (IS_VALID_DISCOVER_VENDOR_OPTION (CachedPacket->PxeVendorOption.BitMap)) {
    257       //
    258       // It's a pxe10 offer with PXEClient and discover vendor option.
    259       //
    260       OfferType = DHCP4_PACKET_TYPE_PXE10;
    261     } else if (IS_VALID_MTFTP_VENDOR_OPTION (CachedPacket->PxeVendorOption.BitMap)) {
    262       //
    263       // It's a wfm11a offer with PXEClient and mtftp vendor option, and
    264       // return false since mtftp not supported currently.
    265       //
    266       return FALSE;
    267     } else {
    268       //
    269       // If the binl offer with only PXEClient.
    270       //
    271       OfferType = (UINT8) ((CachedPacket->IsPxeOffer) ? DHCP4_PACKET_TYPE_BINL : DHCP4_PACKET_TYPE_DHCP_ONLY);
    272     }
    273   }
    274 
    275   CachedPacket->OfferType = OfferType;
    276 
    277   return TRUE;
    278 }
    279 
    280 
    281 /**
    282   Offer dhcp service with a BINL dhcp offer.
    283 
    284   @param  Private   Pointer to PxeBc private data.
    285   @param  Index     Index of cached packets as complements of pxe mode data,
    286                     the index is maximum offer number.
    287 
    288   @retval TRUE      Offer the service successfully under priority BINL.
    289   @retval FALSE     Boot Service failed, parse cached dhcp packet failed or this
    290                     BINL ack cannot find options set or bootfile name specified.
    291 
    292 **/
    293 BOOLEAN
    294 PxeBcTryBinl (
    295   IN PXEBC_PRIVATE_DATA  *Private,
    296   IN UINT32              Index
    297   )
    298 {
    299   EFI_DHCP4_PACKET          *Offer;
    300   EFI_IP_ADDRESS            ServerIp;
    301   EFI_STATUS                Status;
    302   PXEBC_CACHED_DHCP4_PACKET *CachedPacket;
    303   EFI_DHCP4_PACKET          *Reply;
    304 
    305   ASSERT (Index < PXEBC_MAX_OFFER_NUM);
    306   ASSERT (Private->Dhcp4Offers[Index].OfferType == DHCP4_PACKET_TYPE_BINL);
    307 
    308   Offer = &Private->Dhcp4Offers[Index].Packet.Offer;
    309 
    310   //
    311   // Use siaddr(next server) in DHCPOFFER packet header, if zero, use option 54(server identifier)
    312   // in DHCPOFFER packet.
    313   // (It does not comply with PXE Spec, Ver2.1)
    314   //
    315   if (EFI_IP4_EQUAL (&Offer->Dhcp4.Header.ServerAddr.Addr, &mZeroIp4Addr)) {
    316     CopyMem (
    317       &ServerIp.Addr[0],
    318       Private->Dhcp4Offers[Index].Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
    319       sizeof (EFI_IPv4_ADDRESS)
    320       );
    321   } else {
    322     CopyMem (
    323       &ServerIp.Addr[0],
    324       &Offer->Dhcp4.Header.ServerAddr,
    325       sizeof (EFI_IPv4_ADDRESS)
    326       );
    327   }
    328   if (ServerIp.Addr[0] == 0) {
    329     return FALSE;
    330   }
    331 
    332   CachedPacket = &Private->ProxyOffer;
    333   Reply        = &CachedPacket->Packet.Offer;
    334 
    335   Status = PxeBcDiscvBootService (
    336             Private,
    337             0,
    338             NULL,
    339             FALSE,
    340             &ServerIp,
    341             0,
    342             NULL,
    343             FALSE,
    344             Reply
    345             );
    346   if (EFI_ERROR (Status)) {
    347     return FALSE;
    348   }
    349 
    350   if (!PxeBcParseCachedDhcpPacket (CachedPacket)) {
    351     return FALSE;
    352   }
    353 
    354   if ((CachedPacket->OfferType != DHCP4_PACKET_TYPE_PXE10) &&
    355       (CachedPacket->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL)) {
    356     //
    357     // This BINL ack doesn't have discovery options set or bootfile name
    358     // specified.
    359     //
    360     return FALSE;
    361   }
    362 
    363   Private->PxeBc.Mode->ProxyOfferReceived = TRUE;
    364   CopyMem (&Private->PxeBc.Mode->ProxyOffer, &Reply->Dhcp4, Reply->Length);
    365 
    366   return TRUE;
    367 }
    368 
    369 
    370 /**
    371   Offer dhcp service for each proxy with a BINL dhcp offer.
    372 
    373   @param  Private     Pointer to PxeBc private data
    374   @param  OfferIndex  Pointer to the index of cached packets as complements of
    375                       pxe mode data, the index is maximum offer number.
    376 
    377   @return If there is no service needed offer return FALSE, otherwise TRUE.
    378 
    379 **/
    380 BOOLEAN
    381 PxeBcTryBinlProxy (
    382   IN  PXEBC_PRIVATE_DATA  *Private,
    383   OUT UINT32              *OfferIndex
    384   )
    385 {
    386   UINT32  Index;
    387 
    388   for (Index = 0; Index < Private->ProxyIndex[DHCP4_PACKET_TYPE_BINL]; Index++) {
    389 
    390     *OfferIndex = Private->BinlIndex[Index];
    391     //
    392     // Try this BINL proxy offer
    393     //
    394     if (PxeBcTryBinl (Private, *OfferIndex)) {
    395       return TRUE;
    396     }
    397   }
    398 
    399   return FALSE;
    400 }
    401 
    402 
    403 /**
    404   This function is to check the selected proxy offer (include BINL dhcp offer and
    405   DHCP_ONLY offer ) and set the flag and copy the DHCP packets to the Pxe base code
    406   mode structure.
    407 
    408   @param  Private          Pointer to PxeBc private data.
    409 
    410   @retval EFI_SUCCESS      Operational successful.
    411   @retval EFI_NO_RESPONSE  Offer dhcp service failed.
    412 
    413 **/
    414 EFI_STATUS
    415 PxeBcCheckSelectedOffer (
    416   IN PXEBC_PRIVATE_DATA  *Private
    417   )
    418 {
    419   PXEBC_CACHED_DHCP4_PACKET *SelectedOffer;
    420   EFI_DHCP4_PACKET_OPTION   **Options;
    421   UINT32                    Index;
    422   EFI_DHCP4_PACKET          *Offer;
    423   UINT32                    ProxyOfferIndex;
    424   EFI_STATUS                Status;
    425   EFI_PXE_BASE_CODE_MODE    *Mode;
    426   EFI_DHCP4_PACKET          *Ack;
    427 
    428   ASSERT (Private->SelectedOffer != 0);
    429 
    430   Status        = EFI_SUCCESS;
    431   SelectedOffer = &Private->Dhcp4Offers[Private->SelectedOffer - 1];
    432   Options       = SelectedOffer->Dhcp4Option;
    433 
    434   if (SelectedOffer->OfferType == DHCP4_PACKET_TYPE_BINL) {
    435     //
    436     // The addresses are acquired from a BINL dhcp offer, try BINL to get
    437     // the bootfile name
    438     //
    439     if (!PxeBcTryBinl (Private, Private->SelectedOffer - 1)) {
    440       Status = EFI_NO_RESPONSE;
    441     }
    442   } else if (SelectedOffer->OfferType == DHCP4_PACKET_TYPE_DHCP_ONLY) {
    443     //
    444     // The selected offer to finish the D.O.R.A. is a DHCP only offer, we need
    445     // try proxy offers if there are some, othewise the bootfile name must be
    446     // set in this DHCP only offer.
    447     //
    448     if (Private->GotProxyOffer) {
    449       //
    450       // Get rid of the compiler warning.
    451       //
    452       ProxyOfferIndex = 0;
    453       if (Private->SortOffers) {
    454         //
    455         // The offers are sorted before selecting, the proxy offer type must be
    456         // already determined.
    457         //
    458         ASSERT (Private->ProxyIndex[Private->ProxyOfferType] > 0);
    459 
    460         if (Private->ProxyOfferType == DHCP4_PACKET_TYPE_BINL) {
    461           //
    462           // We buffer all received BINL proxy offers, try them all one by one
    463           //
    464           if (!PxeBcTryBinlProxy (Private, &ProxyOfferIndex)) {
    465             Status = EFI_NO_RESPONSE;
    466           }
    467         } else {
    468           //
    469           // For other types, only one proxy offer is buffered.
    470           //
    471           ProxyOfferIndex = Private->ProxyIndex[Private->ProxyOfferType] - 1;
    472         }
    473       } else {
    474         //
    475         // The proxy offer type is not determined, choose proxy offer in the
    476         // received order.
    477         //
    478         Status = EFI_NO_RESPONSE;
    479 
    480         ASSERT (Private->NumOffers < PXEBC_MAX_OFFER_NUM);
    481         for (Index = 0; Index < Private->NumOffers; Index++) {
    482 
    483           Offer = &Private->Dhcp4Offers[Index].Packet.Offer;
    484           if (!IS_PROXY_DHCP_OFFER (Offer)) {
    485             //
    486             // Skip non proxy dhcp offers.
    487             //
    488             continue;
    489           }
    490 
    491           if (Private->Dhcp4Offers[Index].OfferType == DHCP4_PACKET_TYPE_BINL) {
    492             //
    493             // Try BINL
    494             //
    495             if (!PxeBcTryBinl (Private, Index)) {
    496               //
    497               // Failed, skip to the next offer
    498               //
    499               continue;
    500             }
    501           }
    502 
    503           Private->ProxyOfferType = Private->Dhcp4Offers[Index].OfferType;
    504           ProxyOfferIndex         = Index;
    505           Status                  = EFI_SUCCESS;
    506           break;
    507         }
    508       }
    509 
    510       if (!EFI_ERROR (Status) && (Private->ProxyOfferType != DHCP4_PACKET_TYPE_BINL)) {
    511         //
    512         // Copy the proxy offer to Mode and set the flag
    513         //
    514         PxeBcCopyProxyOffer (Private, ProxyOfferIndex);
    515       }
    516     } else {
    517       //
    518       // No proxy offer is received, the bootfile name MUST be set.
    519       //
    520       ASSERT (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);
    521     }
    522   }
    523 
    524   if (!EFI_ERROR (Status)) {
    525     //
    526     // Everything is OK, set the flag and copy the DHCP packets.
    527     //
    528     Mode  = Private->PxeBc.Mode;
    529     Offer = &SelectedOffer->Packet.Offer;
    530 
    531     //
    532     // The discover packet is already copied, just set flag here.
    533     //
    534     Mode->DhcpDiscoverValid = TRUE;
    535 
    536     Ack                     = &Private->Dhcp4Ack.Packet.Ack;
    537     if (SelectedOffer->OfferType == DHCP4_PACKET_TYPE_BOOTP) {
    538       //
    539       // Other type of ACK is already cached. Bootp is special that we should
    540       // use the bootp reply as the ACK and put it into the DHCP_ONLY buffer.
    541       //
    542       PxeBcCopyEfiDhcp4Packet (&Private->Dhcp4Ack.Packet.Ack, Offer);
    543     }
    544 
    545     PxeBcParseCachedDhcpPacket (&Private->Dhcp4Ack);
    546 
    547     Mode->DhcpAckReceived = TRUE;
    548 
    549     //
    550     // Copy the dhcp ack.
    551     //
    552     CopyMem (&Mode->DhcpAck, &Ack->Dhcp4, Ack->Length);
    553   }
    554 
    555   return Status;
    556 }
    557 
    558 
    559 /**
    560   Cache the Dhcp4 packet offer, Parse and validate each option of the packet.
    561 
    562   @param  Private    Pointer to PxeBc private data.
    563   @param  RcvdOffer  Pointer to the received Dhcp proxy offer packet.
    564 
    565 **/
    566 VOID
    567 PxeBcCacheDhcpOffer (
    568   IN PXEBC_PRIVATE_DATA  *Private,
    569   IN EFI_DHCP4_PACKET    *RcvdOffer
    570   )
    571 {
    572   PXEBC_CACHED_DHCP4_PACKET *CachedOffer;
    573   EFI_DHCP4_PACKET          *Offer;
    574   UINT8                     OfferType;
    575 
    576   CachedOffer = &Private->Dhcp4Offers[Private->NumOffers];
    577   Offer       = &CachedOffer->Packet.Offer;
    578 
    579   //
    580   // Cache the orignal dhcp packet
    581   //
    582   PxeBcCopyEfiDhcp4Packet (Offer, RcvdOffer);
    583 
    584   //
    585   // Parse and validate the options (including dhcp option and vendor option)
    586   //
    587   if (!PxeBcParseCachedDhcpPacket (CachedOffer)) {
    588     return ;
    589   }
    590 
    591   OfferType = CachedOffer->OfferType;
    592   if (OfferType >= DHCP4_PACKET_TYPE_MAX) {
    593     return ;
    594   }
    595 
    596   if (OfferType == DHCP4_PACKET_TYPE_BOOTP) {
    597 
    598     if (Private->BootpIndex != 0) {
    599       //
    600       // Only cache the first bootp offer, discard others.
    601       //
    602       return ;
    603     } else {
    604       //
    605       // Take as a dhcp only offer, but record index specifically.
    606       //
    607       Private->BootpIndex = Private->NumOffers + 1;
    608     }
    609   } else {
    610 
    611     if (IS_PROXY_DHCP_OFFER (Offer)) {
    612       //
    613       // It's a proxy dhcp offer with no your address, including pxe10, wfm11a or binl offer.
    614       //
    615       Private->GotProxyOffer = TRUE;
    616 
    617       if (OfferType == DHCP4_PACKET_TYPE_BINL) {
    618         //
    619         // Cache all binl offers.
    620         //
    621         Private->BinlIndex[Private->ProxyIndex[DHCP4_PACKET_TYPE_BINL]] = Private->NumOffers;
    622         Private->ProxyIndex[DHCP4_PACKET_TYPE_BINL]++;
    623       } else if (Private->ProxyIndex[OfferType] != 0) {
    624         //
    625         // Only cache the first pxe10/wfm11a offers each, discard the others.
    626         //
    627         return ;
    628       } else {
    629         //
    630         // Record index of the proxy dhcp offer with type other than binl.
    631         //
    632         Private->ProxyIndex[OfferType] = Private->NumOffers + 1;
    633       }
    634     } else {
    635       //
    636       // It's a dhcp offer with your address.
    637       //
    638       ASSERT (Private->ServerCount[OfferType] < PXEBC_MAX_OFFER_NUM);
    639       Private->OfferIndex[OfferType][Private->ServerCount[OfferType]] = Private->NumOffers;
    640       Private->ServerCount[OfferType]++;
    641     }
    642   }
    643 
    644   //
    645   // Count the accepted offers.
    646   //
    647   Private->NumOffers++;
    648 }
    649 
    650 /**
    651   Switch the Ip4 policy to static.
    652 
    653   @param[in]  Private             The pointer to PXEBC_PRIVATE_DATA.
    654 
    655   @retval     EFI_SUCCESS         The policy is already configured to static.
    656   @retval     Others              Other error as indicated..
    657 
    658 **/
    659 EFI_STATUS
    660 PxeBcSetIp4Policy (
    661   IN PXEBC_PRIVATE_DATA            *Private
    662   )
    663 {
    664   EFI_STATUS                   Status;
    665   EFI_IP4_CONFIG2_PROTOCOL     *Ip4Config2;
    666   EFI_IP4_CONFIG2_POLICY       Policy;
    667   UINTN                        DataSize;
    668 
    669   Ip4Config2 = Private->Ip4Config2;
    670   DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
    671   Status = Ip4Config2->GetData (
    672                        Ip4Config2,
    673                        Ip4Config2DataTypePolicy,
    674                        &DataSize,
    675                        &Policy
    676                        );
    677   if (EFI_ERROR (Status)) {
    678     return Status;
    679   }
    680 
    681   if (Policy != Ip4Config2PolicyStatic) {
    682     Policy = Ip4Config2PolicyStatic;
    683     Status= Ip4Config2->SetData (
    684                           Ip4Config2,
    685                           Ip4Config2DataTypePolicy,
    686                           sizeof (EFI_IP4_CONFIG2_POLICY),
    687                           &Policy
    688                           );
    689     if (EFI_ERROR (Status)) {
    690       return Status;
    691     }
    692   }
    693 
    694   return  EFI_SUCCESS;
    695 }
    696 
    697 
    698 /**
    699   Select the specified proxy offer, such as BINL, DHCP_ONLY and so on.
    700   If the proxy does not exist, try offers with bootfile.
    701 
    702   @param  Private   Pointer to PxeBc private data.
    703 
    704 **/
    705 VOID
    706 PxeBcSelectOffer (
    707   IN PXEBC_PRIVATE_DATA  *Private
    708   )
    709 {
    710   UINT32            Index;
    711   UINT32            OfferIndex;
    712   EFI_DHCP4_PACKET  *Offer;
    713 
    714   Private->SelectedOffer = 0;
    715 
    716   if (Private->SortOffers) {
    717     //
    718     // Select offer according to the priority
    719     //
    720     if (Private->ServerCount[DHCP4_PACKET_TYPE_PXE10] > 0) {
    721       //
    722       // DHCP with PXE10
    723       //
    724       Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_PXE10][0] + 1;
    725 
    726     } else if (Private->ServerCount[DHCP4_PACKET_TYPE_WFM11A] > 0) {
    727       //
    728       // DHCP with WfM
    729       //
    730       Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_WFM11A][0] + 1;
    731 
    732     } else if ((Private->ProxyIndex[DHCP4_PACKET_TYPE_PXE10] > 0) &&
    733              (Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY] > 0)
    734             ) {
    735       //
    736       // DHCP only and proxy DHCP with PXE10
    737       //
    738       Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][0] + 1;
    739       Private->ProxyOfferType     = DHCP4_PACKET_TYPE_PXE10;
    740 
    741     } else if ((Private->ProxyIndex[DHCP4_PACKET_TYPE_WFM11A] > 0) &&
    742              (Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY] > 0)
    743             ) {
    744       //
    745       // DHCP only and proxy DHCP with WfM
    746       //
    747       Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][0] + 1;
    748       Private->ProxyOfferType     = DHCP4_PACKET_TYPE_WFM11A;
    749 
    750     } else if (Private->ServerCount[DHCP4_PACKET_TYPE_BINL] > 0) {
    751       //
    752       // DHCP with BINL
    753       //
    754       Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_BINL][0] + 1;
    755 
    756     } else if ((Private->ProxyIndex[DHCP4_PACKET_TYPE_BINL] > 0) &&
    757              (Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY] > 0)
    758             ) {
    759       //
    760       // DHCP only and proxy DHCP with BINL
    761       //
    762       Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][0] + 1;
    763       Private->ProxyOfferType     = DHCP4_PACKET_TYPE_BINL;
    764 
    765     } else {
    766       //
    767       // Try offers with bootfile
    768       //
    769       for (Index = 0; Index < Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY]; Index++) {
    770         //
    771         // Select the first DHCP only offer with bootfile
    772         //
    773         OfferIndex = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][Index];
    774         if (Private->Dhcp4Offers[OfferIndex].Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
    775           Private->SelectedOffer = OfferIndex + 1;
    776           break;
    777         }
    778       }
    779 
    780       if (Private->SelectedOffer == 0) {
    781         //
    782         // Select the Bootp reply with bootfile if any
    783         //
    784         Private->SelectedOffer = Private->BootpIndex;
    785       }
    786     }
    787   } else {
    788     //
    789     // Try the offers in the received order.
    790     //
    791     for (Index = 0; Index < Private->NumOffers; Index++) {
    792 
    793       Offer = &Private->Dhcp4Offers[Index].Packet.Offer;
    794 
    795       if (IS_PROXY_DHCP_OFFER (Offer)) {
    796         //
    797         // Skip proxy offers
    798         //
    799         continue;
    800       }
    801 
    802       if ((Private->Dhcp4Offers[Index].OfferType == DHCP4_PACKET_TYPE_DHCP_ONLY) &&
    803           ((!Private->GotProxyOffer) && (Private->Dhcp4Offers[Index].Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL))) {
    804         //
    805         // DHCP only offer but no proxy offer received and no bootfile option in this offer
    806         //
    807         continue;
    808       }
    809 
    810       Private->SelectedOffer = Index + 1;
    811       break;
    812     }
    813   }
    814 }
    815 
    816 
    817 /**
    818   Callback routine.
    819 
    820   EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protocol driver
    821   to intercept events that occurred in the configuration process. This structure
    822   provides advanced control of each state transition of the DHCP process. The
    823   returned status code determines the behavior of the EFI DHCPv4 Protocol driver.
    824   There are three possible returned values, which are described in the following
    825   table.
    826 
    827   @param  This                  Pointer to the EFI DHCPv4 Protocol instance that is used to
    828                                 configure this callback function.
    829   @param  Context               Pointer to the context that is initialized by
    830                                 EFI_DHCP4_PROTOCOL.Configure().
    831   @param  CurrentState          The current operational state of the EFI DHCPv4 Protocol
    832                                 driver.
    833   @param  Dhcp4Event            The event that occurs in the current state, which usually means a
    834                                 state transition.
    835   @param  Packet                The DHCP packet that is going to be sent or already received.
    836   @param  NewPacket             The packet that is used to replace the above Packet.
    837 
    838   @retval EFI_SUCCESS           Tells the EFI DHCPv4 Protocol driver to continue the DHCP process.
    839   @retval EFI_NOT_READY         Only used in the Dhcp4Selecting state. The EFI DHCPv4 Protocol
    840                                 driver will continue to wait for more DHCPOFFER packets until the retry
    841                                 timeout expires.
    842   @retval EFI_ABORTED           Tells the EFI DHCPv4 Protocol driver to abort the current process and
    843                                 return to the Dhcp4Init or Dhcp4InitReboot state.
    844 
    845 **/
    846 EFI_STATUS
    847 EFIAPI
    848 PxeBcDhcpCallBack (
    849   IN EFI_DHCP4_PROTOCOL                * This,
    850   IN VOID                              *Context,
    851   IN EFI_DHCP4_STATE                   CurrentState,
    852   IN EFI_DHCP4_EVENT                   Dhcp4Event,
    853   IN EFI_DHCP4_PACKET                  * Packet OPTIONAL,
    854   OUT EFI_DHCP4_PACKET                 **NewPacket OPTIONAL
    855   )
    856 {
    857   PXEBC_PRIVATE_DATA                  *Private;
    858   EFI_PXE_BASE_CODE_MODE              *Mode;
    859   EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;
    860   EFI_DHCP4_PACKET_OPTION             *MaxMsgSize;
    861   UINT16                              Value;
    862   EFI_STATUS                          Status;
    863   BOOLEAN                             Received;
    864   EFI_DHCP4_HEADER                    *DhcpHeader;
    865 
    866   if ((Dhcp4Event != Dhcp4RcvdOffer) &&
    867       (Dhcp4Event != Dhcp4SelectOffer) &&
    868       (Dhcp4Event != Dhcp4SendDiscover) &&
    869       (Dhcp4Event != Dhcp4RcvdAck) &&
    870       (Dhcp4Event != Dhcp4SendRequest)) {
    871     return EFI_SUCCESS;
    872   }
    873 
    874   Private   = (PXEBC_PRIVATE_DATA *) Context;
    875   Mode      = Private->PxeBc.Mode;
    876   Callback  = Private->PxeBcCallback;
    877 
    878   //
    879   // Override the Maximum DHCP Message Size.
    880   //
    881   MaxMsgSize = PxeBcParseExtendOptions (
    882                 Packet->Dhcp4.Option,
    883                 GET_OPTION_BUFFER_LEN (Packet),
    884                 PXEBC_DHCP4_TAG_MAXMSG
    885                 );
    886   if (MaxMsgSize != NULL) {
    887     Value = HTONS (PXEBC_DHCP4_MAX_PACKET_SIZE);
    888     CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));
    889   }
    890 
    891   if ((Dhcp4Event != Dhcp4SelectOffer) && (Callback != NULL)) {
    892     Received = (BOOLEAN) ((Dhcp4Event == Dhcp4RcvdOffer) || (Dhcp4Event == Dhcp4RcvdAck));
    893     Status = Callback->Callback (
    894                         Callback,
    895                         Private->Function,
    896                         Received,
    897                         Packet->Length,
    898                         (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp4
    899                         );
    900     if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
    901       return EFI_ABORTED;
    902     }
    903   }
    904 
    905   Status = EFI_SUCCESS;
    906 
    907   switch (Dhcp4Event) {
    908 
    909   case Dhcp4SendDiscover:
    910   case Dhcp4SendRequest:
    911     if (Mode->SendGUID) {
    912       //
    913       // send the system GUID instead of the MAC address as the hardware address
    914       // in the DHCP packet header.
    915       //
    916       DhcpHeader = &Packet->Dhcp4.Header;
    917 
    918       if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) DhcpHeader->ClientHwAddr))) {
    919         //
    920         // GUID not yet set - send all 0xff's to show programable (via SetVariable)
    921         // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
    922         // GUID not yet set - send all 0's to show not programable
    923         //
    924         ZeroMem (DhcpHeader->ClientHwAddr, sizeof (EFI_GUID));
    925       }
    926 
    927       DhcpHeader->HwAddrLen = (UINT8) sizeof (EFI_GUID);
    928     }
    929 
    930     if (Dhcp4Event == Dhcp4SendDiscover) {
    931       //
    932       // Cache the dhcp discover packet, of which some information will be used later.
    933       //
    934       CopyMem (Mode->DhcpDiscover.Raw, &Packet->Dhcp4, Packet->Length);
    935     }
    936 
    937     break;
    938 
    939   case Dhcp4RcvdOffer:
    940     Status = EFI_NOT_READY;
    941     if (Private->NumOffers < PXEBC_MAX_OFFER_NUM) {
    942       //
    943       // Cache the dhcp offers in Private->Dhcp4Offers[]
    944       //
    945       PxeBcCacheDhcpOffer (Private, Packet);
    946     }
    947 
    948     break;
    949 
    950   case Dhcp4SelectOffer:
    951     //
    952     // Select an offer, if succeeded, Private->SelectedOffer points to
    953     // the index of the selected one.
    954     //
    955     PxeBcSelectOffer (Private);
    956 
    957     if (Private->SelectedOffer == 0) {
    958       Status = EFI_ABORTED;
    959     } else {
    960       *NewPacket = &Private->Dhcp4Offers[Private->SelectedOffer - 1].Packet.Offer;
    961     }
    962 
    963     break;
    964 
    965   case Dhcp4RcvdAck:
    966     //
    967     // Cache Ack
    968     //
    969     ASSERT (Private->SelectedOffer != 0);
    970 
    971     PxeBcCopyEfiDhcp4Packet (&Private->Dhcp4Ack.Packet.Ack, Packet);
    972     break;
    973 
    974   default:
    975     break;
    976   }
    977 
    978   return Status;
    979 }
    980 
    981 
    982 /**
    983   Initialize the DHCP options and build the option list.
    984 
    985   @param  Private          Pointer to PxeBc private data.
    986   @param  OptList          Pointer to a DHCP option list.
    987 
    988   @param  IsDhcpDiscover   Discover dhcp option or not.
    989 
    990   @return The index item number of the option list.
    991 
    992 **/
    993 UINT32
    994 PxeBcBuildDhcpOptions (
    995   IN PXEBC_PRIVATE_DATA            *Private,
    996   IN EFI_DHCP4_PACKET_OPTION       **OptList,
    997   IN BOOLEAN                       IsDhcpDiscover
    998   )
    999 {
   1000   UINT32                    Index;
   1001   PXEBC_DHCP4_OPTION_ENTRY  OptEnt;
   1002   UINT16                    Value;
   1003 
   1004   Index       = 0;
   1005   OptList[0]  = (EFI_DHCP4_PACKET_OPTION *) Private->OptionBuffer;
   1006 
   1007   if (!IsDhcpDiscover) {
   1008     //
   1009     // Append message type.
   1010     //
   1011     OptList[Index]->OpCode  = PXEBC_DHCP4_TAG_MSG_TYPE;
   1012     OptList[Index]->Length  = 1;
   1013     OptEnt.Mesg             = (PXEBC_DHCP4_OPTION_MESG *) OptList[Index]->Data;
   1014     OptEnt.Mesg->Type       = PXEBC_DHCP4_MSG_TYPE_REQUEST;
   1015     Index++;
   1016     OptList[Index]          = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
   1017 
   1018     //
   1019     // Append max message size.
   1020     //
   1021     OptList[Index]->OpCode  = PXEBC_DHCP4_TAG_MAXMSG;
   1022     OptList[Index]->Length  = (UINT8) sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE);
   1023     OptEnt.MaxMesgSize      = (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE *) OptList[Index]->Data;
   1024     Value                   = NTOHS (PXEBC_DHCP4_MAX_PACKET_SIZE);
   1025     CopyMem (&OptEnt.MaxMesgSize->Size, &Value, sizeof (UINT16));
   1026     Index++;
   1027     OptList[Index]          = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
   1028   }
   1029   //
   1030   // Parameter request list option.
   1031   //
   1032   OptList[Index]->OpCode    = PXEBC_DHCP4_TAG_PARA_LIST;
   1033   OptList[Index]->Length    = 35;
   1034   OptEnt.Para               = (PXEBC_DHCP4_OPTION_PARA *) OptList[Index]->Data;
   1035   OptEnt.Para->ParaList[0]  = PXEBC_DHCP4_TAG_NETMASK;
   1036   OptEnt.Para->ParaList[1]  = PXEBC_DHCP4_TAG_TIME_OFFSET;
   1037   OptEnt.Para->ParaList[2]  = PXEBC_DHCP4_TAG_ROUTER;
   1038   OptEnt.Para->ParaList[3]  = PXEBC_DHCP4_TAG_TIME_SERVER;
   1039   OptEnt.Para->ParaList[4]  = PXEBC_DHCP4_TAG_NAME_SERVER;
   1040   OptEnt.Para->ParaList[5]  = PXEBC_DHCP4_TAG_DNS_SERVER;
   1041   OptEnt.Para->ParaList[6]  = PXEBC_DHCP4_TAG_HOSTNAME;
   1042   OptEnt.Para->ParaList[7]  = PXEBC_DHCP4_TAG_BOOTFILE_LEN;
   1043   OptEnt.Para->ParaList[8]  = PXEBC_DHCP4_TAG_DOMAINNAME;
   1044   OptEnt.Para->ParaList[9]  = PXEBC_DHCP4_TAG_ROOTPATH;
   1045   OptEnt.Para->ParaList[10] = PXEBC_DHCP4_TAG_EXTEND_PATH;
   1046   OptEnt.Para->ParaList[11] = PXEBC_DHCP4_TAG_EMTU;
   1047   OptEnt.Para->ParaList[12] = PXEBC_DHCP4_TAG_TTL;
   1048   OptEnt.Para->ParaList[13] = PXEBC_DHCP4_TAG_BROADCAST;
   1049   OptEnt.Para->ParaList[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN;
   1050   OptEnt.Para->ParaList[15] = PXEBC_DHCP4_TAG_NIS_SERVER;
   1051   OptEnt.Para->ParaList[16] = PXEBC_DHCP4_TAG_NTP_SERVER;
   1052   OptEnt.Para->ParaList[17] = PXEBC_DHCP4_TAG_VENDOR;
   1053   OptEnt.Para->ParaList[18] = PXEBC_DHCP4_TAG_REQUEST_IP;
   1054   OptEnt.Para->ParaList[19] = PXEBC_DHCP4_TAG_LEASE;
   1055   OptEnt.Para->ParaList[20] = PXEBC_DHCP4_TAG_SERVER_ID;
   1056   OptEnt.Para->ParaList[21] = PXEBC_DHCP4_TAG_T1;
   1057   OptEnt.Para->ParaList[22] = PXEBC_DHCP4_TAG_T2;
   1058   OptEnt.Para->ParaList[23] = PXEBC_DHCP4_TAG_CLASS_ID;
   1059   OptEnt.Para->ParaList[24] = PXEBC_DHCP4_TAG_TFTP;
   1060   OptEnt.Para->ParaList[25] = PXEBC_DHCP4_TAG_BOOTFILE;
   1061   OptEnt.Para->ParaList[26] = PXEBC_PXE_DHCP4_TAG_UUID;
   1062   OptEnt.Para->ParaList[27] = 0x80;
   1063   OptEnt.Para->ParaList[28] = 0x81;
   1064   OptEnt.Para->ParaList[29] = 0x82;
   1065   OptEnt.Para->ParaList[30] = 0x83;
   1066   OptEnt.Para->ParaList[31] = 0x84;
   1067   OptEnt.Para->ParaList[32] = 0x85;
   1068   OptEnt.Para->ParaList[33] = 0x86;
   1069   OptEnt.Para->ParaList[34] = 0x87;
   1070   Index++;
   1071   OptList[Index]            = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
   1072 
   1073   //
   1074   // Append UUID/Guid-based client identifier option
   1075   //
   1076   OptList[Index]->OpCode  = PXEBC_PXE_DHCP4_TAG_UUID;
   1077   OptList[Index]->Length  = (UINT8) sizeof (PXEBC_DHCP4_OPTION_UUID);
   1078   OptEnt.Uuid             = (PXEBC_DHCP4_OPTION_UUID *) OptList[Index]->Data;
   1079   OptEnt.Uuid->Type       = 0;
   1080   Index++;
   1081   OptList[Index]          = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
   1082 
   1083   if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) OptEnt.Uuid->Guid))) {
   1084     //
   1085     // GUID not yet set - send all 0xff's to show programable (via SetVariable)
   1086     // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);
   1087     // GUID not yet set - send all 0's to show not programable
   1088     //
   1089     ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));
   1090   }
   1091 
   1092   //
   1093   // Append client network device interface option
   1094   //
   1095   OptList[Index]->OpCode  = PXEBC_PXE_DHCP4_TAG_UNDI;
   1096   OptList[Index]->Length  = (UINT8) sizeof (PXEBC_DHCP4_OPTION_UNDI);
   1097   OptEnt.Undi             = (PXEBC_DHCP4_OPTION_UNDI *) OptList[Index]->Data;
   1098   if (Private->Nii != NULL) {
   1099     OptEnt.Undi->Type       = Private->Nii->Type;
   1100     OptEnt.Undi->MajorVer   = Private->Nii->MajorVer;
   1101     OptEnt.Undi->MinorVer   = Private->Nii->MinorVer;
   1102   } else {
   1103     OptEnt.Undi->Type       = DEFAULT_UNDI_TYPE;
   1104     OptEnt.Undi->MajorVer   = DEFAULT_UNDI_MAJOR;
   1105     OptEnt.Undi->MinorVer   = DEFAULT_UNDI_MINOR;
   1106   }
   1107 
   1108   Index++;
   1109   OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
   1110 
   1111   //
   1112   // Append client system architecture option
   1113   //
   1114   OptList[Index]->OpCode  = PXEBC_PXE_DHCP4_TAG_ARCH;
   1115   OptList[Index]->Length  = (UINT8) sizeof (PXEBC_DHCP4_OPTION_ARCH);
   1116   OptEnt.Arch             = (PXEBC_DHCP4_OPTION_ARCH *) OptList[Index]->Data;
   1117   Value                   = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE);
   1118   CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));
   1119   Index++;
   1120   OptList[Index]          = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);
   1121 
   1122   //
   1123   // Append client system architecture option
   1124   //
   1125   OptList[Index]->OpCode  = PXEBC_DHCP4_TAG_CLASS_ID;
   1126   OptList[Index]->Length  = (UINT8) sizeof (PXEBC_DHCP4_OPTION_CLID);
   1127   OptEnt.Clid             = (PXEBC_DHCP4_OPTION_CLID *) OptList[Index]->Data;
   1128   CopyMem (OptEnt.Clid, DEFAULT_CLASS_ID_DATA, sizeof (PXEBC_DHCP4_OPTION_CLID));
   1129   CvtNum (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE, OptEnt.Clid->ArchitectureType, sizeof (OptEnt.Clid->ArchitectureType));
   1130 
   1131   if (Private->Nii != NULL) {
   1132     //
   1133     // If NII protocol exists, update DHCP option data
   1134     //
   1135     CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));
   1136     CvtNum (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));
   1137     CvtNum (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));
   1138   }
   1139 
   1140   Index++;
   1141 
   1142   return Index;
   1143 }
   1144 
   1145 
   1146 /**
   1147   Discover the boot of service and initialize the vendor option if exists.
   1148 
   1149   @param  Private               Pointer to PxeBc private data.
   1150   @param  Type                  PxeBc option boot item type
   1151   @param  Layer                 PxeBc option boot item layer
   1152   @param  UseBis                Use BIS or not
   1153   @param  DestIp                Ip address for server
   1154   @param  IpCount               The total count of the server ip address
   1155   @param  SrvList               Server list
   1156   @param  IsDiscv               Discover the vendor or not
   1157   @param  Reply                 The dhcp4 packet of Pxe reply
   1158 
   1159   @retval EFI_SUCCESS           Operation succeeds.
   1160   @retval EFI_OUT_OF_RESOURCES  Allocate memory pool failed.
   1161   @retval EFI_NOT_FOUND         There is no vendor option exists.
   1162   @retval EFI_TIMEOUT           Send Pxe Discover time out.
   1163 
   1164 **/
   1165 EFI_STATUS
   1166 PxeBcDiscvBootService (
   1167   IN PXEBC_PRIVATE_DATA                * Private,
   1168   IN UINT16                            Type,
   1169   IN UINT16                            *Layer,
   1170   IN BOOLEAN                           UseBis,
   1171   IN EFI_IP_ADDRESS                    * DestIp,
   1172   IN UINT16                            IpCount,
   1173   IN EFI_PXE_BASE_CODE_SRVLIST         * SrvList,
   1174   IN BOOLEAN                           IsDiscv,
   1175   OUT EFI_DHCP4_PACKET                 * Reply OPTIONAL
   1176   )
   1177 {
   1178   EFI_PXE_BASE_CODE_UDP_PORT          Sport;
   1179   EFI_PXE_BASE_CODE_MODE              *Mode;
   1180   EFI_DHCP4_PROTOCOL                  *Dhcp4;
   1181   EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN    Token;
   1182   BOOLEAN                             IsBCast;
   1183   EFI_STATUS                          Status;
   1184   UINT16                              RepIndex;
   1185   UINT16                              SrvIndex;
   1186   UINT16                              TryIndex;
   1187   EFI_DHCP4_LISTEN_POINT              ListenPoint;
   1188   EFI_DHCP4_PACKET                    *Response;
   1189   EFI_DHCP4_PACKET_OPTION             *OptList[PXEBC_DHCP4_MAX_OPTION_NUM];
   1190   UINT32                              OptCount;
   1191   EFI_DHCP4_PACKET_OPTION             *PxeOpt;
   1192   PXEBC_OPTION_BOOT_ITEM              *PxeBootItem;
   1193   UINT8                               VendorOptLen;
   1194   EFI_DHCP4_HEADER                    *DhcpHeader;
   1195   UINT32                              Xid;
   1196 
   1197   Mode      = Private->PxeBc.Mode;
   1198   Dhcp4     = Private->Dhcp4;
   1199   Status    = EFI_SUCCESS;
   1200 
   1201   ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));
   1202 
   1203   if (DestIp == NULL) {
   1204     Sport   = PXEBC_DHCP4_S_PORT;
   1205     IsBCast = TRUE;
   1206   } else {
   1207     Sport   = PXEBC_BS_DISCOVER_PORT;
   1208     IsBCast = FALSE;
   1209   }
   1210 
   1211   if (!UseBis && Layer != NULL) {
   1212     *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;
   1213   }
   1214 
   1215   OptCount = PxeBcBuildDhcpOptions (Private, OptList, FALSE);
   1216 
   1217   if (IsDiscv) {
   1218     ASSERT (Layer != NULL);
   1219     //
   1220     // Add vendor option of PXE_BOOT_ITEM
   1221     //
   1222     VendorOptLen = (UINT8) ((sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1);
   1223     OptList[OptCount] = AllocatePool (VendorOptLen);
   1224     if (OptList[OptCount] == NULL) {
   1225       return EFI_OUT_OF_RESOURCES;
   1226     }
   1227 
   1228     OptList[OptCount]->OpCode     = PXEBC_DHCP4_TAG_VENDOR;
   1229     OptList[OptCount]->Length     = (UINT8) (VendorOptLen - 2);
   1230     PxeOpt                        = (EFI_DHCP4_PACKET_OPTION *) OptList[OptCount]->Data;
   1231     PxeOpt->OpCode                = PXEBC_VENDOR_TAG_BOOT_ITEM;
   1232     PxeOpt->Length                = (UINT8) sizeof (PXEBC_OPTION_BOOT_ITEM);
   1233     PxeBootItem                   = (PXEBC_OPTION_BOOT_ITEM *) PxeOpt->Data;
   1234     PxeBootItem->Type             = HTONS (Type);
   1235     PxeBootItem->Layer            = HTONS (*Layer);
   1236     PxeOpt->Data[PxeOpt->Length]  = PXEBC_DHCP4_TAG_EOP;
   1237 
   1238     OptCount++;
   1239   }
   1240 
   1241   Status = Dhcp4->Build (Dhcp4, &Private->SeedPacket, 0, NULL, OptCount, OptList, &Token.Packet);
   1242 
   1243   if (IsDiscv) {
   1244     FreePool (OptList[OptCount - 1]);
   1245   }
   1246 
   1247   if (EFI_ERROR (Status)) {
   1248     return Status;
   1249   }
   1250 
   1251   DhcpHeader = &Token.Packet->Dhcp4.Header;
   1252   if (Mode->SendGUID) {
   1253     if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) DhcpHeader->ClientHwAddr))) {
   1254       //
   1255       // GUID not yet set - send all 0's to show not programable
   1256       //
   1257       ZeroMem (DhcpHeader->ClientHwAddr, sizeof (EFI_GUID));
   1258     }
   1259 
   1260     DhcpHeader->HwAddrLen = (UINT8) sizeof (EFI_GUID);
   1261   }
   1262 
   1263   Xid                                 = NET_RANDOM (NetRandomInitSeed ());
   1264   Token.Packet->Dhcp4.Header.Xid      = HTONL(Xid);
   1265   Token.Packet->Dhcp4.Header.Reserved = HTONS((UINT16) ((IsBCast) ? 0x8000 : 0));
   1266   CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
   1267 
   1268   Token.RemotePort = Sport;
   1269 
   1270   if (IsBCast) {
   1271     SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);
   1272   } else {
   1273     CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));
   1274   }
   1275 
   1276   CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));
   1277 
   1278   if (!IsBCast) {
   1279     Token.ListenPointCount            = 1;
   1280     Token.ListenPoints                = &ListenPoint;
   1281     Token.ListenPoints[0].ListenPort  = PXEBC_BS_DISCOVER_PORT;
   1282     CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof(EFI_IPv4_ADDRESS));
   1283     CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof(EFI_IPv4_ADDRESS));
   1284   }
   1285   //
   1286   // Send Pxe Discover
   1287   //
   1288   for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) {
   1289 
   1290     Token.TimeoutValue                  = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex);
   1291     Token.Packet->Dhcp4.Header.Seconds  = (UINT16) (PXEBC_BOOT_REQUEST_TIMEOUT * (TryIndex - 1));
   1292 
   1293     Status              = Dhcp4->TransmitReceive (Dhcp4, &Token);
   1294 
   1295     if (Token.Status != EFI_TIMEOUT) {
   1296       break;
   1297     }
   1298   }
   1299 
   1300   if (TryIndex > PXEBC_BOOT_REQUEST_RETRIES) {
   1301     //
   1302     // No server response our PXE request
   1303     //
   1304     Status = EFI_TIMEOUT;
   1305   }
   1306 
   1307   if (!EFI_ERROR (Status)) {
   1308     //
   1309     // Find Pxe Reply
   1310     //
   1311     RepIndex  = 0;
   1312     SrvIndex  = 0;
   1313     Response  = Token.ResponseList;
   1314 
   1315     while (RepIndex < Token.ResponseCount) {
   1316 
   1317       while (SrvIndex < IpCount) {
   1318 
   1319         if (SrvList[SrvIndex].AcceptAnyResponse) {
   1320           break;
   1321         }
   1322 
   1323         if ((SrvList[SrvIndex].Type == Type) && EFI_IP4_EQUAL (&(Response->Dhcp4.Header.ServerAddr), &(Private->ServerIp))) {
   1324           break;
   1325         }
   1326 
   1327         SrvIndex++;
   1328       }
   1329 
   1330       if ((IpCount != SrvIndex) || (IpCount == 0)) {
   1331         break;
   1332       }
   1333 
   1334       SrvIndex = 0;
   1335       RepIndex++;
   1336 
   1337       Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size);
   1338     }
   1339 
   1340     if (RepIndex < Token.ResponseCount) {
   1341 
   1342       if (Reply != NULL) {
   1343         PxeBcCopyEfiDhcp4Packet (Reply, Response);
   1344       }
   1345 
   1346       if (IsDiscv) {
   1347         CopyMem (&(Mode->PxeDiscover), &(Token.Packet->Dhcp4), Token.Packet->Length);
   1348         Mode->PxeDiscoverValid = TRUE;
   1349 
   1350         CopyMem (Mode->PxeReply.Raw, &Response->Dhcp4, Response->Length);
   1351         Mode->PxeReplyReceived = TRUE;
   1352       }
   1353     } else {
   1354       Status = EFI_NOT_FOUND;
   1355     }
   1356 
   1357     //
   1358     // free the responselist
   1359     //
   1360     if (Token.ResponseList != NULL) {
   1361       FreePool (Token.ResponseList);
   1362     }
   1363   }
   1364   //
   1365   // Free the dhcp packet
   1366   //
   1367   FreePool (Token.Packet);
   1368 
   1369   return Status;
   1370 }
   1371 
   1372 
   1373 /**
   1374   Parse interested dhcp options.
   1375 
   1376   @param  Buffer     Pointer to the dhcp options packet.
   1377   @param  Length     The length of the dhcp options.
   1378   @param  OptTag     The option OpCode.
   1379 
   1380   @return NULL if the buffer length is 0 and OpCode is not
   1381           PXEBC_DHCP4_TAG_EOP, or the pointer to the buffer.
   1382 
   1383 **/
   1384 EFI_DHCP4_PACKET_OPTION *
   1385 PxeBcParseExtendOptions (
   1386   IN UINT8                         *Buffer,
   1387   IN UINT32                        Length,
   1388   IN UINT8                         OptTag
   1389   )
   1390 {
   1391   EFI_DHCP4_PACKET_OPTION *Option;
   1392   UINT32                  Offset;
   1393 
   1394   Option  = (EFI_DHCP4_PACKET_OPTION *) Buffer;
   1395   Offset  = 0;
   1396 
   1397   while (Offset < Length && Option->OpCode != PXEBC_DHCP4_TAG_EOP) {
   1398 
   1399     if (Option->OpCode == OptTag) {
   1400 
   1401       return Option;
   1402     }
   1403 
   1404     if (Option->OpCode == PXEBC_DHCP4_TAG_PAD) {
   1405       Offset++;
   1406     } else {
   1407       Offset += Option->Length + 2;
   1408     }
   1409 
   1410     Option = (EFI_DHCP4_PACKET_OPTION *) (Buffer + Offset);
   1411   }
   1412 
   1413   return NULL;
   1414 }
   1415 
   1416 
   1417 /**
   1418   This function is to parse and check vendor options.
   1419 
   1420   @param  Dhcp4Option           Pointer to dhcp options
   1421   @param  VendorOption          Pointer to vendor options
   1422 
   1423   @return TRUE if valid for vendor options, or FALSE.
   1424 
   1425 **/
   1426 BOOLEAN
   1427 PxeBcParseVendorOptions (
   1428   IN EFI_DHCP4_PACKET_OPTION       *Dhcp4Option,
   1429   IN PXEBC_VENDOR_OPTION           *VendorOption
   1430   )
   1431 {
   1432   UINT32                  *BitMap;
   1433   UINT8                   VendorOptionLen;
   1434   EFI_DHCP4_PACKET_OPTION *PxeOption;
   1435   UINT8                   Offset;
   1436 
   1437   BitMap          = VendorOption->BitMap;
   1438   VendorOptionLen = Dhcp4Option->Length;
   1439   PxeOption       = (EFI_DHCP4_PACKET_OPTION *) &Dhcp4Option->Data[0];
   1440   Offset          = 0;
   1441 
   1442   while ((Offset < VendorOptionLen) && (PxeOption->OpCode != PXEBC_DHCP4_TAG_EOP)) {
   1443     //
   1444     // Parse every Vendor Option and set its BitMap
   1445     //
   1446     switch (PxeOption->OpCode) {
   1447 
   1448     case PXEBC_VENDOR_TAG_MTFTP_IP:
   1449 
   1450       CopyMem (&VendorOption->MtftpIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
   1451       break;
   1452 
   1453     case PXEBC_VENDOR_TAG_MTFTP_CPORT:
   1454 
   1455       CopyMem (&VendorOption->MtftpCPort, PxeOption->Data, sizeof (VendorOption->MtftpCPort));
   1456       break;
   1457 
   1458     case PXEBC_VENDOR_TAG_MTFTP_SPORT:
   1459 
   1460       CopyMem (&VendorOption->MtftpSPort, PxeOption->Data, sizeof (VendorOption->MtftpSPort));
   1461       break;
   1462 
   1463     case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT:
   1464 
   1465       VendorOption->MtftpTimeout = *PxeOption->Data;
   1466       break;
   1467 
   1468     case PXEBC_VENDOR_TAG_MTFTP_DELAY:
   1469 
   1470       VendorOption->MtftpDelay = *PxeOption->Data;
   1471       break;
   1472 
   1473     case PXEBC_VENDOR_TAG_DISCOVER_CTRL:
   1474 
   1475       VendorOption->DiscoverCtrl = *PxeOption->Data;
   1476       break;
   1477 
   1478     case PXEBC_VENDOR_TAG_DISCOVER_MCAST:
   1479 
   1480       CopyMem (&VendorOption->DiscoverMcastIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
   1481       break;
   1482 
   1483     case PXEBC_VENDOR_TAG_BOOT_SERVERS:
   1484 
   1485       VendorOption->BootSvrLen  = PxeOption->Length;
   1486       VendorOption->BootSvr     = (PXEBC_BOOT_SVR_ENTRY *) PxeOption->Data;
   1487       break;
   1488 
   1489     case PXEBC_VENDOR_TAG_BOOT_MENU:
   1490 
   1491       VendorOption->BootMenuLen = PxeOption->Length;
   1492       VendorOption->BootMenu    = (PXEBC_BOOT_MENU_ENTRY *) PxeOption->Data;
   1493       break;
   1494 
   1495     case PXEBC_VENDOR_TAG_MENU_PROMPT:
   1496 
   1497       VendorOption->MenuPromptLen = PxeOption->Length;
   1498       VendorOption->MenuPrompt    = (PXEBC_MENU_PROMPT *) PxeOption->Data;
   1499       break;
   1500 
   1501     case PXEBC_VENDOR_TAG_MCAST_ALLOC:
   1502 
   1503       CopyMem (&VendorOption->McastIpBase, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));
   1504       CopyMem (&VendorOption->McastIpBlock, PxeOption->Data + 4, sizeof (VendorOption->McastIpBlock));
   1505       CopyMem (&VendorOption->McastIpRange, PxeOption->Data + 6, sizeof (VendorOption->McastIpRange));
   1506       break;
   1507 
   1508     case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES:
   1509 
   1510       VendorOption->CredTypeLen = PxeOption->Length;
   1511       VendorOption->CredType    = (UINT32 *) PxeOption->Data;
   1512       break;
   1513 
   1514     case PXEBC_VENDOR_TAG_BOOT_ITEM:
   1515 
   1516       CopyMem (&VendorOption->BootSrvType, PxeOption->Data, sizeof (VendorOption->BootSrvType));
   1517       CopyMem (&VendorOption->BootSrvLayer, PxeOption->Data + 2, sizeof (VendorOption->BootSrvLayer));
   1518       break;
   1519     }
   1520 
   1521     SET_VENDOR_OPTION_BIT_MAP (BitMap, PxeOption->OpCode);
   1522 
   1523     if (PxeOption->OpCode == PXEBC_DHCP4_TAG_PAD) {
   1524       Offset++;
   1525     } else {
   1526       Offset = (UINT8) (Offset + PxeOption->Length + 2);
   1527     }
   1528 
   1529     PxeOption = (EFI_DHCP4_PACKET_OPTION *) (Dhcp4Option->Data + Offset);
   1530   }
   1531 
   1532   //
   1533   // FixMe, return falas if invalid of any vendor option
   1534   //
   1535 
   1536   return TRUE;
   1537 }
   1538 
   1539 
   1540 /**
   1541   This function display boot item detail.
   1542 
   1543   If the length of the boot item string over 70 Char, just display 70 Char.
   1544 
   1545   @param  Str     Pointer to a string (boot item string).
   1546   @param  Len     The length of string.
   1547 
   1548 **/
   1549 VOID
   1550 PxeBcDisplayBootItem (
   1551   IN UINT8                 *Str,
   1552   IN UINT8                 Len
   1553   )
   1554 {
   1555   UINT8 Tmp;
   1556 
   1557   Len       = (UINT8) MIN (70, Len);
   1558   Tmp       = Str[Len];
   1559   Str[Len]  = 0;
   1560   AsciiPrint ("%a \n", Str);
   1561   Str[Len] = Tmp;
   1562 }
   1563 
   1564 
   1565 /**
   1566   Choose the boot prompt.
   1567 
   1568   @param  Private              Pointer to PxeBc private data.
   1569 
   1570   @retval EFI_SUCCESS          Select boot prompt done.
   1571   @retval EFI_TIMEOUT          Select boot prompt time out.
   1572   @retval EFI_NOT_FOUND        The proxy offer is not Pxe10.
   1573   @retval EFI_ABORTED          User cancel the operation.
   1574   @retval EFI_NOT_READY        Read the input key from the keybroad has not finish.
   1575 
   1576 **/
   1577 EFI_STATUS
   1578 PxeBcSelectBootPrompt (
   1579   IN PXEBC_PRIVATE_DATA              *Private
   1580   )
   1581 {
   1582   PXEBC_CACHED_DHCP4_PACKET  *Packet;
   1583   PXEBC_VENDOR_OPTION       *VendorOpt;
   1584   EFI_EVENT                  TimeoutEvent;
   1585   EFI_EVENT                  DescendEvent;
   1586   EFI_INPUT_KEY              InputKey;
   1587   EFI_STATUS                 Status;
   1588   UINT8                      Timeout;
   1589   UINT8                      *Prompt;
   1590   UINT8                      PromptLen;
   1591   INT32                      SecCol;
   1592   INT32                      SecRow;
   1593 
   1594   TimeoutEvent  = NULL;
   1595   DescendEvent  = NULL;
   1596 
   1597   if (Private->PxeBc.Mode->ProxyOfferReceived) {
   1598 
   1599     Packet  = &Private->ProxyOffer;
   1600   } else {
   1601 
   1602     Packet  = &Private->Dhcp4Ack;
   1603   }
   1604 
   1605   if (Packet->OfferType != DHCP4_PACKET_TYPE_PXE10) {
   1606     return EFI_NOT_FOUND;
   1607   }
   1608 
   1609   VendorOpt = &Packet->PxeVendorOption;
   1610   //
   1611   // According to the PXE specification 2.1, Table 2-1 PXE DHCP Options  (Full
   1612   // List), we must not consider a boot prompt or boot menu if all of the
   1613   // following hold:
   1614   // - the PXE_DISCOVERY_CONTROL PXE tag is present inside the Vendor Options
   1615   //   (=43) DHCP tag, and
   1616   // - the PXE_DISCOVERY_CONTROL PXE tag has bit 3 set, and
   1617   // - a boot file name has been presented with DHCP option 67.
   1618   //
   1619   if (IS_DISABLE_PROMPT_MENU (VendorOpt->DiscoverCtrl) &&
   1620       Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {
   1621     return EFI_ABORTED;
   1622   }
   1623 
   1624   if (!IS_VALID_BOOT_PROMPT (VendorOpt->BitMap)) {
   1625     return EFI_SUCCESS;
   1626   }
   1627 
   1628   Timeout   = VendorOpt->MenuPrompt->Timeout;
   1629   Prompt    = VendorOpt->MenuPrompt->Prompt;
   1630   PromptLen = (UINT8) (VendorOpt->MenuPromptLen - 1);
   1631 
   1632   if (Timeout == 0) {
   1633     return EFI_SUCCESS;
   1634   }
   1635 
   1636   if (Timeout == 255) {
   1637     return EFI_TIMEOUT;
   1638   }
   1639 
   1640   Status = gBS->CreateEvent (
   1641                   EVT_TIMER,
   1642                   TPL_CALLBACK,
   1643                   NULL,
   1644                   NULL,
   1645                   &TimeoutEvent
   1646                   );
   1647 
   1648   if (EFI_ERROR (Status)) {
   1649     return Status;
   1650   }
   1651 
   1652   Status = gBS->SetTimer (
   1653                   TimeoutEvent,
   1654                   TimerRelative,
   1655                   Timeout * TICKS_PER_SECOND
   1656                   );
   1657 
   1658   if (EFI_ERROR (Status)) {
   1659     goto ON_EXIT;
   1660   }
   1661 
   1662   Status = gBS->CreateEvent (
   1663                   EVT_TIMER,
   1664                   TPL_CALLBACK,
   1665                   NULL,
   1666                   NULL,
   1667                   &DescendEvent
   1668                   );
   1669 
   1670   if (EFI_ERROR (Status)) {
   1671     goto ON_EXIT;
   1672   }
   1673 
   1674   Status = gBS->SetTimer (
   1675                   DescendEvent,
   1676                   TimerPeriodic,
   1677                   TICKS_PER_SECOND
   1678                   );
   1679 
   1680   if (EFI_ERROR (Status)) {
   1681     goto ON_EXIT;
   1682   }
   1683 
   1684   SecCol = gST->ConOut->Mode->CursorColumn;
   1685   SecRow = gST->ConOut->Mode->CursorRow;
   1686 
   1687   PxeBcDisplayBootItem (Prompt, PromptLen);
   1688 
   1689   gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);
   1690   AsciiPrint ("(%d) ", Timeout--);
   1691 
   1692   while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
   1693 
   1694     if (!EFI_ERROR (gBS->CheckEvent (DescendEvent))) {
   1695       gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);
   1696       AsciiPrint ("(%d) ", Timeout--);
   1697     }
   1698 
   1699     if (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {
   1700 
   1701       gBS->Stall (10 * TICKS_PER_MS);
   1702       continue;
   1703     }
   1704 
   1705     if (InputKey.ScanCode == 0) {
   1706 
   1707       switch (InputKey.UnicodeChar) {
   1708       case CTRL ('c'):
   1709         Status = EFI_ABORTED;
   1710         break;
   1711 
   1712       case CTRL ('m'):
   1713       case 'm':
   1714       case 'M':
   1715         Status = EFI_TIMEOUT;
   1716         break;
   1717 
   1718       default:
   1719         continue;
   1720       }
   1721     } else {
   1722 
   1723       switch (InputKey.ScanCode) {
   1724       case SCAN_F8:
   1725         Status = EFI_TIMEOUT;
   1726         break;
   1727 
   1728       case SCAN_ESC:
   1729         Status = EFI_ABORTED;
   1730         break;
   1731 
   1732       default:
   1733         continue;
   1734       }
   1735     }
   1736 
   1737     break;
   1738   }
   1739 
   1740   gST->ConOut->SetCursorPosition (gST->ConOut, 0 , SecRow + 1);
   1741 
   1742 ON_EXIT:
   1743 
   1744   if (DescendEvent != NULL) {
   1745     gBS->CloseEvent (DescendEvent);
   1746   }
   1747 
   1748   if (TimeoutEvent != NULL) {
   1749     gBS->CloseEvent (TimeoutEvent);
   1750   }
   1751 
   1752   return Status;
   1753 }
   1754 
   1755 
   1756 /**
   1757   Select the boot menu.
   1758 
   1759   @param  Private         Pointer to PxeBc private data.
   1760   @param  Type            The type of the menu.
   1761   @param  UseDefaultItem  Use default item or not.
   1762 
   1763   @retval EFI_ABORTED     User cancel operation.
   1764   @retval EFI_SUCCESS     Select the boot menu success.
   1765   @retval EFI_NOT_READY   Read the input key from the keybroad has not finish.
   1766 
   1767 **/
   1768 EFI_STATUS
   1769 PxeBcSelectBootMenu (
   1770   IN  PXEBC_PRIVATE_DATA              *Private,
   1771   OUT UINT16                          *Type,
   1772   IN  BOOLEAN                         UseDefaultItem
   1773   )
   1774 {
   1775   PXEBC_CACHED_DHCP4_PACKET  *Packet;
   1776   PXEBC_VENDOR_OPTION        *VendorOpt;
   1777   EFI_INPUT_KEY              InputKey;
   1778   UINT8                      MenuSize;
   1779   UINT8                      MenuNum;
   1780   INT32                      TopRow;
   1781   UINT16                     Select;
   1782   UINT16                     LastSelect;
   1783   UINT8                      Index;
   1784   BOOLEAN                    Finish;
   1785   CHAR8                      Blank[70];
   1786   PXEBC_BOOT_MENU_ENTRY      *MenuItem;
   1787   PXEBC_BOOT_MENU_ENTRY      *MenuArray[PXEBC_MAX_MENU_NUM];
   1788 
   1789   Finish  = FALSE;
   1790   Select  = 1;
   1791   Index   = 0;
   1792   *Type   = 0;
   1793 
   1794   if (Private->PxeBc.Mode->ProxyOfferReceived) {
   1795 
   1796     Packet  = &Private->ProxyOffer;
   1797   } else {
   1798 
   1799     Packet  = &Private->Dhcp4Ack;
   1800   }
   1801 
   1802   ASSERT (Packet->OfferType == DHCP4_PACKET_TYPE_PXE10);
   1803 
   1804   VendorOpt = &Packet->PxeVendorOption;
   1805 
   1806   if (!IS_VALID_BOOT_MENU (VendorOpt->BitMap)) {
   1807     return EFI_SUCCESS;
   1808   }
   1809 
   1810   SetMem (Blank, sizeof(Blank), ' ');
   1811 
   1812   MenuSize  = VendorOpt->BootMenuLen;
   1813   MenuItem  = VendorOpt->BootMenu;
   1814 
   1815   if (MenuSize == 0) {
   1816     return EFI_NOT_READY;
   1817   }
   1818 
   1819   while (MenuSize > 0) {
   1820     MenuArray[Index++]  = MenuItem;
   1821     MenuSize          = (UINT8) (MenuSize - (MenuItem->DescLen + 3));
   1822     MenuItem          = (PXEBC_BOOT_MENU_ENTRY *) ((UINT8 *) MenuItem + MenuItem->DescLen + 3);
   1823     if (Index >= PXEBC_MAX_MENU_NUM) {
   1824       break;
   1825     }
   1826   }
   1827 
   1828   if (UseDefaultItem) {
   1829     *Type = MenuArray[0]->Type;
   1830     *Type = NTOHS (*Type);
   1831     return EFI_SUCCESS;
   1832   }
   1833 
   1834   MenuNum = Index;
   1835 
   1836   for (Index = 0; Index < MenuNum; Index++) {
   1837     PxeBcDisplayBootItem (MenuArray[Index]->DescStr, MenuArray[Index]->DescLen);
   1838   }
   1839 
   1840   TopRow  = gST->ConOut->Mode->CursorRow - MenuNum;
   1841 
   1842   do {
   1843     ASSERT (Select < PXEBC_MAX_MENU_NUM);
   1844     //
   1845     // highlight selected row
   1846     //
   1847     gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
   1848     gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Select);
   1849     Blank[MenuArray[Select]->DescLen] = 0;
   1850     AsciiPrint ("%a\r", Blank);
   1851     PxeBcDisplayBootItem (MenuArray[Select]->DescStr, MenuArray[Select]->DescLen);
   1852     gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);
   1853     LastSelect = Select;
   1854 
   1855     while (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {
   1856       gBS->Stall (10 * TICKS_PER_MS);
   1857     }
   1858 
   1859     if (InputKey.ScanCode != 0) {
   1860       switch (InputKey.UnicodeChar) {
   1861       case CTRL ('c'):
   1862         InputKey.ScanCode = SCAN_ESC;
   1863         break;
   1864 
   1865       case CTRL ('j'):  /* linefeed */
   1866       case CTRL ('m'):  /* return */
   1867         Finish = TRUE;
   1868         break;
   1869 
   1870       case CTRL ('i'):  /* tab */
   1871       case ' ':
   1872       case 'd':
   1873       case 'D':
   1874         InputKey.ScanCode = SCAN_DOWN;
   1875         break;
   1876 
   1877       case CTRL ('h'):  /* backspace */
   1878       case 'u':
   1879       case 'U':
   1880         InputKey.ScanCode = SCAN_UP;
   1881         break;
   1882 
   1883       default:
   1884         InputKey.ScanCode = 0;
   1885       }
   1886     }
   1887 
   1888     switch (InputKey.ScanCode) {
   1889     case SCAN_LEFT:
   1890     case SCAN_UP:
   1891       if (Select > 0) {
   1892         --Select;
   1893       }
   1894 
   1895       break;
   1896 
   1897     case SCAN_DOWN:
   1898     case SCAN_RIGHT:
   1899       if (++Select == MenuNum) {
   1900         --Select;
   1901       }
   1902 
   1903       break;
   1904 
   1905     case SCAN_PAGE_UP:
   1906     case SCAN_HOME:
   1907       Select = 0;
   1908       break;
   1909 
   1910     case SCAN_PAGE_DOWN:
   1911     case SCAN_END:
   1912       Select = (UINT16) (MenuNum - 1);
   1913       break;
   1914 
   1915     case SCAN_ESC:
   1916       return EFI_ABORTED;
   1917     }
   1918 
   1919     /* unhighlight last selected row */
   1920     gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
   1921     gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + LastSelect);
   1922     Blank[MenuArray[LastSelect]->DescLen] = 0;
   1923     AsciiPrint ("%a\r", Blank);
   1924     PxeBcDisplayBootItem (MenuArray[LastSelect]->DescStr, MenuArray[LastSelect]->DescLen);
   1925     gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);
   1926   } while (!Finish);
   1927 
   1928    ASSERT (Select < PXEBC_MAX_MENU_NUM);
   1929 
   1930   //
   1931   // Swap the byte order
   1932   //
   1933   CopyMem (Type, &MenuArray[Select]->Type, sizeof (UINT16));
   1934   *Type = NTOHS (*Type);
   1935 
   1936   return EFI_SUCCESS;
   1937 }
   1938 
   1939