Home | History | Annotate | Download | only in UefiPxeBcDxe
      1 /** @file
      2   Interface routines for PxeBc.
      3 
      4 Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 
     16 #include "PxeBcImpl.h"
     17 
     18 UINT32  mPxeDhcpTimeout[4] = { 4, 8, 16, 32 };
     19 
     20 /**
     21   Get and record the arp cache.
     22 
     23   @param  This                    Pointer to EFI_PXE_BC_PROTOCOL
     24 
     25   @retval EFI_SUCCESS             Arp cache updated successfully
     26   @retval others                  If error occurs when getting arp cache
     27 
     28 **/
     29 EFI_STATUS
     30 UpdateArpCache (
     31   IN EFI_PXE_BASE_CODE_PROTOCOL     * This
     32   )
     33 {
     34   PXEBC_PRIVATE_DATA      *Private;
     35   EFI_PXE_BASE_CODE_MODE  *Mode;
     36   EFI_STATUS              Status;
     37   UINT32                  EntryLength;
     38   UINT32                  EntryCount;
     39   EFI_ARP_FIND_DATA       *Entries;
     40   UINT32                  Index;
     41 
     42   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
     43   Mode    = Private->PxeBc.Mode;
     44 
     45   Status = Private->Arp->Find (
     46                      Private->Arp,
     47                      TRUE,
     48                      NULL,
     49                      &EntryLength,
     50                      &EntryCount,
     51                      &Entries,
     52                      TRUE
     53                      );
     54   if (EFI_ERROR (Status)) {
     55     return Status;
     56   }
     57 
     58   Mode->ArpCacheEntries = MIN (
     59                            EntryCount,
     60                            EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES
     61                            );
     62   for (Index = 0; Index < Mode->ArpCacheEntries; Index ++) {
     63     CopyMem (
     64       &Mode->ArpCache[Index].IpAddr,
     65       Entries + 1,
     66       Entries->SwAddressLength
     67       );
     68     CopyMem (
     69       &Mode->ArpCache[Index].MacAddr,
     70       (UINT8 *) (Entries + 1) + Entries->SwAddressLength,
     71       Entries->HwAddressLength
     72       );
     73     //
     74     // Slip to the next FindData.
     75     //
     76     Entries = (EFI_ARP_FIND_DATA *) ((UINT8 *) Entries + EntryLength);
     77   }
     78 
     79   return EFI_SUCCESS;
     80 }
     81 
     82 /**
     83   Timeout routine to update arp cache.
     84 
     85   @param  Event              Pointer to EFI_PXE_BC_PROTOCOL
     86   @param  Context            Context of the timer event
     87 
     88 **/
     89 VOID
     90 EFIAPI
     91 ArpCacheUpdateTimeout (
     92   IN EFI_EVENT    Event,
     93   IN VOID         *Context
     94   )
     95 {
     96   UpdateArpCache ((EFI_PXE_BASE_CODE_PROTOCOL *) Context);
     97 }
     98 
     99 /**
    100   Do arp resolution from arp cache in PxeBcMode.
    101 
    102   @param  PxeBcMode      The PXE BC mode to look into.
    103   @param  Ip4Addr        The Ip4 address for resolution.
    104   @param  MacAddress     The resoluted MAC address if the resolution is successful.
    105                          The value is undefined if resolution fails.
    106 
    107   @retval TRUE           The resolution is successful.
    108   @retval FALSE          Otherwise.
    109 
    110 **/
    111 BOOLEAN
    112 FindInArpCache (
    113   IN  EFI_PXE_BASE_CODE_MODE    *PxeBcMode,
    114   IN  EFI_IPv4_ADDRESS          *Ip4Addr,
    115   OUT EFI_MAC_ADDRESS           *MacAddress
    116   )
    117 {
    118   UINT32                  Index;
    119 
    120   for (Index = 0; Index < PxeBcMode->ArpCacheEntries; Index ++) {
    121     if (EFI_IP4_EQUAL (&PxeBcMode->ArpCache[Index].IpAddr.v4, Ip4Addr)) {
    122       CopyMem (
    123         MacAddress,
    124         &PxeBcMode->ArpCache[Index].MacAddr,
    125         sizeof (EFI_MAC_ADDRESS)
    126         );
    127       return TRUE;
    128     }
    129   }
    130 
    131   return FALSE;
    132 }
    133 
    134 /**
    135   Notify function for the ICMP receive token, used to process
    136   the received ICMP packets.
    137 
    138   @param  Context               The PXEBC private data.
    139 
    140 **/
    141 VOID
    142 EFIAPI
    143 IcmpErrorListenHandlerDpc (
    144   IN VOID      *Context
    145   )
    146 {
    147   EFI_STATUS              Status;
    148   EFI_IP4_RECEIVE_DATA    *RxData;
    149   EFI_IP4_PROTOCOL        *Ip4;
    150   PXEBC_PRIVATE_DATA      *Private;
    151   EFI_PXE_BASE_CODE_MODE  *Mode;
    152   UINTN                   Index;
    153   UINT32                  CopiedLen;
    154   UINT8                   *CopiedPointer;
    155 
    156   Private = (PXEBC_PRIVATE_DATA *) Context;
    157   Mode    = &Private->Mode;
    158   Status  = Private->IcmpErrorRcvToken.Status;
    159   RxData  = Private->IcmpErrorRcvToken.Packet.RxData;
    160   Ip4     = Private->Ip4;
    161 
    162   if (Status == EFI_ABORTED) {
    163     //
    164     // The reception is actively aborted by the consumer, directly return.
    165     //
    166     return;
    167   }
    168 
    169   if (EFI_ERROR (Status) || (RxData == NULL)) {
    170     //
    171     // Only process the normal packets and the icmp error packets, if RxData is NULL
    172     // with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although
    173     // this should be a bug of the low layer (IP).
    174     //
    175     goto Resume;
    176   }
    177 
    178   if (EFI_IP4 (RxData->Header->SourceAddress) != 0 &&
    179       (NTOHL (Mode->SubnetMask.Addr[0]) != 0) &&
    180       IP4_NET_EQUAL (NTOHL(Mode->StationIp.Addr[0]), EFI_NTOHL (RxData->Header->SourceAddress), NTOHL (Mode->SubnetMask.Addr[0])) &&
    181       !NetIp4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), NTOHL (Mode->SubnetMask.Addr[0]))) {
    182     //
    183     // The source address is not zero and it's not a unicast IP address, discard it.
    184     //
    185     goto CleanUp;
    186   }
    187 
    188   if (!EFI_IP4_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v4)) {
    189     //
    190     // The dest address is not equal to Station Ip address, discard it.
    191     //
    192     goto CleanUp;
    193   }
    194 
    195   //
    196   // Constructor ICMP error packet
    197   //
    198   CopiedLen = 0;
    199   CopiedPointer = (UINT8 *) &Mode->IcmpError;
    200 
    201   for (Index = 0; Index < RxData->FragmentCount; Index ++) {
    202     CopiedLen += RxData->FragmentTable[Index].FragmentLength;
    203     if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {
    204       CopyMem (
    205         CopiedPointer,
    206         RxData->FragmentTable[Index].FragmentBuffer,
    207         RxData->FragmentTable[Index].FragmentLength
    208         );
    209     } else {
    210       CopyMem (
    211         CopiedPointer,
    212         RxData->FragmentTable[Index].FragmentBuffer,
    213         CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
    214         );
    215     }
    216     CopiedPointer += CopiedLen;
    217   }
    218 
    219   goto Resume;
    220 
    221 CleanUp:
    222   gBS->SignalEvent (RxData->RecycleSignal);
    223 
    224 Resume:
    225   Ip4->Receive (Ip4, &(Private->IcmpErrorRcvToken));
    226 }
    227 
    228 /**
    229   Request IcmpErrorListenHandlerDpc as a DPC at TPL_CALLBACK
    230 
    231   @param  Event                 The event signaled.
    232   @param  Context               The context passed in by the event notifier.
    233 
    234 **/
    235 VOID
    236 EFIAPI
    237 IcmpErrorListenHandler (
    238   IN EFI_EVENT Event,
    239   IN VOID      *Context
    240   )
    241 {
    242   //
    243   // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
    244   //
    245   QueueDpc (TPL_CALLBACK, IcmpErrorListenHandlerDpc, Context);
    246 }
    247 
    248 /**
    249   Enables the use of the PXE Base Code Protocol functions.
    250 
    251   This function enables the use of the PXE Base Code Protocol functions. If the
    252   Started field of the EFI_PXE_BASE_CODE_MODE structure is already TRUE, then
    253   EFI_ALREADY_STARTED will be returned. If UseIpv6 is TRUE, then IPv6 formatted
    254   addresses will be used in this session. If UseIpv6 is FALSE, then IPv4 formatted
    255   addresses will be used in this session. If UseIpv6 is TRUE, and the Ipv6Supported
    256   field of the EFI_PXE_BASE_CODE_MODE structure is FALSE, then EFI_UNSUPPORTED will
    257   be returned. If there is not enough memory or other resources to start the PXE
    258   Base Code Protocol, then EFI_OUT_OF_RESOURCES will be returned. Otherwise, the
    259   PXE Base Code Protocol will be started, and all of the fields of the EFI_PXE_BASE_CODE_MODE
    260   structure will be initialized as follows:
    261     StartedSet to TRUE.
    262     Ipv6SupportedUnchanged.
    263     Ipv6AvailableUnchanged.
    264     UsingIpv6Set to UseIpv6.
    265     BisSupportedUnchanged.
    266     BisDetectedUnchanged.
    267     AutoArpSet to TRUE.
    268     SendGUIDSet to FALSE.
    269     TTLSet to DEFAULT_TTL.
    270     ToSSet to DEFAULT_ToS.
    271     DhcpCompletedSet to FALSE.
    272     ProxyOfferReceivedSet to FALSE.
    273     StationIpSet to an address of all zeros.
    274     SubnetMaskSet to a subnet mask of all zeros.
    275     DhcpDiscoverZero-filled.
    276     DhcpAckZero-filled.
    277     ProxyOfferZero-filled.
    278     PxeDiscoverValidSet to FALSE.
    279     PxeDiscoverZero-filled.
    280     PxeReplyValidSet to FALSE.
    281     PxeReplyZero-filled.
    282     PxeBisReplyValidSet to FALSE.
    283     PxeBisReplyZero-filled.
    284     IpFilterSet the Filters field to 0 and the IpCnt field to 0.
    285     ArpCacheEntriesSet to 0.
    286     ArpCacheZero-filled.
    287     RouteTableEntriesSet to 0.
    288     RouteTableZero-filled.
    289     IcmpErrorReceivedSet to FALSE.
    290     IcmpErrorZero-filled.
    291     TftpErroReceivedSet to FALSE.
    292     TftpErrorZero-filled.
    293     MakeCallbacksSet to TRUE if the PXE Base Code Callback Protocol is available.
    294     Set to FALSE if the PXE Base Code Callback Protocol is not available.
    295 
    296   @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
    297   @param  UseIpv6               Specifies the type of IP addresses that are to be used during the session
    298                                 that is being started. Set to TRUE for IPv6 addresses, and FALSE for
    299                                 IPv4 addresses.
    300 
    301   @retval EFI_SUCCESS           The PXE Base Code Protocol was started.
    302   @retval EFI_DEVICE_ERROR      The network device encountered an error during this oper
    303   @retval EFI_UNSUPPORTED       UseIpv6 is TRUE, but the Ipv6Supported field of the
    304                                 EFI_PXE_BASE_CODE_MODE structure is FALSE.
    305   @retval EFI_ALREADY_STARTED   The PXE Base Code Protocol is already in the started state.
    306   @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not point to a valid
    307                                 EFI_PXE_BASE_CODE_PROTOCOL structure.
    308   @retval EFI_OUT_OF_RESOURCES  Could not allocate enough memory or other resources to start the
    309                                 PXE Base Code Protocol.
    310 
    311 **/
    312 EFI_STATUS
    313 EFIAPI
    314 EfiPxeBcStart (
    315   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
    316   IN BOOLEAN                          UseIpv6
    317   )
    318 {
    319   PXEBC_PRIVATE_DATA      *Private;
    320   EFI_PXE_BASE_CODE_MODE  *Mode;
    321   EFI_STATUS              Status;
    322 
    323   if (This == NULL) {
    324     return EFI_INVALID_PARAMETER;
    325   }
    326 
    327   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
    328   Mode    = Private->PxeBc.Mode;
    329 
    330   if (Mode->Started) {
    331     return EFI_ALREADY_STARTED;
    332   }
    333 
    334   if (UseIpv6) {
    335     //
    336     // IPv6 is not supported now.
    337     //
    338     return EFI_UNSUPPORTED;
    339   }
    340 
    341   //
    342   // Configure the udp4 instance to let it receive data
    343   //
    344   Status = Private->Udp4Read->Configure (
    345                                Private->Udp4Read,
    346                                &Private->Udp4CfgData
    347                                );
    348   if (EFI_ERROR (Status)) {
    349     return Status;
    350   }
    351 
    352 
    353   //
    354   // Configure block size for TFTP as a default value to handle all link layers.
    355   //
    356   Private->BlockSize   = (UINTN) (MIN (Private->Ip4MaxPacketSize, PXEBC_DEFAULT_PACKET_SIZE) -
    357                            PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE);
    358   //
    359   // If PcdTftpBlockSize is set to non-zero, override the default value.
    360   //
    361   if (PcdGet64 (PcdTftpBlockSize) != 0) {
    362     Private->BlockSize   = (UINTN) PcdGet64 (PcdTftpBlockSize);
    363   }
    364 
    365   Private->AddressIsOk = FALSE;
    366 
    367   ZeroMem (Mode, sizeof (EFI_PXE_BASE_CODE_MODE));
    368 
    369   Mode->Started = TRUE;
    370   Mode->TTL     = DEFAULT_TTL;
    371   Mode->ToS     = DEFAULT_ToS;
    372   Mode->AutoArp = TRUE;
    373 
    374   //
    375   // Create the event for Arp Cache checking.
    376   //
    377   Status = gBS->CreateEvent (
    378                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
    379                   TPL_CALLBACK,
    380                   ArpCacheUpdateTimeout,
    381                   This,
    382                   &Private->GetArpCacheEvent
    383                   );
    384   if (EFI_ERROR (Status)) {
    385     goto ON_EXIT;
    386   }
    387 
    388   //
    389   // Start the timeout timer event.
    390   //
    391   Status = gBS->SetTimer (
    392                   Private->GetArpCacheEvent,
    393                   TimerPeriodic,
    394                   TICKS_PER_SECOND
    395                   );
    396 
    397   if (EFI_ERROR (Status)) {
    398     goto ON_EXIT;
    399   }
    400 
    401   //
    402   // Create ICMP error receiving event
    403   //
    404   Status = gBS->CreateEvent (
    405                   EVT_NOTIFY_SIGNAL,
    406                   TPL_NOTIFY,
    407                   IcmpErrorListenHandler,
    408                   Private,
    409                   &(Private->IcmpErrorRcvToken.Event)
    410                   );
    411   if (EFI_ERROR (Status)) {
    412     goto ON_EXIT;
    413   }
    414 
    415   //
    416   //DHCP4 service allows only one of its children to be configured in
    417   //the active state, If the DHCP4 D.O.R.A started by IP4 auto
    418   //configuration and has not been completed, the Dhcp4 state machine
    419   //will not be in the right state for the PXE to start a new round D.O.R.A.
    420   //so we need to switch it's policy to static.
    421   //
    422   Status = PxeBcSetIp4Policy (Private);
    423   if (EFI_ERROR (Status)) {
    424     goto ON_EXIT;
    425   }
    426 
    427   Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4ConfigData);
    428   if (EFI_ERROR (Status)) {
    429     goto ON_EXIT;
    430   }
    431 
    432   //
    433   // start to listen incoming packet
    434   //
    435   Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpErrorRcvToken);
    436   if (!EFI_ERROR (Status)) {
    437     return Status;
    438   }
    439 
    440 ON_EXIT:
    441   Private->Ip4->Configure (Private->Ip4, NULL);
    442 
    443   if (Private->IcmpErrorRcvToken.Event != NULL) {
    444     gBS->CloseEvent (Private->IcmpErrorRcvToken.Event);
    445   }
    446 
    447   if (Private->GetArpCacheEvent != NULL) {
    448     gBS->SetTimer (Private->GetArpCacheEvent, TimerCancel, 0);
    449     gBS->CloseEvent (Private->GetArpCacheEvent);
    450   }
    451 
    452   Mode->Started = FALSE;
    453   Mode->TTL     = 0;
    454   Mode->ToS     = 0;
    455   Mode->AutoArp = FALSE;
    456 
    457   return Status;
    458 }
    459 
    460 
    461 /**
    462   Disables the use of the PXE Base Code Protocol functions.
    463 
    464   This function stops all activity on the network device. All the resources allocated
    465   in Start() are released, the Started field of the EFI_PXE_BASE_CODE_MODE structure is
    466   set to FALSE and EFI_SUCCESS is returned. If the Started field of the EFI_PXE_BASE_CODE_MODE
    467   structure is already FALSE, then EFI_NOT_STARTED will be returned.
    468 
    469   @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
    470 
    471   @retval EFI_SUCCESS           The PXE Base Code Protocol was stopped.
    472   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is already in the stopped state.
    473   @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not point to a valid
    474                                 EFI_PXE_BASE_CODE_PROTOCOL structure.
    475   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
    476 
    477 **/
    478 EFI_STATUS
    479 EFIAPI
    480 EfiPxeBcStop (
    481   IN EFI_PXE_BASE_CODE_PROTOCOL       *This
    482   )
    483 {
    484   PXEBC_PRIVATE_DATA      *Private;
    485   EFI_PXE_BASE_CODE_MODE  *Mode;
    486 
    487   if (This == NULL) {
    488     return EFI_INVALID_PARAMETER;
    489   }
    490 
    491   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
    492   Mode    = Private->PxeBc.Mode;
    493 
    494   if (!Mode->Started) {
    495     return EFI_NOT_STARTED;
    496   }
    497 
    498   Private->Ip4->Cancel (Private->Ip4, NULL);
    499   //
    500   // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's
    501   // events.
    502   //
    503   DispatchDpc ();
    504 
    505   Private->Ip4->Configure (Private->Ip4, NULL);
    506 
    507   //
    508   // Close the ICMP error receiving event.
    509   //
    510   gBS->CloseEvent (Private->IcmpErrorRcvToken.Event);
    511 
    512   //
    513   // Cancel the TimeoutEvent timer.
    514   //
    515   gBS->SetTimer (Private->GetArpCacheEvent, TimerCancel, 0);
    516 
    517   //
    518   // Close the TimeoutEvent event.
    519   //
    520   gBS->CloseEvent (Private->GetArpCacheEvent);
    521 
    522   Mode->Started = FALSE;
    523 
    524   Private->CurrentUdpSrcPort = 0;
    525   Private->Udp4Write->Configure (Private->Udp4Write, NULL);
    526   Private->Udp4Read->Groups (Private->Udp4Read, FALSE, NULL);
    527   Private->Udp4Read->Configure (Private->Udp4Read, NULL);
    528 
    529   Private->Dhcp4->Stop (Private->Dhcp4);
    530   Private->Dhcp4->Configure (Private->Dhcp4, NULL);
    531 
    532   Private->FileSize = 0;
    533 
    534   return EFI_SUCCESS;
    535 }
    536 
    537 
    538 /**
    539   Attempts to complete a DHCPv4 D.O.R.A. (discover / offer / request / acknowledge) or DHCPv6
    540   S.A.R.R (solicit / advertise / request / reply) sequence.
    541 
    542   This function attempts to complete the DHCP sequence. If this sequence is completed,
    543   then EFI_SUCCESS is returned, and the DhcpCompleted, ProxyOfferReceived, StationIp,
    544   SubnetMask, DhcpDiscover, DhcpAck, and ProxyOffer fields of the EFI_PXE_BASE_CODE_MODE
    545   structure are filled in.
    546   If SortOffers is TRUE, then the cached DHCP offer packets will be sorted before
    547   they are tried. If SortOffers is FALSE, then the cached DHCP offer packets will
    548   be tried in the order in which they are received. Please see the Preboot Execution
    549   Environment (PXE) Specification for additional details on the implementation of DHCP.
    550   This function can take at least 31 seconds to timeout and return control to the
    551   caller. If the DHCP sequence does not complete, then EFI_TIMEOUT will be returned.
    552   If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
    553   then the DHCP sequence will be stopped and EFI_ABORTED will be returned.
    554 
    555   @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
    556   @param  SortOffers            TRUE if the offers received should be sorted. Set to FALSE to try the
    557                                 offers in the order that they are received.
    558 
    559   @retval EFI_SUCCESS           Valid DHCP has completed.
    560   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
    561   @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not point to a valid
    562                                 EFI_PXE_BASE_CODE_PROTOCOL structure.
    563   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
    564   @retval EFI_OUT_OF_RESOURCES  Could not allocate enough memory to complete the DHCP Protocol.
    565   @retval EFI_ABORTED           The callback function aborted the DHCP Protocol.
    566   @retval EFI_TIMEOUT           The DHCP Protocol timed out.
    567   @retval EFI_ICMP_ERROR        An ICMP error packet was received during the DHCP session.
    568   @retval EFI_NO_RESPONSE       Valid PXE offer was not received.
    569 
    570 **/
    571 EFI_STATUS
    572 EFIAPI
    573 EfiPxeBcDhcp (
    574   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
    575   IN BOOLEAN                          SortOffers
    576   )
    577 {
    578   PXEBC_PRIVATE_DATA           *Private;
    579   EFI_PXE_BASE_CODE_MODE       *Mode;
    580   EFI_DHCP4_PROTOCOL           *Dhcp4;
    581   EFI_DHCP4_CONFIG_DATA        Dhcp4CfgData;
    582   EFI_DHCP4_MODE_DATA          Dhcp4Mode;
    583   EFI_DHCP4_PACKET_OPTION      *OptList[PXEBC_DHCP4_MAX_OPTION_NUM];
    584   UINT32                       OptCount;
    585   EFI_STATUS                   Status;
    586   EFI_ARP_CONFIG_DATA          ArpConfigData;
    587   EFI_PXE_BASE_CODE_IP_FILTER  IpFilter;
    588 
    589   if (This == NULL) {
    590     return EFI_INVALID_PARAMETER;
    591   }
    592 
    593   Status              = EFI_SUCCESS;
    594   Private             = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
    595   Mode                = Private->PxeBc.Mode;
    596   Dhcp4               = Private->Dhcp4;
    597   Private->Function   = EFI_PXE_BASE_CODE_FUNCTION_DHCP;
    598   Private->SortOffers = SortOffers;
    599 
    600   if (!Mode->Started) {
    601     return EFI_NOT_STARTED;
    602   }
    603 
    604   Mode->IcmpErrorReceived = FALSE;
    605 
    606   //
    607   // Stop Udp4Read instance
    608   //
    609   Private->Udp4Read->Configure (Private->Udp4Read, NULL);
    610 
    611   //
    612   // Initialize the DHCP options and build the option list
    613   //
    614   OptCount = PxeBcBuildDhcpOptions (Private, OptList, TRUE);
    615 
    616   //
    617   // Set the DHCP4 config data.
    618   // The four discovery timeouts are 4, 8, 16, 32 seconds respectively.
    619   //
    620   ZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));
    621   Dhcp4CfgData.OptionCount      = OptCount;
    622   Dhcp4CfgData.OptionList       = OptList;
    623   Dhcp4CfgData.Dhcp4Callback    = PxeBcDhcpCallBack;
    624   Dhcp4CfgData.CallbackContext  = Private;
    625   Dhcp4CfgData.DiscoverTryCount = 4;
    626   Dhcp4CfgData.DiscoverTimeout  = mPxeDhcpTimeout;
    627 
    628   Status          = Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);
    629   if (EFI_ERROR (Status)) {
    630     goto ON_EXIT;
    631   }
    632 
    633   //
    634   // Zero those arrays to record the varies numbers of DHCP OFFERS.
    635   //
    636   Private->GotProxyOffer = FALSE;
    637   Private->NumOffers     = 0;
    638   Private->BootpIndex    = 0;
    639   ZeroMem (Private->ServerCount, sizeof (Private->ServerCount));
    640   ZeroMem (Private->ProxyIndex, sizeof (Private->ProxyIndex));
    641 
    642   Status = Dhcp4->Start (Dhcp4, NULL);
    643   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
    644     if (Status == EFI_ICMP_ERROR) {
    645       Mode->IcmpErrorReceived = TRUE;
    646     }
    647     goto ON_EXIT;
    648   }
    649 
    650   Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);
    651   if (EFI_ERROR (Status)) {
    652     goto ON_EXIT;
    653   }
    654 
    655   ASSERT (Dhcp4Mode.State == Dhcp4Bound);
    656 
    657   CopyMem (&Private->StationIp, &Dhcp4Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
    658   CopyMem (&Private->SubnetMask, &Dhcp4Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
    659   CopyMem (&Private->GatewayIp, &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
    660 
    661   CopyMem (&Mode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
    662   CopyMem (&Mode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
    663 
    664   //
    665   // Check the selected offer to see whether BINL is required, if no or BINL is
    666   // finished, set the various Mode members.
    667   //
    668   Status = PxeBcCheckSelectedOffer (Private);
    669 
    670 ON_EXIT:
    671   if (EFI_ERROR (Status)) {
    672     Dhcp4->Stop (Dhcp4);
    673     Dhcp4->Configure (Dhcp4, NULL);
    674   } else {
    675     //
    676     // Remove the previously configured option list and callback function
    677     //
    678     ZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));
    679     Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);
    680 
    681     Private->AddressIsOk = TRUE;
    682 
    683     if (!Mode->UsingIpv6) {
    684       //
    685       // If in IPv4 mode, configure the corresponding ARP with this new
    686       // station IP address.
    687       //
    688       ZeroMem (&ArpConfigData, sizeof (EFI_ARP_CONFIG_DATA));
    689 
    690       ArpConfigData.SwAddressType   = 0x0800;
    691       ArpConfigData.SwAddressLength = (UINT8) sizeof (EFI_IPv4_ADDRESS);
    692       ArpConfigData.StationAddress  = &Private->StationIp.v4;
    693 
    694       Private->Arp->Configure (Private->Arp, NULL);
    695       Private->Arp->Configure (Private->Arp, &ArpConfigData);
    696 
    697       //
    698       // Updated the route table. Fill the first entry.
    699       //
    700       Mode->RouteTableEntries                = 1;
    701       Mode->RouteTable[0].IpAddr.Addr[0]     = Private->StationIp.Addr[0] & Private->SubnetMask.Addr[0];
    702       Mode->RouteTable[0].SubnetMask.Addr[0] = Private->SubnetMask.Addr[0];
    703       Mode->RouteTable[0].GwAddr.Addr[0]     = 0;
    704 
    705       //
    706       // Create the default route entry if there is a default router.
    707       //
    708       if (Private->GatewayIp.Addr[0] != 0) {
    709         Mode->RouteTableEntries                = 2;
    710         Mode->RouteTable[1].IpAddr.Addr[0]     = 0;
    711         Mode->RouteTable[1].SubnetMask.Addr[0] = 0;
    712         Mode->RouteTable[1].GwAddr.Addr[0]     = Private->GatewayIp.Addr[0];
    713       }
    714 
    715       //
    716       // Flush new station IP address into Udp4CfgData and Ip4ConfigData
    717       //
    718       CopyMem (&Private->Udp4CfgData.StationAddress, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
    719       CopyMem (&Private->Udp4CfgData.SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
    720       CopyMem (&Private->Ip4ConfigData.StationAddress, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
    721       CopyMem (&Private->Ip4ConfigData.SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
    722 
    723       //
    724       // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.
    725       //
    726       Private->Ip4->Cancel (Private->Ip4, &Private->IcmpErrorRcvToken);
    727       Private->Ip4->Configure (Private->Ip4, NULL);
    728 
    729       Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4ConfigData);
    730       if (EFI_ERROR (Status)) {
    731         goto ON_EXIT;
    732       }
    733 
    734       Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpErrorRcvToken);
    735       if (EFI_ERROR (Status)) {
    736         goto ON_EXIT;
    737       }
    738     }
    739   }
    740 
    741   Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);
    742 
    743   //
    744   // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP
    745   // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
    746   //
    747   ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));
    748   IpFilter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
    749   This->SetIpFilter (This, &IpFilter);
    750 
    751   return Status;
    752 }
    753 
    754 
    755 /**
    756   Attempts to complete the PXE Boot Server and/or boot image discovery sequence.
    757 
    758   This function attempts to complete the PXE Boot Server and/or boot image discovery
    759   sequence. If this sequence is completed, then EFI_SUCCESS is returned, and the
    760   PxeDiscoverValid, PxeDiscover, PxeReplyReceived, and PxeReply fields of the
    761   EFI_PXE_BASE_CODE_MODE structure are filled in. If UseBis is TRUE, then the
    762   PxeBisReplyReceived and PxeBisReply fields of the EFI_PXE_BASE_CODE_MODE structure
    763   will also be filled in. If UseBis is FALSE, then PxeBisReplyValid will be set to FALSE.
    764   In the structure referenced by parameter Info, the PXE Boot Server list, SrvList[],
    765   has two uses: It is the Boot Server IP address list used for unicast discovery
    766   (if the UseUCast field is TRUE), and it is the list used for Boot Server verification
    767   (if the MustUseList field is TRUE). Also, if the MustUseList field in that structure
    768   is TRUE and the AcceptAnyResponse field in the SrvList[] array is TRUE, any Boot
    769   Server reply of that type will be accepted. If the AcceptAnyResponse field is
    770   FALSE, only responses from Boot Servers with matching IP addresses will be accepted.
    771   This function can take at least 10 seconds to timeout and return control to the
    772   caller. If the Discovery sequence does not complete, then EFI_TIMEOUT will be
    773   returned. Please see the Preboot Execution Environment (PXE) Specification for
    774   additional details on the implementation of the Discovery sequence.
    775   If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
    776   then the Discovery sequence is stopped and EFI_ABORTED will be returned.
    777 
    778   @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
    779   @param  Type                  The type of bootstrap to perform.
    780   @param  Layer                 Pointer to the boot server layer number to discover, which must be
    781                                 PXE_BOOT_LAYER_INITIAL when a new server type is being
    782                                 discovered.
    783   @param  UseBis                TRUE if Boot Integrity Services are to be used. FALSE otherwise.
    784   @param  Info                  Pointer to a data structure that contains additional information on the
    785                                 type of discovery operation that is to be performed.
    786 
    787   @retval EFI_SUCCESS           The Discovery sequence has been completed.
    788   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
    789   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    790   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
    791   @retval EFI_OUT_OF_RESOURCES  Could not allocate enough memory to complete Discovery.
    792   @retval EFI_ABORTED           The callback function aborted the Discovery sequence.
    793   @retval EFI_TIMEOUT           The Discovery sequence timed out.
    794   @retval EFI_ICMP_ERROR        An ICMP error packet was received during the PXE discovery
    795                                 session.
    796 
    797 **/
    798 EFI_STATUS
    799 EFIAPI
    800 EfiPxeBcDiscover (
    801   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
    802   IN UINT16                           Type,
    803   IN UINT16                           *Layer,
    804   IN BOOLEAN                          UseBis,
    805   IN EFI_PXE_BASE_CODE_DISCOVER_INFO  *Info   OPTIONAL
    806   )
    807 {
    808   PXEBC_PRIVATE_DATA              *Private;
    809   EFI_PXE_BASE_CODE_MODE          *Mode;
    810   EFI_PXE_BASE_CODE_DISCOVER_INFO DefaultInfo;
    811   EFI_PXE_BASE_CODE_DISCOVER_INFO *CreatedInfo;
    812   EFI_PXE_BASE_CODE_SRVLIST       *SrvList;
    813   EFI_PXE_BASE_CODE_SRVLIST       DefaultSrvList;
    814   PXEBC_CACHED_DHCP4_PACKET       *Packet;
    815   PXEBC_VENDOR_OPTION             *VendorOpt;
    816   UINT16                          Index;
    817   EFI_STATUS                      Status;
    818   PXEBC_BOOT_SVR_ENTRY            *BootSvrEntry;
    819   EFI_PXE_BASE_CODE_IP_FILTER     IpFilter;
    820 
    821   if (This == NULL) {
    822     return EFI_INVALID_PARAMETER;
    823   }
    824 
    825   Private           = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
    826   Mode              = Private->PxeBc.Mode;
    827   BootSvrEntry      = NULL;
    828   SrvList           = NULL;
    829   CreatedInfo       = NULL;
    830   Status            = EFI_DEVICE_ERROR;
    831   Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;
    832 
    833   if (!Private->AddressIsOk) {
    834     return EFI_INVALID_PARAMETER;
    835   }
    836 
    837   if (!Mode->Started) {
    838     return EFI_NOT_STARTED;
    839   }
    840 
    841   //
    842   // Stop Udp4Read instance
    843   //
    844   Private->Udp4Read->Configure (Private->Udp4Read, NULL);
    845 
    846   Mode->IcmpErrorReceived = FALSE;
    847 
    848   //
    849   // If layer isn't EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL,
    850   //   use the previous setting;
    851   // If info isn't offered,
    852   //   use the cached DhcpAck and ProxyOffer packets.
    853   //
    854   ZeroMem (&DefaultInfo, sizeof (EFI_PXE_BASE_CODE_DISCOVER_INFO));
    855   if (*Layer != EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL) {
    856 
    857     if (!Mode->PxeDiscoverValid || !Mode->PxeReplyReceived || (!Mode->PxeBisReplyReceived && UseBis)) {
    858 
    859       Status = EFI_INVALID_PARAMETER;
    860       goto ON_EXIT;
    861     }
    862 
    863     DefaultInfo.IpCnt                 = 1;
    864     DefaultInfo.UseUCast              = TRUE;
    865 
    866     DefaultSrvList.Type               = Type;
    867     DefaultSrvList.AcceptAnyResponse  = FALSE;
    868     DefaultSrvList.IpAddr.Addr[0]     = Private->ServerIp.Addr[0];
    869 
    870     SrvList = &DefaultSrvList;
    871     Info = &DefaultInfo;
    872   } else if (Info == NULL) {
    873     //
    874     // Create info by the cached packet before
    875     //
    876     Packet    = (Mode->ProxyOfferReceived) ? &Private->ProxyOffer : &Private->Dhcp4Ack;
    877     VendorOpt = &Packet->PxeVendorOption;
    878 
    879     if (!Mode->DhcpAckReceived || !IS_VALID_DISCOVER_VENDOR_OPTION (VendorOpt->BitMap)) {
    880       //
    881       // Address is not acquired or no discovery options.
    882       //
    883       Status = EFI_INVALID_PARAMETER;
    884       goto ON_EXIT;
    885     }
    886 
    887     DefaultInfo.UseMCast    = (BOOLEAN)!IS_DISABLE_MCAST_DISCOVER (VendorOpt->DiscoverCtrl);
    888     DefaultInfo.UseBCast    = (BOOLEAN)!IS_DISABLE_BCAST_DISCOVER (VendorOpt->DiscoverCtrl);
    889     DefaultInfo.MustUseList = (BOOLEAN) IS_ENABLE_USE_SERVER_LIST (VendorOpt->DiscoverCtrl);
    890     DefaultInfo.UseUCast    = DefaultInfo.MustUseList;
    891 
    892     if (DefaultInfo.UseMCast) {
    893       //
    894       // Get the multicast discover ip address from vendor option.
    895       //
    896       CopyMem (
    897         &DefaultInfo.ServerMCastIp.Addr,
    898         &VendorOpt->DiscoverMcastIp,
    899         sizeof (EFI_IPv4_ADDRESS)
    900         );
    901     }
    902 
    903     DefaultInfo.IpCnt = 0;
    904     Info    = &DefaultInfo;
    905     SrvList = Info->SrvList;
    906 
    907     if (DefaultInfo.MustUseList) {
    908       BootSvrEntry  = VendorOpt->BootSvr;
    909       Status        = EFI_INVALID_PARAMETER;
    910 
    911       while (((UINT8) (BootSvrEntry - VendorOpt->BootSvr)) < VendorOpt->BootSvrLen) {
    912 
    913         if (BootSvrEntry->Type == HTONS (Type)) {
    914           Status = EFI_SUCCESS;
    915           break;
    916         }
    917 
    918         BootSvrEntry = GET_NEXT_BOOT_SVR_ENTRY (BootSvrEntry);
    919       }
    920 
    921       if (EFI_ERROR (Status)) {
    922         goto ON_EXIT;
    923       }
    924 
    925       DefaultInfo.IpCnt = BootSvrEntry->IpCnt;
    926 
    927       if (DefaultInfo.IpCnt >= 1) {
    928         CreatedInfo = AllocatePool (sizeof (DefaultInfo) + (DefaultInfo.IpCnt - 1) * sizeof (*SrvList));
    929         if (CreatedInfo == NULL) {
    930           Status = EFI_OUT_OF_RESOURCES;
    931           goto ON_EXIT;
    932 
    933         }
    934 
    935         CopyMem (CreatedInfo, &DefaultInfo, sizeof (DefaultInfo));
    936         Info    = CreatedInfo;
    937         SrvList = Info->SrvList;
    938       }
    939 
    940       for (Index = 0; Index < DefaultInfo.IpCnt; Index++) {
    941         CopyMem (&SrvList[Index].IpAddr, &BootSvrEntry->IpAddr[Index], sizeof (EFI_IPv4_ADDRESS));
    942         SrvList[Index].AcceptAnyResponse   = FALSE;
    943         SrvList[Index].Type                = BootSvrEntry->Type;
    944       }
    945     }
    946 
    947   } else {
    948 
    949     SrvList = Info->SrvList;
    950 
    951     if (!SrvList[0].AcceptAnyResponse) {
    952 
    953       for (Index = 1; Index < Info->IpCnt; Index++) {
    954         if (SrvList[Index].AcceptAnyResponse) {
    955           break;
    956         }
    957       }
    958 
    959       if (Index != Info->IpCnt) {
    960         Status = EFI_INVALID_PARAMETER;
    961         goto ON_EXIT;
    962       }
    963     }
    964   }
    965 
    966   if ((!Info->UseUCast && !Info->UseBCast && !Info->UseMCast) || (Info->MustUseList && Info->IpCnt == 0)) {
    967 
    968     Status = EFI_INVALID_PARAMETER;
    969     goto ON_EXIT;
    970   }
    971   //
    972   // Execute discover by UniCast/BroadCast/MultiCast
    973   //
    974   if (Info->UseUCast) {
    975 
    976     for (Index = 0; Index < Info->IpCnt; Index++) {
    977 
    978       if (BootSvrEntry == NULL) {
    979         Private->ServerIp.Addr[0] = SrvList[Index].IpAddr.Addr[0];
    980       } else {
    981         CopyMem (
    982           &Private->ServerIp,
    983           &BootSvrEntry->IpAddr[Index],
    984           sizeof (EFI_IPv4_ADDRESS)
    985           );
    986       }
    987 
    988       Status = PxeBcDiscvBootService (
    989                 Private,
    990                 Type,
    991                 Layer,
    992                 UseBis,
    993                 &SrvList[Index].IpAddr,
    994                 0,
    995                 NULL,
    996                 TRUE,
    997                 &Private->PxeReply.Packet.Ack
    998                 );
    999       if (!EFI_ERROR (Status)) {
   1000         break;
   1001       }
   1002     }
   1003 
   1004   } else if (Info->UseMCast) {
   1005 
   1006     Status = PxeBcDiscvBootService (
   1007               Private,
   1008               Type,
   1009               Layer,
   1010               UseBis,
   1011               &Info->ServerMCastIp,
   1012               0,
   1013               NULL,
   1014               TRUE,
   1015               &Private->PxeReply.Packet.Ack
   1016               );
   1017 
   1018   } else if (Info->UseBCast) {
   1019 
   1020     Status = PxeBcDiscvBootService (
   1021               Private,
   1022               Type,
   1023               Layer,
   1024               UseBis,
   1025               NULL,
   1026               Info->IpCnt,
   1027               SrvList,
   1028               TRUE,
   1029               &Private->PxeReply.Packet.Ack
   1030               );
   1031   }
   1032 
   1033   if (EFI_ERROR (Status) || !Mode->PxeReplyReceived || (!Mode->PxeBisReplyReceived && UseBis)) {
   1034     if (Status == EFI_ICMP_ERROR) {
   1035       Mode->IcmpErrorReceived = TRUE;
   1036     } else {
   1037       Status = EFI_DEVICE_ERROR;
   1038     }
   1039     goto ON_EXIT;
   1040   } else {
   1041     PxeBcParseCachedDhcpPacket (&Private->PxeReply);
   1042   }
   1043 
   1044   if (Mode->PxeBisReplyReceived) {
   1045     CopyMem (
   1046       &Private->ServerIp,
   1047       &Mode->PxeReply.Dhcpv4.BootpSiAddr,
   1048       sizeof (EFI_IPv4_ADDRESS)
   1049       );
   1050   }
   1051 
   1052   if (CreatedInfo != NULL) {
   1053     FreePool (CreatedInfo);
   1054   }
   1055 
   1056 ON_EXIT:
   1057 
   1058   Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);
   1059 
   1060   //
   1061   // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP
   1062   // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
   1063   //
   1064   ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));
   1065   IpFilter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
   1066   This->SetIpFilter (This, &IpFilter);
   1067 
   1068   return Status;
   1069 }
   1070 
   1071 
   1072 /**
   1073   Used to perform TFTP and MTFTP services.
   1074 
   1075   This function is used to perform TFTP and MTFTP services. This includes the
   1076   TFTP operations to get the size of a file, read a directory, read a file, and
   1077   write a file. It also includes the MTFTP operations to get the size of a file,
   1078   read a directory, and read a file. The type of operation is specified by Operation.
   1079   If the callback function that is invoked during the TFTP/MTFTP operation does
   1080   not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, then EFI_ABORTED will
   1081   be returned.
   1082   For read operations, the return data will be placed in the buffer specified by
   1083   BufferPtr. If BufferSize is too small to contain the entire downloaded file,
   1084   then EFI_BUFFER_TOO_SMALL will be returned and BufferSize will be set to zero
   1085   or the size of the requested file (the size of the requested file is only returned
   1086   if the TFTP server supports TFTP options). If BufferSize is large enough for the
   1087   read operation, then BufferSize will be set to the size of the downloaded file,
   1088   and EFI_SUCCESS will be returned. Applications using the PxeBc.Mtftp() services
   1089   should use the get-file-size operations to determine the size of the downloaded
   1090   file prior to using the read-file operations-especially when downloading large
   1091   (greater than 64 MB) files-instead of making two calls to the read-file operation.
   1092   Following this recommendation will save time if the file is larger than expected
   1093   and the TFTP server does not support TFTP option extensions. Without TFTP option
   1094   extension support, the client has to download the entire file, counting and discarding
   1095   the received packets, to determine the file size.
   1096   For write operations, the data to be sent is in the buffer specified by BufferPtr.
   1097   BufferSize specifies the number of bytes to send. If the write operation completes
   1098   successfully, then EFI_SUCCESS will be returned.
   1099   For TFTP "get file size" operations, the size of the requested file or directory
   1100   is returned in BufferSize, and EFI_SUCCESS will be returned. If the TFTP server
   1101   does not support options, the file will be downloaded into a bit bucket and the
   1102   length of the downloaded file will be returned. For MTFTP "get file size" operations,
   1103   if the MTFTP server does not support the "get file size" option, EFI_UNSUPPORTED
   1104   will be returned.
   1105   This function can take up to 10 seconds to timeout and return control to the caller.
   1106   If the TFTP sequence does not complete, EFI_TIMEOUT will be returned.
   1107   If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
   1108   then the TFTP sequence is stopped and EFI_ABORTED will be returned.
   1109   The format of the data returned from a TFTP read directory operation is a null-terminated
   1110   filename followed by a null-terminated information string, of the form
   1111   "size year-month-day hour:minute:second" (i.e. %d %d-%d-%d %d:%d:%f - note that
   1112   the seconds field can be a decimal number), where the date and time are UTC. For
   1113   an MTFTP read directory command, there is additionally a null-terminated multicast
   1114   IP address preceding the filename of the form %d.%d.%d.%d for IP v4. The final
   1115   entry is itself null-terminated, so that the final information string is terminated
   1116   with two null octets.
   1117 
   1118   @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
   1119   @param  Operation             The type of operation to perform.
   1120   @param  BufferPtr             A pointer to the data buffer.
   1121   @param  Overwrite             Only used on write file operations. TRUE if a file on a remote server can
   1122                                 be overwritten.
   1123   @param  BufferSize            For get-file-size operations, *BufferSize returns the size of the
   1124                                 requested file.
   1125   @param  BlockSize             The requested block size to be used during a TFTP transfer.
   1126   @param  ServerIp              The TFTP / MTFTP server IP address.
   1127   @param  Filename              A Null-terminated ASCII string that specifies a directory name or a file
   1128                                 name.
   1129   @param  Info                  Pointer to the MTFTP information.
   1130   @param  DontUseBuffer         Set to FALSE for normal TFTP and MTFTP read file operation.
   1131 
   1132   @retval EFI_SUCCESS           The TFTP/MTFTP operation was completed.
   1133   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
   1134   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   1135   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
   1136   @retval EFI_BUFFER_TOO_SMALL  The buffer is not large enough to complete the read operation.
   1137   @retval EFI_ABORTED           The callback function aborted the TFTP/MTFTP operation.
   1138   @retval EFI_TIMEOUT           The TFTP/MTFTP operation timed out.
   1139   @retval EFI_ICMP_ERROR        An ICMP error packet was received during the MTFTP session.
   1140   @retval EFI_TFTP_ERROR        A TFTP error packet was received during the MTFTP session.
   1141 
   1142 **/
   1143 EFI_STATUS
   1144 EFIAPI
   1145 EfiPxeBcMtftp (
   1146   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
   1147   IN EFI_PXE_BASE_CODE_TFTP_OPCODE    Operation,
   1148   IN OUT VOID                         *BufferPtr,
   1149   IN BOOLEAN                          Overwrite,
   1150   IN OUT UINT64                       *BufferSize,
   1151   IN UINTN                            *BlockSize    OPTIONAL,
   1152   IN EFI_IP_ADDRESS                   *ServerIp,
   1153   IN UINT8                            *Filename,
   1154   IN EFI_PXE_BASE_CODE_MTFTP_INFO     *Info         OPTIONAL,
   1155   IN BOOLEAN                          DontUseBuffer
   1156   )
   1157 {
   1158   PXEBC_PRIVATE_DATA           *Private;
   1159   EFI_MTFTP4_CONFIG_DATA       Mtftp4Config;
   1160   EFI_STATUS                   Status;
   1161   EFI_PXE_BASE_CODE_MODE       *Mode;
   1162   EFI_MAC_ADDRESS              TempMacAddr;
   1163   EFI_PXE_BASE_CODE_IP_FILTER  IpFilter;
   1164 
   1165   if ((This == NULL)                                                          ||
   1166       (Filename == NULL)                                                      ||
   1167       (BufferSize == NULL)                                                    ||
   1168       ((ServerIp == NULL) ||
   1169        (IP4_IS_UNSPECIFIED (NTOHL (ServerIp->Addr[0])) ||
   1170         IP4_IS_LOCAL_BROADCAST (NTOHL (ServerIp->Addr[0]))))                  ||
   1171       ((BufferPtr == NULL) && DontUseBuffer)                                  ||
   1172       ((BlockSize != NULL) && (*BlockSize < 512))) {
   1173 
   1174     return EFI_INVALID_PARAMETER;
   1175   }
   1176 
   1177   Status  = EFI_DEVICE_ERROR;
   1178   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
   1179   Mode    = &Private->Mode;
   1180 
   1181   if (!Mode->AutoArp) {
   1182     //
   1183     // If AutoArp is set false, check arp cache
   1184     //
   1185     UpdateArpCache (This);
   1186     if (!FindInArpCache (Mode, &ServerIp->v4, &TempMacAddr)) {
   1187       return EFI_DEVICE_ERROR;
   1188     }
   1189   }
   1190 
   1191   //
   1192   // Stop Udp4Read instance
   1193   //
   1194   Private->Udp4Read->Configure (Private->Udp4Read, NULL);
   1195 
   1196   Mode->TftpErrorReceived = FALSE;
   1197   Mode->IcmpErrorReceived = FALSE;
   1198 
   1199   Mtftp4Config.UseDefaultSetting = FALSE;
   1200   Mtftp4Config.TimeoutValue      = PXEBC_MTFTP_TIMEOUT;
   1201   Mtftp4Config.TryCount          = PXEBC_MTFTP_RETRIES;
   1202 
   1203   CopyMem (
   1204     &Mtftp4Config.StationIp,
   1205     &Private->StationIp,
   1206     sizeof (EFI_IPv4_ADDRESS)
   1207     );
   1208   CopyMem (
   1209     &Mtftp4Config.SubnetMask,
   1210     &Private->SubnetMask,
   1211     sizeof (EFI_IPv4_ADDRESS)
   1212     );
   1213   CopyMem (
   1214     &Mtftp4Config.GatewayIp,
   1215     &Private->GatewayIp,
   1216     sizeof (EFI_IPv4_ADDRESS)
   1217     );
   1218   CopyMem (
   1219     &Mtftp4Config.ServerIp,
   1220     ServerIp,
   1221     sizeof (EFI_IPv4_ADDRESS)
   1222     );
   1223 
   1224   switch (Operation) {
   1225 
   1226   case EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE:
   1227 
   1228     Status = PxeBcTftpGetFileSize (
   1229               Private,
   1230               &Mtftp4Config,
   1231               Filename,
   1232               BlockSize,
   1233               BufferSize
   1234               );
   1235 
   1236     break;
   1237 
   1238   case EFI_PXE_BASE_CODE_TFTP_READ_FILE:
   1239 
   1240     Status = PxeBcTftpReadFile (
   1241               Private,
   1242               &Mtftp4Config,
   1243               Filename,
   1244               BlockSize,
   1245               BufferPtr,
   1246               BufferSize,
   1247               DontUseBuffer
   1248               );
   1249 
   1250     break;
   1251 
   1252   case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE:
   1253 
   1254     Status = PxeBcTftpWriteFile (
   1255               Private,
   1256               &Mtftp4Config,
   1257               Filename,
   1258               Overwrite,
   1259               BlockSize,
   1260               BufferPtr,
   1261               BufferSize
   1262               );
   1263 
   1264     break;
   1265 
   1266   case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY:
   1267 
   1268     Status = PxeBcTftpReadDirectory (
   1269               Private,
   1270               &Mtftp4Config,
   1271               Filename,
   1272               BlockSize,
   1273               BufferPtr,
   1274               BufferSize,
   1275               DontUseBuffer
   1276               );
   1277 
   1278     break;
   1279 
   1280   case EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE:
   1281   case EFI_PXE_BASE_CODE_MTFTP_READ_FILE:
   1282   case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY:
   1283     Status = EFI_UNSUPPORTED;
   1284     break;
   1285 
   1286   default:
   1287 
   1288     Status = EFI_INVALID_PARAMETER;
   1289     break;
   1290   }
   1291 
   1292   if (Status == EFI_ICMP_ERROR) {
   1293     Mode->IcmpErrorReceived = TRUE;
   1294   }
   1295 
   1296   if (EFI_ERROR (Status)) {
   1297     goto ON_EXIT;
   1298   }
   1299 
   1300 ON_EXIT:
   1301   Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);
   1302   //
   1303   // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP
   1304   // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
   1305   //
   1306   ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));
   1307   IpFilter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
   1308   This->SetIpFilter (This, &IpFilter);
   1309 
   1310   return Status;
   1311 }
   1312 
   1313 
   1314 /**
   1315   Writes a UDP packet to the network interface.
   1316 
   1317   This function writes a UDP packet specified by the (optional HeaderPtr and)
   1318   BufferPtr parameters to the network interface. The UDP header is automatically
   1319   built by this routine. It uses the parameters OpFlags, DestIp, DestPort, GatewayIp,
   1320   SrcIp, and SrcPort to build this header. If the packet is successfully built and
   1321   transmitted through the network interface, then EFI_SUCCESS will be returned.
   1322   If a timeout occurs during the transmission of the packet, then EFI_TIMEOUT will
   1323   be returned. If an ICMP error occurs during the transmission of the packet, then
   1324   the IcmpErrorReceived field is set to TRUE, the IcmpError field is filled in and
   1325   EFI_ICMP_ERROR will be returned. If the Callback Protocol does not return
   1326   EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, then EFI_ABORTED will be returned.
   1327 
   1328   @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
   1329   @param  OpFlags               The UDP operation flags.
   1330   @param  DestIp                The destination IP address.
   1331   @param  DestPort              The destination UDP port number.
   1332   @param  GatewayIp             The gateway IP address.
   1333   @param  SrcIp                 The source IP address.
   1334   @param  SrcPort               The source UDP port number.
   1335   @param  HeaderSize            An optional field which may be set to the length of a header at
   1336                                 HeaderPtr to be prefixed to the data at BufferPtr.
   1337   @param  HeaderPtr             If HeaderSize is not NULL, a pointer to a header to be prefixed to the
   1338                                 data at BufferPtr.
   1339   @param  BufferSize            A pointer to the size of the data at BufferPtr.
   1340   @param  BufferPtr             A pointer to the data to be written.
   1341 
   1342   @retval EFI_SUCCESS           The UDP Write operation was completed.
   1343   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
   1344   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   1345   @retval EFI_BAD_BUFFER_SIZE   The buffer is too long to be transmitted.
   1346   @retval EFI_ABORTED           The callback function aborted the UDP Write operation.
   1347   @retval EFI_TIMEOUT           The UDP Write operation timed out.
   1348   @retval EFI_ICMP_ERROR        An ICMP error packet was received during the UDP write session.
   1349 
   1350 **/
   1351 EFI_STATUS
   1352 EFIAPI
   1353 EfiPxeBcUdpWrite (
   1354   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
   1355   IN UINT16                           OpFlags,
   1356   IN EFI_IP_ADDRESS                   *DestIp,
   1357   IN EFI_PXE_BASE_CODE_UDP_PORT       *DestPort,
   1358   IN EFI_IP_ADDRESS                   *GatewayIp  OPTIONAL,
   1359   IN EFI_IP_ADDRESS                   *SrcIp      OPTIONAL,
   1360   IN OUT EFI_PXE_BASE_CODE_UDP_PORT   *SrcPort    OPTIONAL,
   1361   IN UINTN                            *HeaderSize OPTIONAL,
   1362   IN VOID                             *HeaderPtr  OPTIONAL,
   1363   IN UINTN                            *BufferSize,
   1364   IN VOID                             *BufferPtr
   1365   )
   1366 {
   1367   PXEBC_PRIVATE_DATA        *Private;
   1368   EFI_UDP4_PROTOCOL         *Udp4;
   1369   EFI_UDP4_COMPLETION_TOKEN Token;
   1370   EFI_UDP4_TRANSMIT_DATA    *Udp4TxData;
   1371   UINT32                    FragCount;
   1372   UINT32                    DataLength;
   1373   EFI_UDP4_SESSION_DATA     Udp4Session;
   1374   EFI_STATUS                Status;
   1375   BOOLEAN                   IsDone;
   1376   EFI_PXE_BASE_CODE_MODE    *Mode;
   1377   EFI_MAC_ADDRESS           TempMacAddr;
   1378 
   1379   IsDone = FALSE;
   1380 
   1381   if ((This == NULL) || (DestIp == NULL) || (DestPort == NULL)) {
   1382     return EFI_INVALID_PARAMETER;
   1383   }
   1384 
   1385   if ((GatewayIp != NULL) && (IP4_IS_UNSPECIFIED (NTOHL (GatewayIp->Addr[0])) || IP4_IS_LOCAL_BROADCAST (NTOHL (GatewayIp->Addr[0])))) {
   1386     //
   1387     // Gateway is provided but it's not a unicast IP address.
   1388     //
   1389     return EFI_INVALID_PARAMETER;
   1390   }
   1391 
   1392   if ((HeaderSize != NULL) && ((*HeaderSize == 0) || (HeaderPtr == NULL))) {
   1393     //
   1394     // The HeaderSize ptr isn't NULL and: 1. the value is zero; or 2. the HeaderPtr
   1395     // is NULL.
   1396     //
   1397     return EFI_INVALID_PARAMETER;
   1398   }
   1399 
   1400   if ((BufferSize == NULL) || ((*BufferSize != 0) && (BufferPtr == NULL))) {
   1401     return EFI_INVALID_PARAMETER;
   1402   }
   1403 
   1404   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
   1405   Udp4    = Private->Udp4Write;
   1406   Mode    = &Private->Mode;
   1407   if (!Mode->Started) {
   1408     return EFI_NOT_STARTED;
   1409   }
   1410 
   1411   if (!Private->AddressIsOk && (SrcIp == NULL)) {
   1412     return EFI_INVALID_PARAMETER;
   1413   }
   1414 
   1415   if (!Mode->AutoArp) {
   1416     //
   1417     // If AutoArp is set false, check arp cache
   1418     //
   1419     UpdateArpCache (This);
   1420     if (!FindInArpCache (Mode, &DestIp->v4, &TempMacAddr)) {
   1421       return EFI_DEVICE_ERROR;
   1422     }
   1423   }
   1424 
   1425   Mode->IcmpErrorReceived = FALSE;
   1426 
   1427   if ((Private->CurrentUdpSrcPort == 0) ||
   1428       ((SrcPort != NULL) && (*SrcPort != Private->CurrentUdpSrcPort))) {
   1429     //
   1430     // Port is changed, (re)configure the Udp4Write instance
   1431     //
   1432     if (SrcPort != NULL) {
   1433       Private->CurrentUdpSrcPort = *SrcPort;
   1434     }
   1435   }
   1436 
   1437   Status = PxeBcConfigureUdpWriteInstance (
   1438              Udp4,
   1439              &Private->StationIp.v4,
   1440              &Private->SubnetMask.v4,
   1441              &Private->GatewayIp.v4,
   1442              &Private->CurrentUdpSrcPort,
   1443              Private->Mode.TTL,
   1444              Private->Mode.ToS
   1445              );
   1446   if (EFI_ERROR (Status)) {
   1447     Private->CurrentUdpSrcPort = 0;
   1448     return EFI_INVALID_PARAMETER;
   1449   }
   1450 
   1451   ZeroMem (&Token, sizeof (EFI_UDP4_COMPLETION_TOKEN));
   1452   ZeroMem (&Udp4Session, sizeof (EFI_UDP4_SESSION_DATA));
   1453 
   1454   CopyMem (&Udp4Session.DestinationAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));
   1455   Udp4Session.DestinationPort = *DestPort;
   1456   if (SrcIp != NULL) {
   1457     CopyMem (&Udp4Session.SourceAddress, SrcIp, sizeof (EFI_IPv4_ADDRESS));
   1458   }
   1459   if (SrcPort != NULL) {
   1460     Udp4Session.SourcePort = *SrcPort;
   1461   }
   1462 
   1463   FragCount = (HeaderSize != NULL) ? 2 : 1;
   1464   Udp4TxData = (EFI_UDP4_TRANSMIT_DATA *) AllocateZeroPool (sizeof (EFI_UDP4_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA));
   1465   if (Udp4TxData == NULL) {
   1466     return EFI_OUT_OF_RESOURCES;
   1467   }
   1468 
   1469   Udp4TxData->FragmentCount = FragCount;
   1470   Udp4TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32) *BufferSize;
   1471   Udp4TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;
   1472   DataLength = (UINT32) *BufferSize;
   1473 
   1474   if (FragCount == 2) {
   1475 
   1476     Udp4TxData->FragmentTable[0].FragmentLength = (UINT32) *HeaderSize;
   1477     Udp4TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;
   1478     DataLength += (UINT32) *HeaderSize;
   1479   }
   1480 
   1481   if (GatewayIp != NULL) {
   1482     Udp4TxData->GatewayAddress  = (EFI_IPv4_ADDRESS *) GatewayIp;
   1483   }
   1484   Udp4TxData->UdpSessionData  = &Udp4Session;
   1485   Udp4TxData->DataLength      = DataLength;
   1486   Token.Packet.TxData         = Udp4TxData;
   1487 
   1488   Status = gBS->CreateEvent (
   1489                   EVT_NOTIFY_SIGNAL,
   1490                   TPL_NOTIFY,
   1491                   PxeBcCommonNotify,
   1492                   &IsDone,
   1493                   &Token.Event
   1494                   );
   1495   if (EFI_ERROR (Status)) {
   1496     goto ON_EXIT;
   1497   }
   1498 
   1499   Status = Udp4->Transmit (Udp4, &Token);
   1500   if (EFI_ERROR (Status)) {
   1501     if (Status == EFI_ICMP_ERROR) {
   1502       Mode->IcmpErrorReceived = TRUE;
   1503     }
   1504     goto ON_EXIT;
   1505   }
   1506 
   1507   while (!IsDone) {
   1508 
   1509     Udp4->Poll (Udp4);
   1510   }
   1511 
   1512   Status = Token.Status;
   1513 
   1514 ON_EXIT:
   1515 
   1516   if (Token.Event != NULL) {
   1517     gBS->CloseEvent (Token.Event);
   1518   }
   1519 
   1520   FreePool (Udp4TxData);
   1521 
   1522   //
   1523   // Reset the instance.
   1524   //
   1525   Udp4->Configure (Udp4, NULL);
   1526   return Status;
   1527 }
   1528 
   1529 /**
   1530   Decide whether the incoming UDP packet is acceptable per IP filter settings
   1531   in provided PxeBcMode.
   1532 
   1533   @param  PxeBcMode          Pointer to EFI_PXE_BASE_CODE_MODE.
   1534   @param  Session            Received UDP session.
   1535 
   1536   @retval TRUE               The UDP package matches IP filters.
   1537   @retval FALSE              The UDP package doesn't matches IP filters.
   1538 
   1539 **/
   1540 BOOLEAN
   1541 CheckIpByFilter (
   1542   IN EFI_PXE_BASE_CODE_MODE    *PxeBcMode,
   1543   IN EFI_UDP4_SESSION_DATA     *Session
   1544   )
   1545 {
   1546   UINTN                   Index;
   1547   EFI_IPv4_ADDRESS        Ip4Address;
   1548   EFI_IPv4_ADDRESS        DestIp4Address;
   1549 
   1550   if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != 0) {
   1551     return TRUE;
   1552   }
   1553 
   1554   CopyMem (&DestIp4Address, &Session->DestinationAddress, sizeof (DestIp4Address));
   1555   if (((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) != 0) &&
   1556       IP4_IS_MULTICAST (EFI_NTOHL (DestIp4Address))
   1557       ) {
   1558     return TRUE;
   1559   }
   1560 
   1561   if (((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0) &&
   1562       IP4_IS_LOCAL_BROADCAST (EFI_NTOHL (DestIp4Address))
   1563       ) {
   1564     return TRUE;
   1565   }
   1566 
   1567   CopyMem (&Ip4Address, &PxeBcMode->StationIp.v4, sizeof (Ip4Address));
   1568   if (((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0) &&
   1569       EFI_IP4_EQUAL (&Ip4Address, &DestIp4Address)
   1570       ) {
   1571     return TRUE;
   1572   }
   1573 
   1574   ASSERT (PxeBcMode->IpFilter.IpCnt < EFI_PXE_BASE_CODE_MAX_IPCNT);
   1575 
   1576   for (Index = 0; Index < PxeBcMode->IpFilter.IpCnt; Index++) {
   1577     CopyMem (
   1578       &Ip4Address,
   1579       &PxeBcMode->IpFilter.IpList[Index].v4,
   1580       sizeof (Ip4Address)
   1581       );
   1582     if (EFI_IP4_EQUAL (&Ip4Address, &DestIp4Address)) {
   1583       return TRUE;
   1584     }
   1585   }
   1586 
   1587   return FALSE;
   1588 }
   1589 
   1590 /**
   1591   Reads a UDP packet from the network interface.
   1592 
   1593   This function reads a UDP packet from a network interface. The data contents
   1594   are returned in (the optional HeaderPtr and) BufferPtr, and the size of the
   1595   buffer received is returned in BufferSize . If the input BufferSize is smaller
   1596   than the UDP packet received (less optional HeaderSize), it will be set to the
   1597   required size, and EFI_BUFFER_TOO_SMALL will be returned. In this case, the
   1598   contents of BufferPtr are undefined, and the packet is lost. If a UDP packet is
   1599   successfully received, then EFI_SUCCESS will be returned, and the information
   1600   from the UDP header will be returned in DestIp, DestPort, SrcIp, and SrcPort if
   1601   they are not NULL. Depending on the values of OpFlags and the DestIp, DestPort,
   1602   SrcIp, and SrcPort input values, different types of UDP packet receive filtering
   1603   will be performed. The following tables summarize these receive filter operations.
   1604 
   1605   @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
   1606   @param  OpFlags               The UDP operation flags.
   1607   @param  DestIp                The destination IP address.
   1608   @param  DestPort              The destination UDP port number.
   1609   @param  SrcIp                 The source IP address.
   1610   @param  SrcPort               The source UDP port number.
   1611   @param  HeaderSize            An optional field which may be set to the length of a header at
   1612                                 HeaderPtr to be prefixed to the data at BufferPtr.
   1613   @param  HeaderPtr             If HeaderSize is not NULL, a pointer to a header to be prefixed to the
   1614                                 data at BufferPtr.
   1615   @param  BufferSize            A pointer to the size of the data at BufferPtr.
   1616   @param  BufferPtr             A pointer to the data to be read.
   1617 
   1618   @retval EFI_SUCCESS           The UDP Read operation was completed.
   1619   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
   1620   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   1621   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
   1622   @retval EFI_BUFFER_TOO_SMALL  The packet is larger than Buffer can hold.
   1623   @retval EFI_ABORTED           The callback function aborted the UDP Read operation.
   1624   @retval EFI_TIMEOUT           The UDP Read operation timed out.
   1625 
   1626 **/
   1627 EFI_STATUS
   1628 EFIAPI
   1629 EfiPxeBcUdpRead (
   1630   IN EFI_PXE_BASE_CODE_PROTOCOL                *This,
   1631   IN UINT16                                    OpFlags,
   1632   IN OUT EFI_IP_ADDRESS                        *DestIp     OPTIONAL,
   1633   IN OUT EFI_PXE_BASE_CODE_UDP_PORT            *DestPort   OPTIONAL,
   1634   IN OUT EFI_IP_ADDRESS                        *SrcIp      OPTIONAL,
   1635   IN OUT EFI_PXE_BASE_CODE_UDP_PORT            *SrcPort    OPTIONAL,
   1636   IN UINTN                                     *HeaderSize OPTIONAL,
   1637   IN VOID                                      *HeaderPtr  OPTIONAL,
   1638   IN OUT UINTN                                 *BufferSize,
   1639   IN VOID                                      *BufferPtr
   1640   )
   1641 {
   1642   PXEBC_PRIVATE_DATA        *Private;
   1643   EFI_PXE_BASE_CODE_MODE    *Mode;
   1644   EFI_UDP4_PROTOCOL         *Udp4;
   1645   EFI_UDP4_COMPLETION_TOKEN Token;
   1646   EFI_UDP4_RECEIVE_DATA     *RxData;
   1647   EFI_UDP4_SESSION_DATA     *Session;
   1648   EFI_STATUS                Status;
   1649   BOOLEAN                   IsDone;
   1650   BOOLEAN                   Matched;
   1651   UINTN                     CopiedLen;
   1652   UINTN                     HeaderLen;
   1653   UINTN                     HeaderCopiedLen;
   1654   UINTN                     BufferCopiedLen;
   1655   UINT32                    FragmentLength;
   1656   UINTN                     FragmentIndex;
   1657   UINT8                     *FragmentBuffer;
   1658 
   1659   if (This == NULL || DestIp == NULL || DestPort == NULL) {
   1660     return EFI_INVALID_PARAMETER;
   1661   }
   1662 
   1663   if (((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) == 0 && (DestPort == NULL)) ||
   1664       ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) == 0 && (SrcIp == NULL)) ||
   1665       ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) == 0 && (SrcPort == NULL))) {
   1666     return EFI_INVALID_PARAMETER;
   1667   }
   1668 
   1669   if (((HeaderSize != NULL) && (*HeaderSize == 0)) || ((HeaderSize != NULL) && (HeaderPtr == NULL))) {
   1670     return EFI_INVALID_PARAMETER;
   1671   }
   1672 
   1673   if ((BufferSize == NULL) || (BufferPtr == NULL)) {
   1674     return EFI_INVALID_PARAMETER;
   1675   }
   1676 
   1677   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
   1678   Mode    = Private->PxeBc.Mode;
   1679   Udp4    = Private->Udp4Read;
   1680 
   1681   if (!Mode->Started) {
   1682     return EFI_NOT_STARTED;
   1683   }
   1684 
   1685   Mode->IcmpErrorReceived = FALSE;
   1686 
   1687   Status = gBS->CreateEvent (
   1688                   EVT_NOTIFY_SIGNAL,
   1689                   TPL_NOTIFY,
   1690                   PxeBcCommonNotify,
   1691                   &IsDone,
   1692                   &Token.Event
   1693                   );
   1694   if (EFI_ERROR (Status)) {
   1695     return EFI_OUT_OF_RESOURCES;
   1696   }
   1697 
   1698 TRY_AGAIN:
   1699 
   1700   IsDone = FALSE;
   1701   Status = Udp4->Receive (Udp4, &Token);
   1702   if (EFI_ERROR (Status)) {
   1703     if (Status == EFI_ICMP_ERROR) {
   1704       Mode->IcmpErrorReceived = TRUE;
   1705     }
   1706     goto ON_EXIT;
   1707   }
   1708 
   1709   Udp4->Poll (Udp4);
   1710 
   1711   if (!IsDone) {
   1712     Status = EFI_TIMEOUT;
   1713   } else {
   1714 
   1715     //
   1716     // check whether this packet matches the filters
   1717     //
   1718     if (EFI_ERROR (Token.Status)){
   1719       goto ON_EXIT;
   1720     }
   1721 
   1722     RxData  = Token.Packet.RxData;
   1723     Session = &RxData->UdpSession;
   1724 
   1725     Matched = TRUE;
   1726 
   1727     if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) != 0) {
   1728       Matched = FALSE;
   1729       //
   1730       // Check UDP package by IP filter settings
   1731       //
   1732       if (CheckIpByFilter (Mode, Session)) {
   1733         Matched = TRUE;
   1734       }
   1735     }
   1736 
   1737     if (Matched) {
   1738       Matched = FALSE;
   1739 
   1740       //
   1741       // Match the destination ip of the received udp dgram
   1742       //
   1743       if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP) != 0) {
   1744         Matched = TRUE;
   1745 
   1746         if (DestIp != NULL) {
   1747           CopyMem (DestIp, &Session->DestinationAddress, sizeof (EFI_IPv4_ADDRESS));
   1748         }
   1749       } else {
   1750         if (DestIp != NULL) {
   1751           if (EFI_IP4_EQUAL (DestIp, &Session->DestinationAddress)) {
   1752             Matched = TRUE;
   1753           }
   1754         } else {
   1755           if (EFI_IP4_EQUAL (&Private->StationIp, &Session->DestinationAddress)) {
   1756             Matched = TRUE;
   1757           }
   1758         }
   1759       }
   1760     }
   1761 
   1762     if (Matched) {
   1763       //
   1764       // Match the destination port of the received udp dgram
   1765       //
   1766       if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) != 0) {
   1767 
   1768         if (DestPort != NULL) {
   1769           *DestPort = Session->DestinationPort;
   1770         }
   1771       } else {
   1772 
   1773         if (*DestPort != Session->DestinationPort) {
   1774           Matched = FALSE;
   1775         }
   1776       }
   1777     }
   1778 
   1779     if (Matched) {
   1780       //
   1781       // Match the source ip of the received udp dgram
   1782       //
   1783       if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) != 0) {
   1784 
   1785         if (SrcIp != NULL) {
   1786           CopyMem (SrcIp, &Session->SourceAddress, sizeof (EFI_IPv4_ADDRESS));
   1787         }
   1788       } else {
   1789 
   1790         if (!EFI_IP4_EQUAL (SrcIp, &Session->SourceAddress)) {
   1791           Matched = FALSE;
   1792         }
   1793       }
   1794     }
   1795 
   1796     if (Matched) {
   1797       //
   1798       // Match the source port of the received udp dgram
   1799       //
   1800       if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) != 0) {
   1801 
   1802         if (SrcPort != NULL) {
   1803           *SrcPort = Session->SourcePort;
   1804         }
   1805       } else {
   1806 
   1807         if (*SrcPort != Session->SourcePort) {
   1808           Matched = FALSE;
   1809         }
   1810       }
   1811     }
   1812 
   1813     if (Matched) {
   1814       ASSERT (RxData != NULL);
   1815 
   1816       HeaderLen = 0;
   1817       if (HeaderSize != NULL) {
   1818         HeaderLen = MIN (*HeaderSize, RxData->DataLength);
   1819       }
   1820 
   1821       if (RxData->DataLength - HeaderLen > *BufferSize) {
   1822         Status = EFI_BUFFER_TOO_SMALL;
   1823       } else {
   1824         *HeaderSize = HeaderLen;
   1825         *BufferSize = RxData->DataLength - HeaderLen;
   1826 
   1827         HeaderCopiedLen = 0;
   1828         BufferCopiedLen = 0;
   1829         for (FragmentIndex = 0; FragmentIndex < RxData->FragmentCount; FragmentIndex++) {
   1830           FragmentLength = RxData->FragmentTable[FragmentIndex].FragmentLength;
   1831           FragmentBuffer = RxData->FragmentTable[FragmentIndex].FragmentBuffer;
   1832           if (HeaderCopiedLen + FragmentLength < HeaderLen) {
   1833             //
   1834             // Copy the header part of received data.
   1835             //
   1836             CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, FragmentLength);
   1837             HeaderCopiedLen += FragmentLength;
   1838           } else if (HeaderCopiedLen < HeaderLen) {
   1839             //
   1840             // Copy the header part of received data.
   1841             //
   1842             CopiedLen = HeaderLen - HeaderCopiedLen;
   1843             CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, CopiedLen);
   1844             HeaderCopiedLen += CopiedLen;
   1845 
   1846             //
   1847             // Copy the other part of received data.
   1848             //
   1849             CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer + CopiedLen, FragmentLength - CopiedLen);
   1850             BufferCopiedLen += (FragmentLength - CopiedLen);
   1851           } else {
   1852             //
   1853             // Copy the other part of received data.
   1854             //
   1855             CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer, FragmentLength);
   1856             BufferCopiedLen += FragmentLength;
   1857           }
   1858         }
   1859       }
   1860     } else {
   1861 
   1862       Status = EFI_TIMEOUT;
   1863     }
   1864 
   1865     //
   1866     // Recycle the RxData
   1867     //
   1868     gBS->SignalEvent (RxData->RecycleSignal);
   1869 
   1870     if (!Matched) {
   1871       goto TRY_AGAIN;
   1872     }
   1873   }
   1874 
   1875 ON_EXIT:
   1876 
   1877   Udp4->Cancel (Udp4, &Token);
   1878 
   1879   gBS->CloseEvent (Token.Event);
   1880 
   1881   return Status;
   1882 }
   1883 
   1884 /**
   1885   Updates the IP receive filters of a network device and enables software filtering.
   1886 
   1887   The NewFilter field is used to modify the network device's current IP receive
   1888   filter settings and to enable a software filter. This function updates the IpFilter
   1889   field of the EFI_PXE_BASE_CODE_MODE structure with the contents of NewIpFilter.
   1890   The software filter is used when the USE_FILTER in OpFlags is set to UdpRead().
   1891   The current hardware filter remains in effect no matter what the settings of OpFlags
   1892   are, so that the meaning of ANY_DEST_IP set in OpFlags to UdpRead() is from those
   1893   packets whose reception is enabled in hardware-physical NIC address (unicast),
   1894   broadcast address, logical address or addresses (multicast), or all (promiscuous).
   1895   UdpRead() does not modify the IP filter settings.
   1896   Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP receive
   1897   filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
   1898   If an application or driver wishes to preserve the IP receive filter settings,
   1899   it will have to preserve the IP receive filter settings before these calls, and
   1900   use SetIpFilter() to restore them after the calls. If incompatible filtering is
   1901   requested (for example, PROMISCUOUS with anything else) or if the device does not
   1902   support a requested filter setting and it cannot be accommodated in software
   1903   (for example, PROMISCUOUS not supported), EFI_INVALID_PARAMETER will be returned.
   1904   The IPlist field is used to enable IPs other than the StationIP. They may be
   1905   multicast or unicast. If IPcnt is set as well as EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP,
   1906   then both the StationIP and the IPs from the IPlist will be used.
   1907 
   1908   @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
   1909   @param  NewFilter             Pointer to the new set of IP receive filters.
   1910 
   1911   @retval EFI_SUCCESS           The IP receive filter settings were updated.
   1912   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
   1913   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   1914 
   1915 **/
   1916 EFI_STATUS
   1917 EFIAPI
   1918 EfiPxeBcSetIpFilter (
   1919   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
   1920   IN EFI_PXE_BASE_CODE_IP_FILTER      *NewFilter
   1921   )
   1922 {
   1923   EFI_STATUS                Status;
   1924   PXEBC_PRIVATE_DATA        *Private;
   1925   EFI_PXE_BASE_CODE_MODE    *Mode;
   1926   UINTN                     Index;
   1927   EFI_UDP4_CONFIG_DATA      *Udp4Cfg;
   1928   BOOLEAN                   PromiscuousNeed;
   1929   BOOLEAN                   AcceptPromiscuous;
   1930   BOOLEAN                   AcceptBroadcast;
   1931   BOOLEAN                   MultiCastUpdate;
   1932 
   1933   if (This == NULL) {
   1934     DEBUG ((EFI_D_ERROR, "This == NULL.\n"));
   1935     return EFI_INVALID_PARAMETER;
   1936   }
   1937 
   1938   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
   1939   Mode = Private->PxeBc.Mode;
   1940 
   1941   if (NewFilter == NULL) {
   1942     DEBUG ((EFI_D_ERROR, "NewFilter == NULL.\n"));
   1943     return EFI_INVALID_PARAMETER;
   1944   }
   1945 
   1946   if (NewFilter->IpCnt > EFI_PXE_BASE_CODE_MAX_IPCNT) {
   1947     DEBUG ((EFI_D_ERROR, "NewFilter->IpCnt > %d.\n", EFI_PXE_BASE_CODE_MAX_IPCNT));
   1948     return EFI_INVALID_PARAMETER;
   1949   }
   1950 
   1951   if (!Mode->Started) {
   1952     DEBUG ((EFI_D_ERROR, "BC was not started.\n"));
   1953     return EFI_NOT_STARTED;
   1954   }
   1955 
   1956   if (Mode->UsingIpv6) {
   1957     DEBUG ((EFI_D_ERROR, "This driver is PXE for IPv4 Only.\n"));
   1958     return EFI_INVALID_PARAMETER;
   1959   }
   1960 
   1961   PromiscuousNeed = FALSE;
   1962 
   1963   for (Index = 0; Index < NewFilter->IpCnt; ++Index) {
   1964     if (IP4_IS_LOCAL_BROADCAST (EFI_IP4 (NewFilter->IpList[Index].v4))) {
   1965       //
   1966       // The IP is a broadcast address.
   1967       //
   1968       DEBUG ((EFI_D_ERROR, "There is broadcast address in NewFilter.\n"));
   1969       return EFI_INVALID_PARAMETER;
   1970     }
   1971     if ((EFI_NTOHL(Mode->StationIp) != 0) &&
   1972         (EFI_NTOHL(Mode->SubnetMask) != 0) &&
   1973         IP4_NET_EQUAL(EFI_NTOHL(Mode->StationIp), EFI_NTOHL(NewFilter->IpList[Index].v4), EFI_NTOHL(Mode->SubnetMask)) &&
   1974         NetIp4IsUnicast (EFI_IP4 (NewFilter->IpList[Index].v4), EFI_NTOHL(Mode->SubnetMask)) &&
   1975         ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0)) {
   1976       //
   1977       // If EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP is set and IP4 address is in IpList,
   1978       // promiscuous mode is needed.
   1979       //
   1980       PromiscuousNeed = TRUE;
   1981     }
   1982   }
   1983 
   1984   AcceptPromiscuous = FALSE;
   1985   AcceptBroadcast   = FALSE;
   1986   MultiCastUpdate   = FALSE;
   1987 
   1988   if (PromiscuousNeed ||
   1989       ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != 0) ||
   1990       ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) != 0)
   1991      ) {
   1992     //
   1993     // Configure the udp4 filter to receive all packages.
   1994     //
   1995     AcceptPromiscuous  = TRUE;
   1996   } else if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0) {
   1997     //
   1998     // Configure the udp4 filter to receive all broadcast packages.
   1999     //
   2000     AcceptBroadcast   = TRUE;
   2001   }
   2002 
   2003   //
   2004   // In multicast condition when Promiscuous FALSE and IpCnt no-zero.
   2005   // Here check if there is any update of the multicast ip address. If yes,
   2006   // we need leave the old multicast group (by Config UDP instance to NULL),
   2007   // and join the new multicast group.
   2008   //
   2009   if (!AcceptPromiscuous) {
   2010     if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0) {
   2011       if (Mode->IpFilter.IpCnt != NewFilter->IpCnt) {
   2012         MultiCastUpdate = TRUE;
   2013       } else if (CompareMem (Mode->IpFilter.IpList, NewFilter->IpList, NewFilter->IpCnt * sizeof (EFI_IP_ADDRESS)) != 0 ) {
   2014         MultiCastUpdate = TRUE;
   2015       }
   2016     }
   2017   }
   2018 
   2019   //
   2020   // Check whether we need reconfigure the UDP instance.
   2021   //
   2022   Udp4Cfg = &Private->Udp4CfgData;
   2023   if ((AcceptPromiscuous != Udp4Cfg->AcceptPromiscuous) ||
   2024   	  (AcceptBroadcast != Udp4Cfg->AcceptBroadcast)     || MultiCastUpdate) {
   2025     //
   2026     // Clear the UDP instance configuration, all joined groups will be left
   2027     // during the operation.
   2028     //
   2029     Private->Udp4Read->Configure (Private->Udp4Read, NULL);
   2030 
   2031     //
   2032     // Configure the UDP instance with the new configuration.
   2033     //
   2034     Udp4Cfg->AcceptPromiscuous = AcceptPromiscuous;
   2035     Udp4Cfg->AcceptBroadcast   = AcceptBroadcast;
   2036     Status = Private->Udp4Read->Configure (Private->Udp4Read, Udp4Cfg);
   2037     if (EFI_ERROR (Status)) {
   2038       return Status;
   2039     }
   2040 
   2041     //
   2042     // In not Promiscuous mode, need to join the new multicast group.
   2043     //
   2044     if (!AcceptPromiscuous) {
   2045       for (Index = 0; Index < NewFilter->IpCnt; ++Index) {
   2046         if (IP4_IS_MULTICAST (EFI_NTOHL (NewFilter->IpList[Index].v4))) {
   2047           //
   2048           // Join the mutilcast group.
   2049           //
   2050           Status = Private->Udp4Read->Groups (Private->Udp4Read, TRUE, &NewFilter->IpList[Index].v4);
   2051           if (EFI_ERROR (Status)) {
   2052             return Status;
   2053           }
   2054         }
   2055       }
   2056     }
   2057   }
   2058 
   2059 
   2060   //
   2061   // Save the new filter.
   2062   //
   2063   CopyMem (&Mode->IpFilter, NewFilter, sizeof (Mode->IpFilter));
   2064 
   2065   return EFI_SUCCESS;
   2066 }
   2067 
   2068 
   2069 /**
   2070   Uses the ARP protocol to resolve a MAC address.
   2071 
   2072   This function uses the ARP protocol to resolve a MAC address. The UsingIpv6 field
   2073   of the EFI_PXE_BASE_CODE_MODE structure is used to determine if IPv4 or IPv6
   2074   addresses are being used. The IP address specified by IpAddr is used to resolve
   2075   a MAC address. If the ARP protocol succeeds in resolving the specified address,
   2076   then the ArpCacheEntries and ArpCache fields of the EFI_PXE_BASE_CODE_MODE structure
   2077   are updated, and EFI_SUCCESS is returned. If MacAddr is not NULL, the resolved
   2078   MAC address is placed there as well.  If the PXE Base Code protocol is in the
   2079   stopped state, then EFI_NOT_STARTED is returned. If the ARP protocol encounters
   2080   a timeout condition while attempting to resolve an address, then EFI_TIMEOUT is
   2081   returned. If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
   2082   then EFI_ABORTED is returned.
   2083 
   2084   @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
   2085   @param  IpAddr                Pointer to the IP address that is used to resolve a MAC address.
   2086   @param  MacAddr               If not NULL, a pointer to the MAC address that was resolved with the
   2087                                 ARP protocol.
   2088 
   2089   @retval EFI_SUCCESS           The IP or MAC address was resolved.
   2090   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
   2091   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   2092   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
   2093   @retval EFI_ICMP_ERROR        Something error occur with the ICMP packet message.
   2094 
   2095 **/
   2096 EFI_STATUS
   2097 EFIAPI
   2098 EfiPxeBcArp (
   2099   IN EFI_PXE_BASE_CODE_PROTOCOL       * This,
   2100   IN EFI_IP_ADDRESS                   * IpAddr,
   2101   IN EFI_MAC_ADDRESS                  * MacAddr OPTIONAL
   2102   )
   2103 {
   2104   PXEBC_PRIVATE_DATA      *Private;
   2105   EFI_PXE_BASE_CODE_MODE  *Mode;
   2106   EFI_STATUS              Status;
   2107   EFI_MAC_ADDRESS         TempMacAddr;
   2108 
   2109   if (This == NULL || IpAddr == NULL) {
   2110     return EFI_INVALID_PARAMETER;
   2111   }
   2112 
   2113   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
   2114   Mode    = Private->PxeBc.Mode;
   2115 
   2116   if (!Mode->Started) {
   2117     return EFI_NOT_STARTED;
   2118   }
   2119 
   2120   if (!Private->AddressIsOk || Mode->UsingIpv6) {
   2121     //
   2122     // We can't resolve the IP address if we don't have a local address now.
   2123     // Don't have ARP for IPv6.
   2124     //
   2125     return EFI_INVALID_PARAMETER;
   2126   }
   2127 
   2128   Mode->IcmpErrorReceived = FALSE;
   2129 
   2130   if (!Mode->AutoArp) {
   2131     //
   2132     // If AutoArp is set false, check arp cache
   2133     //
   2134     UpdateArpCache (This);
   2135     if (!FindInArpCache (Mode, &IpAddr->v4, &TempMacAddr)) {
   2136       return EFI_DEVICE_ERROR;
   2137     }
   2138   } else {
   2139     Status = Private->Arp->Request (Private->Arp, &IpAddr->v4, NULL, &TempMacAddr);
   2140     if (EFI_ERROR (Status)) {
   2141       if (Status == EFI_ICMP_ERROR) {
   2142         Mode->IcmpErrorReceived = TRUE;
   2143       }
   2144       return Status;
   2145     }
   2146   }
   2147 
   2148   if (MacAddr != NULL) {
   2149     CopyMem (MacAddr, &TempMacAddr, sizeof (EFI_MAC_ADDRESS));
   2150   }
   2151 
   2152   return EFI_SUCCESS;
   2153 }
   2154 
   2155 /**
   2156   Updates the parameters that affect the operation of the PXE Base Code Protocol.
   2157 
   2158   This function sets parameters that affect the operation of the PXE Base Code Protocol.
   2159   The parameter specified by NewAutoArp is used to control the generation of ARP
   2160   protocol packets. If NewAutoArp is TRUE, then ARP Protocol packets will be generated
   2161   as required by the PXE Base Code Protocol. If NewAutoArp is FALSE, then no ARP
   2162   Protocol packets will be generated. In this case, the only mappings that are
   2163   available are those stored in the ArpCache of the EFI_PXE_BASE_CODE_MODE structure.
   2164   If there are not enough mappings in the ArpCache to perform a PXE Base Code Protocol
   2165   service, then the service will fail. This function updates the AutoArp field of
   2166   the EFI_PXE_BASE_CODE_MODE structure to NewAutoArp.
   2167   The SetParameters() call must be invoked after a Callback Protocol is installed
   2168   to enable the use of callbacks.
   2169 
   2170   @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
   2171   @param  NewAutoArp            If not NULL, a pointer to a value that specifies whether to replace the
   2172                                 current value of AutoARP.
   2173   @param  NewSendGUID           If not NULL, a pointer to a value that specifies whether to replace the
   2174                                 current value of SendGUID.
   2175   @param  NewTTL                If not NULL, a pointer to be used in place of the current value of TTL,
   2176                                 the "time to live" field of the IP header.
   2177   @param  NewToS                If not NULL, a pointer to be used in place of the current value of ToS,
   2178                                 the "type of service" field of the IP header.
   2179   @param  NewMakeCallback       If not NULL, a pointer to a value that specifies whether to replace the
   2180                                 current value of the MakeCallback field of the Mode structure.
   2181 
   2182   @retval EFI_SUCCESS           The new parameters values were updated.
   2183   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
   2184   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   2185 
   2186 **/
   2187 EFI_STATUS
   2188 EFIAPI
   2189 EfiPxeBcSetParameters (
   2190   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
   2191   IN BOOLEAN                          *NewAutoArp OPTIONAL,
   2192   IN BOOLEAN                          *NewSendGUID OPTIONAL,
   2193   IN UINT8                            *NewTTL OPTIONAL,
   2194   IN UINT8                            *NewToS OPTIONAL,
   2195   IN BOOLEAN                          *NewMakeCallback  // OPTIONAL
   2196   )
   2197 {
   2198   PXEBC_PRIVATE_DATA      *Private;
   2199   EFI_PXE_BASE_CODE_MODE  *Mode;
   2200   EFI_STATUS              Status;
   2201 
   2202   Status = EFI_SUCCESS;
   2203 
   2204   if (This == NULL) {
   2205     Status = EFI_INVALID_PARAMETER;
   2206     goto ON_EXIT;
   2207   }
   2208 
   2209   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
   2210   Mode    = Private->PxeBc.Mode;
   2211 
   2212   if (NewSendGUID != NULL && *NewSendGUID) {
   2213     //
   2214     // FixMe, cann't locate SendGuid
   2215     //
   2216   }
   2217 
   2218   if (NewMakeCallback != NULL && *NewMakeCallback) {
   2219 
   2220     Status = gBS->HandleProtocol (
   2221                     Private->Controller,
   2222                     &gEfiPxeBaseCodeCallbackProtocolGuid,
   2223                     (VOID **) &Private->PxeBcCallback
   2224                     );
   2225     if (EFI_ERROR (Status) || (Private->PxeBcCallback->Callback == NULL)) {
   2226 
   2227       Status = EFI_INVALID_PARAMETER;
   2228       goto ON_EXIT;
   2229     }
   2230   }
   2231 
   2232   if (!Mode->Started) {
   2233     Status = EFI_NOT_STARTED;
   2234     goto ON_EXIT;
   2235   }
   2236 
   2237   if (NewMakeCallback != NULL) {
   2238 
   2239     if (*NewMakeCallback) {
   2240       //
   2241       // Update the Callback protocol.
   2242       //
   2243       Status = gBS->HandleProtocol (
   2244                       Private->Controller,
   2245                       &gEfiPxeBaseCodeCallbackProtocolGuid,
   2246                       (VOID **) &Private->PxeBcCallback
   2247                       );
   2248 
   2249       if (EFI_ERROR (Status) || (Private->PxeBcCallback->Callback == NULL)) {
   2250         Status = EFI_INVALID_PARAMETER;
   2251         goto ON_EXIT;
   2252       }
   2253     } else {
   2254       Private->PxeBcCallback = NULL;
   2255     }
   2256 
   2257     Mode->MakeCallbacks = *NewMakeCallback;
   2258   }
   2259 
   2260   if (NewAutoArp != NULL) {
   2261     Mode->AutoArp = *NewAutoArp;
   2262   }
   2263 
   2264   if (NewSendGUID != NULL) {
   2265     Mode->SendGUID = *NewSendGUID;
   2266   }
   2267 
   2268   if (NewTTL != NULL) {
   2269     Mode->TTL = *NewTTL;
   2270   }
   2271 
   2272   if (NewToS != NULL) {
   2273     Mode->ToS = *NewToS;
   2274   }
   2275 
   2276 ON_EXIT:
   2277   return Status;
   2278 }
   2279 
   2280 /**
   2281   Updates the station IP address and/or subnet mask values of a network device.
   2282 
   2283   This function updates the station IP address and/or subnet mask values of a network
   2284   device. The NewStationIp field is used to modify the network device's current IP address.
   2285   If NewStationIP is NULL, then the current IP address will not be modified. Otherwise,
   2286   this function updates the StationIp field of the EFI_PXE_BASE_CODE_MODE structure
   2287   with NewStationIp. The NewSubnetMask field is used to modify the network device's current subnet
   2288   mask. If NewSubnetMask is NULL, then the current subnet mask will not be modified.
   2289   Otherwise, this function updates the SubnetMask field of the EFI_PXE_BASE_CODE_MODE
   2290   structure with NewSubnetMask.
   2291 
   2292   @param  This                  Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
   2293   @param  NewStationIp          Pointer to the new IP address to be used by the network device.
   2294   @param  NewSubnetMask         Pointer to the new subnet mask to be used by the network device.
   2295 
   2296   @retval EFI_SUCCESS           The new station IP address and/or subnet mask were updated.
   2297   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
   2298   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   2299 
   2300 **/
   2301 EFI_STATUS
   2302 EFIAPI
   2303 EfiPxeBcSetStationIP (
   2304   IN EFI_PXE_BASE_CODE_PROTOCOL       * This,
   2305   IN EFI_IP_ADDRESS                   * NewStationIp  OPTIONAL,
   2306   IN EFI_IP_ADDRESS                   * NewSubnetMask OPTIONAL
   2307   )
   2308 {
   2309   PXEBC_PRIVATE_DATA      *Private;
   2310   EFI_PXE_BASE_CODE_MODE  *Mode;
   2311   EFI_ARP_CONFIG_DATA     ArpConfigData;
   2312 
   2313   if (This == NULL) {
   2314     return EFI_INVALID_PARAMETER;
   2315   }
   2316 
   2317   if (NewSubnetMask != NULL && !IP4_IS_VALID_NETMASK (NTOHL (NewSubnetMask->Addr[0]))) {
   2318     return EFI_INVALID_PARAMETER;
   2319   }
   2320 
   2321   if (NewStationIp != NULL) {
   2322     if (IP4_IS_UNSPECIFIED(NTOHL (NewStationIp->Addr[0])) ||
   2323         IP4_IS_LOCAL_BROADCAST(NTOHL (NewStationIp->Addr[0])) ||
   2324         (NewSubnetMask != NULL && !NetIp4IsUnicast (NTOHL (NewStationIp->Addr[0]), NTOHL (NewSubnetMask->Addr[0])))) {
   2325       return EFI_INVALID_PARAMETER;
   2326     }
   2327   }
   2328 
   2329   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
   2330   Mode    = Private->PxeBc.Mode;
   2331 
   2332   if (!Mode->Started) {
   2333     return EFI_NOT_STARTED;
   2334   }
   2335 
   2336   if (NewStationIp != NULL) {
   2337     CopyMem (&Mode->StationIp, NewStationIp, sizeof (EFI_IP_ADDRESS));
   2338     CopyMem (&Private->StationIp, NewStationIp, sizeof (EFI_IP_ADDRESS));
   2339   }
   2340 
   2341   if (NewSubnetMask != NULL) {
   2342     CopyMem (&Mode->SubnetMask, NewSubnetMask, sizeof (EFI_IP_ADDRESS));
   2343     CopyMem (&Private->SubnetMask ,NewSubnetMask, sizeof (EFI_IP_ADDRESS));
   2344   }
   2345 
   2346   Private->AddressIsOk = TRUE;
   2347 
   2348   if (!Mode->UsingIpv6) {
   2349     //
   2350     // If in IPv4 mode, configure the corresponding ARP with this new
   2351     // station IP address.
   2352     //
   2353     ZeroMem (&ArpConfigData, sizeof (EFI_ARP_CONFIG_DATA));
   2354 
   2355     ArpConfigData.SwAddressType   = 0x0800;
   2356     ArpConfigData.SwAddressLength = (UINT8) sizeof (EFI_IPv4_ADDRESS);
   2357     ArpConfigData.StationAddress  = &Private->StationIp.v4;
   2358 
   2359     Private->Arp->Configure (Private->Arp, NULL);
   2360     Private->Arp->Configure (Private->Arp, &ArpConfigData);
   2361 
   2362     //
   2363     // Update the route table.
   2364     //
   2365     Mode->RouteTableEntries                = 1;
   2366     Mode->RouteTable[0].IpAddr.Addr[0]     = Private->StationIp.Addr[0] & Private->SubnetMask.Addr[0];
   2367     Mode->RouteTable[0].SubnetMask.Addr[0] = Private->SubnetMask.Addr[0];
   2368     Mode->RouteTable[0].GwAddr.Addr[0]     = 0;
   2369   }
   2370 
   2371   return EFI_SUCCESS;
   2372 }
   2373 
   2374 /**
   2375   Updates the contents of the cached DHCP and Discover packets.
   2376 
   2377   The pointers to the new packets are used to update the contents of the cached
   2378   packets in the EFI_PXE_BASE_CODE_MODE structure.
   2379 
   2380   @param  This                   Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
   2381   @param  NewDhcpDiscoverValid   Pointer to a value that will replace the current
   2382                                  DhcpDiscoverValid field.
   2383   @param  NewDhcpAckReceived     Pointer to a value that will replace the current
   2384                                  DhcpAckReceived field.
   2385   @param  NewProxyOfferReceived  Pointer to a value that will replace the current
   2386                                  ProxyOfferReceived field.
   2387   @param  NewPxeDiscoverValid    Pointer to a value that will replace the current
   2388                                  ProxyOfferReceived field.
   2389   @param  NewPxeReplyReceived    Pointer to a value that will replace the current
   2390                                  PxeReplyReceived field.
   2391   @param  NewPxeBisReplyReceived Pointer to a value that will replace the current
   2392                                  PxeBisReplyReceived field.
   2393   @param  NewDhcpDiscover        Pointer to the new cached DHCP Discover packet contents.
   2394   @param  NewDhcpAck             Pointer to the new cached DHCP Ack packet contents.
   2395   @param  NewProxyOffer          Pointer to the new cached Proxy Offer packet contents.
   2396   @param  NewPxeDiscover         Pointer to the new cached PXE Discover packet contents.
   2397   @param  NewPxeReply            Pointer to the new cached PXE Reply packet contents.
   2398   @param  NewPxeBisReply         Pointer to the new cached PXE BIS Reply packet contents.
   2399 
   2400   @retval EFI_SUCCESS            The cached packet contents were updated.
   2401   @retval EFI_NOT_STARTED        The PXE Base Code Protocol is in the stopped state.
   2402   @retval EFI_INVALID_PARAMETER  This is NULL or not point to a valid EFI_PXE_BASE_CODE_PROTOCOL structure.
   2403 
   2404 **/
   2405 EFI_STATUS
   2406 EFIAPI
   2407 EfiPxeBcSetPackets (
   2408   IN EFI_PXE_BASE_CODE_PROTOCOL       * This,
   2409   IN BOOLEAN                          * NewDhcpDiscoverValid OPTIONAL,
   2410   IN BOOLEAN                          * NewDhcpAckReceived OPTIONAL,
   2411   IN BOOLEAN                          * NewProxyOfferReceived OPTIONAL,
   2412   IN BOOLEAN                          * NewPxeDiscoverValid OPTIONAL,
   2413   IN BOOLEAN                          * NewPxeReplyReceived OPTIONAL,
   2414   IN BOOLEAN                          * NewPxeBisReplyReceived OPTIONAL,
   2415   IN EFI_PXE_BASE_CODE_PACKET         * NewDhcpDiscover OPTIONAL,
   2416   IN EFI_PXE_BASE_CODE_PACKET         * NewDhcpAck OPTIONAL,
   2417   IN EFI_PXE_BASE_CODE_PACKET         * NewProxyOffer OPTIONAL,
   2418   IN EFI_PXE_BASE_CODE_PACKET         * NewPxeDiscover OPTIONAL,
   2419   IN EFI_PXE_BASE_CODE_PACKET         * NewPxeReply OPTIONAL,
   2420   IN EFI_PXE_BASE_CODE_PACKET         * NewPxeBisReply OPTIONAL
   2421   )
   2422 {
   2423   PXEBC_PRIVATE_DATA      *Private;
   2424   EFI_PXE_BASE_CODE_MODE  *Mode;
   2425 
   2426   if (This == NULL) {
   2427     return EFI_INVALID_PARAMETER;
   2428   }
   2429 
   2430   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
   2431   Mode    = Private->PxeBc.Mode;
   2432 
   2433   if (!Mode->Started) {
   2434     return EFI_NOT_STARTED;
   2435   }
   2436 
   2437   if (NewDhcpDiscoverValid != NULL) {
   2438     Mode->DhcpDiscoverValid = *NewDhcpDiscoverValid;
   2439   }
   2440 
   2441   if (NewDhcpAckReceived != NULL) {
   2442     Mode->DhcpAckReceived = *NewDhcpAckReceived;
   2443   }
   2444 
   2445   if (NewProxyOfferReceived != NULL) {
   2446     Mode->ProxyOfferReceived = *NewProxyOfferReceived;
   2447   }
   2448 
   2449   if (NewPxeDiscoverValid != NULL) {
   2450     Mode->PxeDiscoverValid = *NewPxeDiscoverValid;
   2451   }
   2452 
   2453   if (NewPxeReplyReceived != NULL) {
   2454     Mode->PxeReplyReceived = *NewPxeReplyReceived;
   2455   }
   2456 
   2457   if (NewPxeBisReplyReceived != NULL) {
   2458     Mode->PxeBisReplyReceived = *NewPxeBisReplyReceived;
   2459   }
   2460 
   2461   if (NewDhcpDiscover != NULL) {
   2462     CopyMem (&Mode->DhcpDiscover, NewDhcpDiscover, sizeof (EFI_PXE_BASE_CODE_PACKET));
   2463   }
   2464 
   2465   if (NewDhcpAck != NULL) {
   2466     CopyMem (&Mode->DhcpAck, NewDhcpAck, sizeof (EFI_PXE_BASE_CODE_PACKET));
   2467   }
   2468 
   2469   if (NewProxyOffer != NULL) {
   2470     CopyMem (&Mode->ProxyOffer, NewProxyOffer, sizeof (EFI_PXE_BASE_CODE_PACKET));
   2471   }
   2472 
   2473   if (NewPxeDiscover != NULL) {
   2474     CopyMem (&Mode->PxeDiscover, NewPxeDiscover, sizeof (EFI_PXE_BASE_CODE_PACKET));
   2475   }
   2476 
   2477   if (NewPxeReply != NULL) {
   2478     CopyMem (&Mode->PxeReply, NewPxeReply, sizeof (EFI_PXE_BASE_CODE_PACKET));
   2479   }
   2480 
   2481   if (NewPxeBisReply != NULL) {
   2482     CopyMem (&Mode->PxeBisReply, NewPxeBisReply, sizeof (EFI_PXE_BASE_CODE_PACKET));
   2483   }
   2484 
   2485   return EFI_SUCCESS;
   2486 }
   2487 
   2488 EFI_PXE_BASE_CODE_PROTOCOL  mPxeBcProtocolTemplate = {
   2489   EFI_PXE_BASE_CODE_PROTOCOL_REVISION,
   2490   EfiPxeBcStart,
   2491   EfiPxeBcStop,
   2492   EfiPxeBcDhcp,
   2493   EfiPxeBcDiscover,
   2494   EfiPxeBcMtftp,
   2495   EfiPxeBcUdpWrite,
   2496   EfiPxeBcUdpRead,
   2497   EfiPxeBcSetIpFilter,
   2498   EfiPxeBcArp,
   2499   EfiPxeBcSetParameters,
   2500   EfiPxeBcSetStationIP,
   2501   EfiPxeBcSetPackets,
   2502   NULL
   2503 };
   2504 
   2505 /**
   2506   Callback function that is invoked when the PXE Base Code Protocol is about to transmit, has
   2507   received, or is waiting to receive a packet.
   2508 
   2509   This function is invoked when the PXE Base Code Protocol is about to transmit, has received,
   2510   or is waiting to receive a packet. Parameters Function and Received specify the type of event.
   2511   Parameters PacketLen and Packet specify the packet that generated the event. If these fields
   2512   are zero and NULL respectively, then this is a status update callback. If the operation specified
   2513   by Function is to continue, then CALLBACK_STATUS_CONTINUE should be returned. If the operation
   2514   specified by Function should be aborted, then CALLBACK_STATUS_ABORT should be returned. Due to
   2515   the polling nature of UEFI device drivers, a callback function should not execute for more than 5 ms.
   2516   The SetParameters() function must be called after a Callback Protocol is installed to enable the
   2517   use of callbacks.
   2518 
   2519   @param  This                  Pointer to the EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL instance.
   2520   @param  Function              The PXE Base Code Protocol function that is waiting for an event.
   2521   @param  Received              TRUE if the callback is being invoked due to a receive event. FALSE if
   2522                                 the callback is being invoked due to a transmit event.
   2523   @param  PacketLength          The length, in bytes, of Packet. This field will have a value of zero if
   2524                                 this is a wait for receive event.
   2525   @param  PacketPtr             If Received is TRUE, a pointer to the packet that was just received;
   2526                                 otherwise a pointer to the packet that is about to be transmitted.
   2527 
   2528   @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE if Function specifies a continue operation
   2529   @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT    if Function specifies an abort operation
   2530 
   2531 **/
   2532 EFI_PXE_BASE_CODE_CALLBACK_STATUS
   2533 EFIAPI
   2534 EfiPxeLoadFileCallback (
   2535   IN EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL  * This,
   2536   IN EFI_PXE_BASE_CODE_FUNCTION           Function,
   2537   IN BOOLEAN                              Received,
   2538   IN UINT32                               PacketLength,
   2539   IN EFI_PXE_BASE_CODE_PACKET             * PacketPtr OPTIONAL
   2540   )
   2541 {
   2542   EFI_INPUT_KEY Key;
   2543   EFI_STATUS    Status;
   2544 
   2545   //
   2546   // Catch Ctrl-C or ESC to abort.
   2547   //
   2548   Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
   2549 
   2550   if (!EFI_ERROR (Status)) {
   2551 
   2552     if (Key.ScanCode == SCAN_ESC || Key.UnicodeChar == (0x1F & 'c')) {
   2553 
   2554       return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;
   2555     }
   2556   }
   2557   //
   2558   // No print if receive packet
   2559   //
   2560   if (Received) {
   2561     return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
   2562   }
   2563   //
   2564   // Print only for three functions
   2565   //
   2566   switch (Function) {
   2567 
   2568   case EFI_PXE_BASE_CODE_FUNCTION_MTFTP:
   2569     //
   2570     // Print only for open MTFTP packets, not every MTFTP packets
   2571     //
   2572     if (PacketLength != 0 && PacketPtr != NULL) {
   2573       if (PacketPtr->Raw[0x1C] != 0x00 || PacketPtr->Raw[0x1D] != 0x01) {
   2574         return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
   2575       }
   2576     }
   2577     break;
   2578 
   2579   case EFI_PXE_BASE_CODE_FUNCTION_DHCP:
   2580   case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER:
   2581     break;
   2582 
   2583   default:
   2584     return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
   2585   }
   2586 
   2587   if (PacketLength != 0 && PacketPtr != NULL) {
   2588     //
   2589     // Print '.' when transmit a packet
   2590     //
   2591     AsciiPrint (".");
   2592 
   2593   }
   2594 
   2595   return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
   2596 }
   2597 
   2598 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL mPxeBcCallBackTemplate = {
   2599   EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL_REVISION,
   2600   EfiPxeLoadFileCallback
   2601 };
   2602 
   2603 
   2604 /**
   2605   Find the boot file.
   2606 
   2607   @param  Private      Pointer to PxeBc private data.
   2608   @param  BufferSize   Pointer to buffer size.
   2609   @param  Buffer       Pointer to buffer.
   2610 
   2611   @retval EFI_SUCCESS          Discover the boot file successfully.
   2612   @retval EFI_TIMEOUT          The TFTP/MTFTP operation timed out.
   2613   @retval EFI_ABORTED          PXE bootstrap server, so local boot need abort.
   2614   @retval EFI_BUFFER_TOO_SMALL The buffer is too small to load the boot file.
   2615 
   2616 **/
   2617 EFI_STATUS
   2618 DiscoverBootFile (
   2619   IN     PXEBC_PRIVATE_DATA  *Private,
   2620   IN OUT UINT64              *BufferSize,
   2621   IN     VOID                *Buffer
   2622   )
   2623 {
   2624   EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;
   2625   EFI_PXE_BASE_CODE_MODE      *Mode;
   2626   EFI_STATUS                  Status;
   2627   UINT16                      Type;
   2628   UINT16                      Layer;
   2629   BOOLEAN                     UseBis;
   2630   PXEBC_CACHED_DHCP4_PACKET   *Packet;
   2631   UINT16                      Value;
   2632 
   2633   PxeBc = &Private->PxeBc;
   2634   Mode  = PxeBc->Mode;
   2635   Type  = EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP;
   2636   Layer = EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL;
   2637 
   2638   //
   2639   // do DHCP.
   2640   //
   2641   Status = PxeBc->Dhcp (PxeBc, TRUE);
   2642   if (EFI_ERROR (Status)) {
   2643     return Status;
   2644   }
   2645 
   2646   //
   2647   // Select a boot server
   2648   //
   2649   Status = PxeBcSelectBootPrompt (Private);
   2650 
   2651   if (Status == EFI_SUCCESS) {
   2652     Status = PxeBcSelectBootMenu (Private, &Type, TRUE);
   2653   } else if (Status == EFI_TIMEOUT) {
   2654     Status = PxeBcSelectBootMenu (Private, &Type, FALSE);
   2655   }
   2656 
   2657   if (!EFI_ERROR (Status)) {
   2658 
   2659     if (Type == EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP) {
   2660       //
   2661       // Local boot(PXE bootstrap server) need abort
   2662       //
   2663       return EFI_ABORTED;
   2664     }
   2665 
   2666     UseBis  = (BOOLEAN) (Mode->BisSupported && Mode->BisDetected);
   2667     Status  = PxeBc->Discover (PxeBc, Type, &Layer, UseBis, NULL);
   2668     if (EFI_ERROR (Status)) {
   2669       return Status;
   2670     }
   2671   }
   2672 
   2673   *BufferSize = 0;
   2674 
   2675   //
   2676   // Get bootfile name and (m)tftp server ip addresss
   2677   //
   2678   if (Mode->PxeReplyReceived) {
   2679     Packet = &Private->PxeReply;
   2680   } else if (Mode->ProxyOfferReceived) {
   2681     Packet = &Private->ProxyOffer;
   2682   } else {
   2683     Packet = &Private->Dhcp4Ack;
   2684   }
   2685 
   2686   //
   2687   // Use siaddr(next server) in DHCPOFFER packet header, if zero, use option 54(server identifier)
   2688   // in DHCPOFFER packet.
   2689   // (It does not comply with PXE Spec, Ver2.1)
   2690   //
   2691   if (EFI_IP4_EQUAL (&Packet->Packet.Offer.Dhcp4.Header.ServerAddr, &mZeroIp4Addr)) {
   2692     CopyMem (
   2693       &Private->ServerIp,
   2694       Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
   2695       sizeof (EFI_IPv4_ADDRESS)
   2696       );
   2697   } else {
   2698     CopyMem (
   2699       &Private->ServerIp,
   2700       &Packet->Packet.Offer.Dhcp4.Header.ServerAddr,
   2701       sizeof (EFI_IPv4_ADDRESS)
   2702       );
   2703   }
   2704   if (Private->ServerIp.Addr[0] == 0) {
   2705     return EFI_DEVICE_ERROR;
   2706   }
   2707 
   2708   ASSERT (Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);
   2709 
   2710   //
   2711   // bootlfile name
   2712   //
   2713   Private->BootFileName = (CHAR8 *) (Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data);
   2714 
   2715   if (Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN] != NULL) {
   2716     //
   2717     // Already have the bootfile length option, compute the file size
   2718     //
   2719     CopyMem (&Value, Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN]->Data, sizeof (Value));
   2720     Value       = NTOHS (Value);
   2721     *BufferSize = 512 * Value;
   2722     Status      = EFI_BUFFER_TOO_SMALL;
   2723   } else {
   2724     //
   2725     // Get the bootfile size from tftp
   2726     //
   2727     Status = PxeBc->Mtftp (
   2728                       PxeBc,
   2729                       EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
   2730                       Buffer,
   2731                       FALSE,
   2732                       BufferSize,
   2733                       &Private->BlockSize,
   2734                       &Private->ServerIp,
   2735                       (UINT8 *) Private->BootFileName,
   2736                       NULL,
   2737                       FALSE
   2738                       );
   2739   }
   2740 
   2741   Private->FileSize = (UINTN) *BufferSize;
   2742 
   2743   return Status;
   2744 }
   2745 
   2746 /**
   2747   Causes the driver to load a specified file.
   2748 
   2749   @param  This                  Protocol instance pointer.
   2750   @param  FilePath              The device specific path of the file to load.
   2751   @param  BootPolicy            If TRUE, indicates that the request originates from the
   2752                                 boot manager is attempting to load FilePath as a boot
   2753                                 selection. If FALSE, then FilePath must match as exact file
   2754                                 to be loaded.
   2755   @param  BufferSize            On input the size of Buffer in bytes. On output with a return
   2756                                 code of EFI_SUCCESS, the amount of data transferred to
   2757                                 Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
   2758                                 the size of Buffer required to retrieve the requested file.
   2759   @param  Buffer                The memory buffer to transfer the file to. IF Buffer is NULL,
   2760                                 then no the size of the requested file is returned in
   2761                                 BufferSize.
   2762 
   2763   @retval EFI_SUCCESS                 The file was loaded.
   2764   @retval EFI_UNSUPPORTED             The device does not support the provided BootPolicy
   2765   @retval EFI_INVALID_PARAMETER       FilePath is not a valid device path, or
   2766                                       BufferSize is NULL.
   2767   @retval EFI_NO_MEDIA                No medium was present to load the file.
   2768   @retval EFI_DEVICE_ERROR            The file was not loaded due to a device error.
   2769   @retval EFI_NO_RESPONSE             The remote system did not respond.
   2770   @retval EFI_NOT_FOUND               The file was not found.
   2771   @retval EFI_ABORTED                 The file load process was manually cancelled.
   2772 
   2773 **/
   2774 EFI_STATUS
   2775 EFIAPI
   2776 EfiPxeLoadFile (
   2777   IN EFI_LOAD_FILE_PROTOCOL           * This,
   2778   IN EFI_DEVICE_PATH_PROTOCOL         * FilePath,
   2779   IN BOOLEAN                          BootPolicy,
   2780   IN OUT UINTN                        *BufferSize,
   2781   IN VOID                             *Buffer OPTIONAL
   2782   )
   2783 {
   2784   PXEBC_PRIVATE_DATA          *Private;
   2785   EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;
   2786   BOOLEAN                     NewMakeCallback;
   2787   EFI_STATUS                  Status;
   2788   UINT64                      TmpBufSize;
   2789   BOOLEAN                     MediaPresent;
   2790 
   2791   if (FilePath == NULL || !IsDevicePathEnd (FilePath)) {
   2792     return EFI_INVALID_PARAMETER;
   2793   }
   2794 
   2795   Private         = PXEBC_PRIVATE_DATA_FROM_LOADFILE (This);
   2796   PxeBc           = &Private->PxeBc;
   2797   NewMakeCallback = FALSE;
   2798   Status          = EFI_DEVICE_ERROR;
   2799 
   2800   if (This == NULL || BufferSize == NULL) {
   2801 
   2802     return EFI_INVALID_PARAMETER;
   2803   }
   2804 
   2805   //
   2806   // Only support BootPolicy
   2807   //
   2808   if (!BootPolicy) {
   2809     return EFI_UNSUPPORTED;
   2810   }
   2811 
   2812   //
   2813   // Check media status before PXE start
   2814   //
   2815   MediaPresent = TRUE;
   2816   NetLibDetectMedia (Private->Controller, &MediaPresent);
   2817   if (!MediaPresent) {
   2818     return EFI_NO_MEDIA;
   2819   }
   2820 
   2821   Status = PxeBc->Start (PxeBc, FALSE);
   2822   if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
   2823     return Status;
   2824   }
   2825 
   2826   Status = gBS->HandleProtocol (
   2827                   Private->Controller,
   2828                   &gEfiPxeBaseCodeCallbackProtocolGuid,
   2829                   (VOID **) &Private->PxeBcCallback
   2830                   );
   2831   if (Status == EFI_UNSUPPORTED) {
   2832 
   2833     CopyMem (&Private->LoadFileCallback, &mPxeBcCallBackTemplate, sizeof (Private->LoadFileCallback));
   2834 
   2835     Status = gBS->InstallProtocolInterface (
   2836                     &Private->Controller,
   2837                     &gEfiPxeBaseCodeCallbackProtocolGuid,
   2838                     EFI_NATIVE_INTERFACE,
   2839                     &Private->LoadFileCallback
   2840                     );
   2841 
   2842     NewMakeCallback = (BOOLEAN) (Status == EFI_SUCCESS);
   2843 
   2844     Status          = PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback);
   2845     if (EFI_ERROR (Status)) {
   2846       PxeBc->Stop (PxeBc);
   2847       return Status;
   2848     }
   2849   }
   2850 
   2851   if (Private->FileSize == 0) {
   2852     TmpBufSize  = 0;
   2853     Status      = DiscoverBootFile (Private, &TmpBufSize, Buffer);
   2854 
   2855     if (sizeof (UINTN) < sizeof (UINT64) && (TmpBufSize > 0xFFFFFFFF)) {
   2856       Status = EFI_DEVICE_ERROR;
   2857     } else if (TmpBufSize > 0 && *BufferSize >= (UINTN) TmpBufSize && Buffer != NULL) {
   2858       *BufferSize = (UINTN) TmpBufSize;
   2859       Status = PxeBc->Mtftp (
   2860                         PxeBc,
   2861                         EFI_PXE_BASE_CODE_TFTP_READ_FILE,
   2862                         Buffer,
   2863                         FALSE,
   2864                         &TmpBufSize,
   2865                         &Private->BlockSize,
   2866                         &Private->ServerIp,
   2867                         (UINT8 *) Private->BootFileName,
   2868                         NULL,
   2869                         FALSE
   2870                         );
   2871     } else if (TmpBufSize > 0) {
   2872       *BufferSize = (UINTN) TmpBufSize;
   2873       Status      = EFI_BUFFER_TOO_SMALL;
   2874     }
   2875   } else if (Buffer == NULL || Private->FileSize > *BufferSize) {
   2876     *BufferSize = Private->FileSize;
   2877     Status      = EFI_BUFFER_TOO_SMALL;
   2878   } else {
   2879     //
   2880     // Download the file.
   2881     //
   2882     TmpBufSize = (UINT64) (*BufferSize);
   2883     Status = PxeBc->Mtftp (
   2884                       PxeBc,
   2885                       EFI_PXE_BASE_CODE_TFTP_READ_FILE,
   2886                       Buffer,
   2887                       FALSE,
   2888                       &TmpBufSize,
   2889                       &Private->BlockSize,
   2890                       &Private->ServerIp,
   2891                       (UINT8 *) Private->BootFileName,
   2892                       NULL,
   2893                       FALSE
   2894                       );
   2895   }
   2896   //
   2897   // If we added a callback protocol, now is the time to remove it.
   2898   //
   2899   if (NewMakeCallback) {
   2900 
   2901     NewMakeCallback = FALSE;
   2902 
   2903     PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback);
   2904 
   2905     gBS->UninstallProtocolInterface (
   2906           Private->Controller,
   2907           &gEfiPxeBaseCodeCallbackProtocolGuid,
   2908           &Private->LoadFileCallback
   2909           );
   2910   }
   2911 
   2912   //
   2913   // Check download status
   2914   //
   2915   if (Status == EFI_SUCCESS) {
   2916     //
   2917     // The DHCP4 can have only one configured child instance so we need to stop
   2918     // reset the DHCP4 child before we return. Otherwise the other programs which
   2919     // also need to use DHCP4 will be impacted.
   2920     // The functionality of PXE Base Code protocol will not be stopped,
   2921     // when downloading is successfully.
   2922     //
   2923     Private->Dhcp4->Stop (Private->Dhcp4);
   2924     Private->Dhcp4->Configure (Private->Dhcp4, NULL);
   2925     return EFI_SUCCESS;
   2926 
   2927   } else if (Status == EFI_BUFFER_TOO_SMALL) {
   2928     if (Buffer != NULL) {
   2929       AsciiPrint ("PXE-E05: Download buffer is smaller than requested file.\n");
   2930     } else {
   2931       //
   2932       // The functionality of PXE Base Code protocol will not be stopped.
   2933       //
   2934       return Status;
   2935     }
   2936 
   2937   } else if (Status == EFI_DEVICE_ERROR) {
   2938     AsciiPrint ("PXE-E07: Network device error.\n");
   2939 
   2940   } else if (Status == EFI_OUT_OF_RESOURCES) {
   2941     AsciiPrint ("PXE-E09: Could not allocate I/O buffers.\n");
   2942 
   2943   } else if (Status == EFI_NO_MEDIA) {
   2944     AsciiPrint ("PXE-E12: Could not detect network connection.\n");
   2945 
   2946   } else if (Status == EFI_NO_RESPONSE) {
   2947     AsciiPrint ("PXE-E16: No offer received.\n");
   2948 
   2949   } else if (Status == EFI_TIMEOUT) {
   2950     AsciiPrint ("PXE-E18: Server response timeout.\n");
   2951 
   2952   } else if (Status == EFI_ABORTED) {
   2953     AsciiPrint ("PXE-E21: Remote boot cancelled.\n");
   2954 
   2955   } else if (Status == EFI_ICMP_ERROR) {
   2956     AsciiPrint ("PXE-E22: Client received ICMP error from server.\n");
   2957 
   2958   } else if (Status == EFI_TFTP_ERROR) {
   2959     AsciiPrint ("PXE-E23: Client received TFTP error from server.\n");
   2960 
   2961   } else {
   2962     AsciiPrint ("PXE-E99: Unexpected network error.\n");
   2963   }
   2964 
   2965   PxeBc->Stop (PxeBc);
   2966 
   2967   return Status;
   2968 }
   2969 
   2970 EFI_LOAD_FILE_PROTOCOL  mLoadFileProtocolTemplate = { EfiPxeLoadFile };
   2971 
   2972