Home | History | Annotate | Download | only in UefiPxeBcDxe
      1 /** @file
      2   This implementation of EFI_PXE_BASE_CODE_PROTOCOL and EFI_LOAD_FILE_PROTOCOL.
      3 
      4   Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php.
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "PxeBcImpl.h"
     17 
     18 
     19 /**
     20   Enables the use of the PXE Base Code Protocol functions.
     21 
     22   This function enables the use of the PXE Base Code Protocol functions. If the
     23   Started field of the EFI_PXE_BASE_CODE_MODE structure is already TRUE, then
     24   EFI_ALREADY_STARTED will be returned. If UseIpv6 is TRUE, then IPv6 formatted
     25   addresses will be used in this session. If UseIpv6 is FALSE, then IPv4 formatted
     26   addresses will be used in this session. If UseIpv6 is TRUE, and the Ipv6Supported
     27   field of the EFI_PXE_BASE_CODE_MODE structure is FALSE, then EFI_UNSUPPORTED will
     28   be returned. If there is not enough memory or other resources to start the PXE
     29   Base Code Protocol, then EFI_OUT_OF_RESOURCES will be returned. Otherwise, the
     30   PXE Base Code Protocol will be started.
     31 
     32   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
     33   @param[in]  UseIpv6           Specifies the type of IP addresses that are to be
     34                                 used during the session that is being started.
     35                                 Set to TRUE for IPv6, and FALSE for IPv4.
     36 
     37   @retval EFI_SUCCESS           The PXE Base Code Protocol was started.
     38   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
     39   @retval EFI_UNSUPPORTED       UseIpv6 is TRUE, but the Ipv6Supported field of the
     40                                 EFI_PXE_BASE_CODE_MODE structure is FALSE.
     41   @retval EFI_ALREADY_STARTED   The PXE Base Code Protocol is already in the started state.
     42   @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not point to a valid
     43                                 EFI_PXE_BASE_CODE_PROTOCOL structure.
     44   @retval EFI_OUT_OF_RESOURCES  Could not allocate enough memory or other resources to start the
     45                                 PXE Base Code Protocol.
     46 
     47 **/
     48 EFI_STATUS
     49 EFIAPI
     50 EfiPxeBcStart (
     51   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
     52   IN BOOLEAN                          UseIpv6
     53   )
     54 {
     55   PXEBC_PRIVATE_DATA      *Private;
     56   EFI_PXE_BASE_CODE_MODE  *Mode;
     57   UINTN                   Index;
     58   EFI_STATUS              Status;
     59 
     60   if (This == NULL) {
     61     return EFI_INVALID_PARAMETER;
     62   }
     63 
     64   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
     65   Mode    = Private->PxeBc.Mode;
     66 
     67   if (Mode->Started) {
     68     return EFI_ALREADY_STARTED;
     69   }
     70 
     71   //
     72   // Detect whether using IPv6 or not, and set it into mode data.
     73   //
     74   if (UseIpv6 && Mode->Ipv6Available && Mode->Ipv6Supported && Private->Ip6Nic != NULL) {
     75     Mode->UsingIpv6 = TRUE;
     76   } else if (!UseIpv6 && Private->Ip4Nic != NULL) {
     77     Mode->UsingIpv6 = FALSE;
     78   } else {
     79     return EFI_UNSUPPORTED;
     80   }
     81 
     82   if (Mode->UsingIpv6) {
     83     AsciiPrint ("\n>>Start PXE over IPv6");
     84     //
     85     // Configure udp6 instance to receive data.
     86     //
     87     Status = Private->Udp6Read->Configure (
     88                                   Private->Udp6Read,
     89                                   &Private->Udp6CfgData
     90                                   );
     91     if (EFI_ERROR (Status)) {
     92       goto ON_ERROR;
     93     }
     94 
     95     //
     96     // Configure block size for TFTP as a default value to handle all link layers.
     97     //
     98     Private->BlockSize = (UINTN) (Private->Ip6MaxPacketSize -
     99                            PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE);
    100 
    101     //
    102     // PXE over IPv6 starts here, initialize the fields and list header.
    103     //
    104     Private->Ip6Policy                          = PXEBC_IP6_POLICY_MAX;
    105     Private->ProxyOffer.Dhcp6.Packet.Offer.Size = PXEBC_CACHED_DHCP6_PACKET_MAX_SIZE;
    106     Private->DhcpAck.Dhcp6.Packet.Ack.Size      = PXEBC_CACHED_DHCP6_PACKET_MAX_SIZE;
    107     Private->PxeReply.Dhcp6.Packet.Ack.Size     = PXEBC_CACHED_DHCP6_PACKET_MAX_SIZE;
    108 
    109     for (Index = 0; Index < PXEBC_OFFER_MAX_NUM; Index++) {
    110       Private->OfferBuffer[Index].Dhcp6.Packet.Offer.Size = PXEBC_CACHED_DHCP6_PACKET_MAX_SIZE;
    111     }
    112 
    113     //
    114     // Create event and set status for token to capture ICMP6 error message.
    115     //
    116     Private->Icmp6Token.Status = EFI_NOT_READY;
    117     Status = gBS->CreateEvent (
    118                     EVT_NOTIFY_SIGNAL,
    119                     TPL_NOTIFY,
    120                     PxeBcIcmp6ErrorUpdate,
    121                     Private,
    122                     &Private->Icmp6Token.Event
    123                     );
    124     if (EFI_ERROR (Status)) {
    125       goto ON_ERROR;
    126     }
    127 
    128     //
    129     // Set Ip6 policy to Automatic to start the IP6 router discovery.
    130     //
    131     Status = PxeBcSetIp6Policy (Private);
    132     if (EFI_ERROR (Status)) {
    133       goto ON_ERROR;
    134     }
    135   } else {
    136     AsciiPrint ("\n>>Start PXE over IPv4");
    137     //
    138     // Configure udp4 instance to receive data.
    139     //
    140     Status = Private->Udp4Read->Configure (
    141                                   Private->Udp4Read,
    142                                   &Private->Udp4CfgData
    143                                   );
    144     if (EFI_ERROR (Status)) {
    145       goto ON_ERROR;
    146     }
    147 
    148     //
    149     // Configure block size for TFTP as a default value to handle all link layers.
    150     //
    151     Private->BlockSize = (UINTN) (Private->Ip4MaxPacketSize -
    152                            PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE);
    153 
    154     //
    155     // PXE over IPv4 starts here, initialize the fields.
    156     //
    157     Private->ProxyOffer.Dhcp4.Packet.Offer.Size = PXEBC_CACHED_DHCP4_PACKET_MAX_SIZE;
    158     Private->DhcpAck.Dhcp4.Packet.Ack.Size      = PXEBC_CACHED_DHCP4_PACKET_MAX_SIZE;
    159     Private->PxeReply.Dhcp4.Packet.Ack.Size     = PXEBC_CACHED_DHCP4_PACKET_MAX_SIZE;
    160 
    161     for (Index = 0; Index < PXEBC_OFFER_MAX_NUM; Index++) {
    162       Private->OfferBuffer[Index].Dhcp4.Packet.Offer.Size = PXEBC_CACHED_DHCP4_PACKET_MAX_SIZE;
    163     }
    164 
    165     PxeBcSeedDhcp4Packet (&Private->SeedPacket, Private->Udp4Read);
    166 
    167     //
    168     // Create the event for Arp cache update.
    169     //
    170     Status = gBS->CreateEvent (
    171                     EVT_TIMER | EVT_NOTIFY_SIGNAL,
    172                     TPL_CALLBACK,
    173                     PxeBcArpCacheUpdate,
    174                     Private,
    175                     &Private->ArpUpdateEvent
    176                     );
    177     if (EFI_ERROR (Status)) {
    178       goto ON_ERROR;
    179     }
    180 
    181     //
    182     // Start a periodic timer by second to update Arp cache.
    183     //
    184     Status = gBS->SetTimer (
    185                     Private->ArpUpdateEvent,
    186                     TimerPeriodic,
    187                     TICKS_PER_SECOND
    188                     );
    189     if (EFI_ERROR (Status)) {
    190       goto ON_ERROR;
    191     }
    192 
    193     //
    194     // Create event and set status for token to capture ICMP error message.
    195     //
    196     Private->Icmp6Token.Status = EFI_NOT_READY;
    197     Status = gBS->CreateEvent (
    198                     EVT_NOTIFY_SIGNAL,
    199                     TPL_NOTIFY,
    200                     PxeBcIcmpErrorUpdate,
    201                     Private,
    202                     &Private->IcmpToken.Event
    203                     );
    204     if (EFI_ERROR (Status)) {
    205       goto ON_ERROR;
    206     }
    207 
    208     //
    209     //DHCP4 service allows only one of its children to be configured in
    210     //the active state, If the DHCP4 D.O.R.A started by IP4 auto
    211     //configuration and has not been completed, the Dhcp4 state machine
    212     //will not be in the right state for the PXE to start a new round D.O.R.A.
    213     //so we need to switch it's policy to static.
    214     //
    215     Status = PxeBcSetIp4Policy (Private);
    216     if (EFI_ERROR (Status)) {
    217       goto ON_ERROR;
    218     }
    219   }
    220 
    221   //
    222   // If PcdTftpBlockSize is set to non-zero, override the default value.
    223   //
    224   if (PcdGet64 (PcdTftpBlockSize) != 0) {
    225     Private->BlockSize   = (UINTN) PcdGet64 (PcdTftpBlockSize);
    226   }
    227 
    228   //
    229   // Create event for UdpRead/UdpWrite timeout since they are both blocking API.
    230   //
    231   Status = gBS->CreateEvent (
    232                   EVT_TIMER,
    233                   TPL_CALLBACK,
    234                   NULL,
    235                   NULL,
    236                   &Private->UdpTimeOutEvent
    237                   );
    238   if (EFI_ERROR (Status)) {
    239     goto ON_ERROR;
    240   }
    241 
    242   Private->IsAddressOk = FALSE;
    243   Mode->Started        = TRUE;
    244 
    245   return EFI_SUCCESS;
    246 
    247 ON_ERROR:
    248   if (Mode->UsingIpv6) {
    249     if (Private->Icmp6Token.Event != NULL) {
    250       gBS->CloseEvent (Private->Icmp6Token.Event);
    251       Private->Icmp6Token.Event = NULL;
    252     }
    253     Private->Udp6Read->Configure (Private->Udp6Read, NULL);
    254     Private->Ip6->Configure (Private->Ip6, NULL);
    255   } else {
    256     if (Private->ArpUpdateEvent != NULL) {
    257       gBS->CloseEvent (Private->ArpUpdateEvent);
    258       Private->ArpUpdateEvent = NULL;
    259     }
    260     if (Private->IcmpToken.Event != NULL) {
    261       gBS->CloseEvent (Private->IcmpToken.Event);
    262       Private->IcmpToken.Event = NULL;
    263     }
    264     Private->Udp4Read->Configure (Private->Udp4Read, NULL);
    265     Private->Ip4->Configure (Private->Ip4, NULL);
    266   }
    267   return Status;
    268 }
    269 
    270 
    271 /**
    272   Disable the use of the PXE Base Code Protocol functions.
    273 
    274   This function stops all activity on the network device. All the resources allocated
    275   in Start() are released, the Started field of the EFI_PXE_BASE_CODE_MODE structure is
    276   set to FALSE, and EFI_SUCCESS is returned. If the Started field of the EFI_PXE_BASE_CODE_MODE
    277   structure is already FALSE, then EFI_NOT_STARTED will be returned.
    278 
    279   @param[in]  This               Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
    280 
    281   @retval EFI_SUCCESS           The PXE Base Code Protocol was stopped.
    282   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is already in the stopped state.
    283   @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not point to a valid
    284                                 EFI_PXE_BASE_CODE_PROTOCOL structure.
    285   @retval Others
    286 
    287 **/
    288 EFI_STATUS
    289 EFIAPI
    290 EfiPxeBcStop (
    291   IN EFI_PXE_BASE_CODE_PROTOCOL       *This
    292   )
    293 {
    294   PXEBC_PRIVATE_DATA      *Private;
    295   EFI_PXE_BASE_CODE_MODE  *Mode;
    296   BOOLEAN                 Ipv6Supported;
    297   BOOLEAN                 Ipv6Available;
    298 
    299   if (This == NULL) {
    300     return EFI_INVALID_PARAMETER;
    301   }
    302 
    303   Private       = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
    304   Mode          = Private->PxeBc.Mode;
    305   Ipv6Supported = Mode->Ipv6Supported;
    306   Ipv6Available = Mode->Ipv6Available;
    307 
    308   if (!Mode->Started) {
    309     return EFI_NOT_STARTED;
    310   }
    311 
    312   if (Mode->UsingIpv6) {
    313     //
    314     // Configure all the instances for IPv6 as NULL.
    315     //
    316     ZeroMem (&Private->Udp6CfgData.StationAddress, sizeof (EFI_IPv6_ADDRESS));
    317     ZeroMem (&Private->Ip6CfgData.StationAddress, sizeof (EFI_IPv6_ADDRESS));
    318     Private->Dhcp6->Stop (Private->Dhcp6);
    319     Private->Dhcp6->Configure (Private->Dhcp6, NULL);
    320     Private->Udp6Write->Configure (Private->Udp6Write, NULL);
    321     Private->Udp6Read->Groups (Private->Udp6Read, FALSE, NULL);
    322     Private->Udp6Read->Configure (Private->Udp6Read, NULL);
    323     Private->Ip6->Cancel (Private->Ip6, &Private->Icmp6Token);
    324     Private->Ip6->Configure (Private->Ip6, NULL);
    325     PxeBcUnregisterIp6Address (Private);
    326     if (Private->Icmp6Token.Event != NULL) {
    327       gBS->CloseEvent (Private->Icmp6Token.Event);
    328       Private->Icmp6Token.Event = NULL;
    329     }
    330     if (Private->Dhcp6Request != NULL) {
    331       FreePool (Private->Dhcp6Request);
    332       Private->Dhcp6Request = NULL;
    333     }
    334     if (Private->BootFileName != NULL) {
    335       FreePool (Private->BootFileName);
    336       Private->BootFileName = NULL;
    337     }
    338   } else {
    339     //
    340     // Configure all the instances for IPv4 as NULL.
    341     //
    342     ZeroMem (&Private->Udp4CfgData.StationAddress, sizeof (EFI_IPv4_ADDRESS));
    343     ZeroMem (&Private->Udp4CfgData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
    344     ZeroMem (&Private->Ip4CfgData.StationAddress, sizeof (EFI_IPv4_ADDRESS));
    345     ZeroMem (&Private->Ip4CfgData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
    346     Private->Dhcp4->Stop (Private->Dhcp4);
    347     Private->Dhcp4->Configure (Private->Dhcp4, NULL);
    348     Private->Udp4Write->Configure (Private->Udp4Write, NULL);
    349     Private->Udp4Read->Groups (Private->Udp4Read, FALSE, NULL);
    350     Private->Udp4Read->Configure (Private->Udp4Read, NULL);
    351     Private->Ip4->Cancel (Private->Ip4, &Private->IcmpToken);
    352     Private->Ip4->Configure (Private->Ip4, NULL);
    353     if (Private->ArpUpdateEvent != NULL) {
    354       gBS->CloseEvent (Private->ArpUpdateEvent);
    355       Private->ArpUpdateEvent = NULL;
    356     }
    357     if (Private->IcmpToken.Event != NULL) {
    358       gBS->CloseEvent (Private->IcmpToken.Event);
    359       Private->IcmpToken.Event = NULL;
    360     }
    361     Private->BootFileName = NULL;
    362   }
    363 
    364   gBS->CloseEvent (Private->UdpTimeOutEvent);
    365   Private->CurSrcPort   = 0;
    366   Private->BootFileSize = 0;
    367   Private->SolicitTimes = 0;
    368   Private->ElapsedTime  = 0;
    369   ZeroMem (&Private->StationIp, sizeof (EFI_IP_ADDRESS));
    370   ZeroMem (&Private->SubnetMask, sizeof (EFI_IP_ADDRESS));
    371   ZeroMem (&Private->GatewayIp, sizeof (EFI_IP_ADDRESS));
    372   ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS));
    373 
    374   //
    375   // Reset the mode data.
    376   //
    377   ZeroMem (Mode, sizeof (EFI_PXE_BASE_CODE_MODE));
    378   Mode->Ipv6Available = Ipv6Available;
    379   Mode->Ipv6Supported = Ipv6Supported;
    380   Mode->AutoArp       = TRUE;
    381   Mode->TTL           = DEFAULT_TTL;
    382   Mode->ToS           = DEFAULT_ToS;
    383 
    384   return EFI_SUCCESS;
    385 }
    386 
    387 
    388 /**
    389   Attempts to complete a DHCPv4 D.O.R.A. (discover / offer / request / acknowledge) or DHCPv6
    390   S.A.R.R (solicit / advertise / request / reply) sequence.
    391 
    392   If SortOffers is TRUE, then the cached DHCP offer packets will be sorted before
    393   they are tried. If SortOffers is FALSE, then the cached DHCP offer packets will
    394   be tried in the order in which they are received. Please see the Preboot Execution
    395   Environment (PXE) Specification and Unified Extensible Firmware Interface (UEFI)
    396   Specification for additional details on the implementation of DHCP.
    397   If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
    398   then the DHCP sequence will be stopped and EFI_ABORTED will be returned.
    399 
    400   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
    401   @param[in]  SortOffers        TRUE if the offers received should be sorted. Set to FALSE to
    402                                 try the offers in the order that they are received.
    403 
    404   @retval EFI_SUCCESS           Valid DHCP has completed.
    405   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
    406   @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not point to a valid
    407                                 EFI_PXE_BASE_CODE_PROTOCOL structure.
    408   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
    409   @retval EFI_OUT_OF_RESOURCES  Could not allocate enough memory to complete the DHCP Protocol.
    410   @retval EFI_ABORTED           The callback function aborted the DHCP Protocol.
    411   @retval EFI_TIMEOUT           The DHCP Protocol timed out.
    412   @retval EFI_ICMP_ERROR        An ICMP error packet was received during the DHCP session.
    413   @retval EFI_NO_RESPONSE       Valid PXE offer was not received.
    414 
    415 **/
    416 EFI_STATUS
    417 EFIAPI
    418 EfiPxeBcDhcp (
    419   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
    420   IN BOOLEAN                          SortOffers
    421   )
    422 {
    423   PXEBC_PRIVATE_DATA           *Private;
    424   EFI_PXE_BASE_CODE_MODE       *Mode;
    425   EFI_STATUS                   Status;
    426   EFI_PXE_BASE_CODE_IP_FILTER  IpFilter;
    427 
    428   if (This == NULL) {
    429     return EFI_INVALID_PARAMETER;
    430   }
    431 
    432   Status                  = EFI_SUCCESS;
    433   Private                 = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
    434   Mode                    = Private->PxeBc.Mode;
    435   Mode->IcmpErrorReceived = FALSE;
    436   Private->Function       = EFI_PXE_BASE_CODE_FUNCTION_DHCP;
    437   Private->IsOfferSorted  = SortOffers;
    438   Private->SolicitTimes   = 0;
    439   Private->ElapsedTime    = 0;
    440 
    441   if (!Mode->Started) {
    442     return EFI_NOT_STARTED;
    443   }
    444 
    445   if (Mode->UsingIpv6) {
    446 
    447     //
    448     // Stop Udp6Read instance
    449     //
    450     Private->Udp6Read->Configure (Private->Udp6Read, NULL);
    451 
    452     //
    453     // Start S.A.R.R. process to get a IPv6 address and other boot information.
    454     //
    455     Status = PxeBcDhcp6Sarr (Private, Private->Dhcp6);
    456   } else {
    457 
    458     //
    459     // Stop Udp4Read instance
    460     //
    461     Private->Udp4Read->Configure (Private->Udp4Read, NULL);
    462 
    463     //
    464     // Start D.O.R.A. process to get a IPv4 address and other boot information.
    465     //
    466     Status = PxeBcDhcp4Dora (Private, Private->Dhcp4);
    467   }
    468 
    469   //
    470   // Reconfigure the UDP instance with the default configuration.
    471   //
    472   if (Mode->UsingIpv6) {
    473     Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);
    474   } else {
    475     Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);
    476   }
    477   //
    478   // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP
    479   // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
    480   //
    481   ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));
    482   IpFilter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
    483   This->SetIpFilter (This, &IpFilter);
    484 
    485   return Status;
    486 }
    487 
    488 
    489 /**
    490   Attempts to complete the PXE Boot Server and/or boot image discovery sequence.
    491 
    492   This function attempts to complete the PXE Boot Server and/or boot image discovery
    493   sequence. If this sequence is completed, then EFI_SUCCESS is returned, and the
    494   PxeDiscoverValid, PxeDiscover, PxeReplyReceived, and PxeReply fields of the
    495   EFI_PXE_BASE_CODE_MODE structure are filled in. If UseBis is TRUE, then the
    496   PxeBisReplyReceived and PxeBisReply fields of the EFI_PXE_BASE_CODE_MODE structure
    497   will also be filled in. If UseBis is FALSE, then PxeBisReplyValid will be set to FALSE.
    498   In the structure referenced by parameter Info, the PXE Boot Server list, SrvList[],
    499   has two uses: It is the Boot Server IP address list used for unicast discovery
    500   (if the UseUCast field is TRUE), and it is the list used for Boot Server verification
    501   (if the MustUseList field is TRUE). Also, if the MustUseList field in that structure
    502   is TRUE and the AcceptAnyResponse field in the SrvList[] array is TRUE, any Boot
    503   Server reply of that type will be accepted. If the AcceptAnyResponse field is
    504   FALSE, only responses from Boot Servers with matching IP addresses will be accepted.
    505   This function can take at least 10 seconds to timeout and return control to the
    506   caller. If the Discovery sequence does not complete, then EFI_TIMEOUT will be
    507   returned. Please see the Preboot Execution Environment (PXE) Specification for
    508   additional details on the implementation of the Discovery sequence.
    509   If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
    510   then the Discovery sequence is stopped and EFI_ABORTED will be returned.
    511 
    512   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
    513   @param[in]  Type              The type of bootstrap to perform.
    514   @param[in]  Layer             Pointer to the boot server layer number to discover, which must be
    515                                 PXE_BOOT_LAYER_INITIAL when a new server type is being
    516                                 discovered.
    517   @param[in]  UseBis            TRUE if Boot Integrity Services are to be used. FALSE otherwise.
    518   @param[in]  Info              Pointer to a data structure that contains additional information
    519                                 on the type of discovery operation that is to be performed.
    520                                 It is optional.
    521 
    522   @retval EFI_SUCCESS           The Discovery sequence has been completed.
    523   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
    524   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    525   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
    526   @retval EFI_OUT_OF_RESOURCES  Could not allocate enough memory to complete Discovery.
    527   @retval EFI_ABORTED           The callback function aborted the Discovery sequence.
    528   @retval EFI_TIMEOUT           The Discovery sequence timed out.
    529   @retval EFI_ICMP_ERROR        An ICMP error packet was received during the PXE discovery
    530                                 session.
    531 
    532 **/
    533 EFI_STATUS
    534 EFIAPI
    535 EfiPxeBcDiscover (
    536   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
    537   IN UINT16                           Type,
    538   IN UINT16                           *Layer,
    539   IN BOOLEAN                          UseBis,
    540   IN EFI_PXE_BASE_CODE_DISCOVER_INFO  *Info   OPTIONAL
    541   )
    542 {
    543   PXEBC_PRIVATE_DATA              *Private;
    544   EFI_PXE_BASE_CODE_MODE          *Mode;
    545   EFI_PXE_BASE_CODE_DISCOVER_INFO DefaultInfo;
    546   EFI_PXE_BASE_CODE_SRVLIST       *SrvList;
    547   PXEBC_BOOT_SVR_ENTRY            *BootSvrEntry;
    548   UINT16                          Index;
    549   EFI_STATUS                      Status;
    550   EFI_PXE_BASE_CODE_IP_FILTER     IpFilter;
    551   EFI_PXE_BASE_CODE_DISCOVER_INFO *NewCreatedInfo;
    552 
    553   if (This == NULL) {
    554     return EFI_INVALID_PARAMETER;
    555   }
    556 
    557   Private                 = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
    558   Mode                    = Private->PxeBc.Mode;
    559   Mode->IcmpErrorReceived = FALSE;
    560   BootSvrEntry            = NULL;
    561   SrvList                 = NULL;
    562   Status                  = EFI_DEVICE_ERROR;
    563   Private->Function       = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;
    564   NewCreatedInfo          = NULL;
    565 
    566   if (!Mode->Started) {
    567     return EFI_NOT_STARTED;
    568   }
    569 
    570   //
    571   // Station address should be ready before do discover.
    572   //
    573   if (!Private->IsAddressOk) {
    574     return EFI_INVALID_PARAMETER;
    575   }
    576 
    577   if (Mode->UsingIpv6) {
    578 
    579     //
    580     // Stop Udp6Read instance
    581     //
    582     Private->Udp6Read->Configure (Private->Udp6Read, NULL);
    583   } else {
    584 
    585     //
    586     // Stop Udp4Read instance
    587     //
    588     Private->Udp4Read->Configure (Private->Udp4Read, NULL);
    589   }
    590 
    591   //
    592   // There are 3 methods to get the information for discover.
    593   //
    594   ZeroMem (&DefaultInfo, sizeof (EFI_PXE_BASE_CODE_DISCOVER_INFO));
    595   if (*Layer != EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL) {
    596     //
    597     // 1. Take the previous setting as the discover info.
    598     //
    599     if (!Mode->PxeDiscoverValid ||
    600         !Mode->PxeReplyReceived ||
    601         (!Mode->PxeBisReplyReceived && UseBis)) {
    602       Status = EFI_INVALID_PARAMETER;
    603       goto ON_EXIT;
    604     }
    605 
    606     Info                         = &DefaultInfo;
    607     Info->IpCnt                  = 1;
    608     Info->UseUCast               = TRUE;
    609     SrvList                      = Info->SrvList;
    610     SrvList[0].Type              = Type;
    611     SrvList[0].AcceptAnyResponse = FALSE;
    612 
    613     CopyMem (&SrvList->IpAddr, &Private->ServerIp, sizeof (EFI_IP_ADDRESS));
    614 
    615   } else if (Info == NULL) {
    616     //
    617     // 2. Extract the discover information from the cached packets if unspecified.
    618     //
    619     NewCreatedInfo = &DefaultInfo;
    620     Status = PxeBcExtractDiscoverInfo (Private, Type, &NewCreatedInfo, &BootSvrEntry, &SrvList);
    621     if (EFI_ERROR (Status)) {
    622       goto ON_EXIT;
    623     }
    624     ASSERT (NewCreatedInfo != NULL);
    625     Info = NewCreatedInfo;
    626   } else {
    627     //
    628     // 3. Take the pass-in information as the discover info, and validate the server list.
    629     //
    630     SrvList = Info->SrvList;
    631 
    632     if (!SrvList[0].AcceptAnyResponse) {
    633       for (Index = 1; Index < Info->IpCnt; Index++) {
    634         if (SrvList[Index].AcceptAnyResponse) {
    635           break;
    636         }
    637       }
    638       if (Index != Info->IpCnt) {
    639         //
    640         // It's invalid if the first server doesn't accecpt any response
    641         // but any of the other servers does accept any response.
    642         //
    643         Status = EFI_INVALID_PARAMETER;
    644         goto ON_EXIT;
    645       }
    646     }
    647   }
    648 
    649   //
    650   // Info and BootSvrEntry/SrvList are all ready by now, so execute discover by UniCast/BroadCast/MultiCast.
    651   //
    652   if ((!Info->UseUCast && !Info->UseBCast && !Info->UseMCast) ||
    653       (Info->MustUseList && Info->IpCnt == 0)) {
    654     Status = EFI_INVALID_PARAMETER;
    655     goto ON_EXIT;
    656   }
    657 
    658   Private->IsDoDiscover = TRUE;
    659 
    660   if (Info->UseMCast) {
    661     //
    662     // Do discover by multicast.
    663     //
    664     Status = PxeBcDiscoverBootServer (
    665                Private,
    666                Type,
    667                Layer,
    668                UseBis,
    669                &Info->ServerMCastIp,
    670                Info->IpCnt,
    671                SrvList
    672                );
    673 
    674   } else if (Info->UseBCast) {
    675     //
    676     // Do discover by broadcast, but only valid for IPv4.
    677     //
    678     ASSERT (!Mode->UsingIpv6);
    679     Status = PxeBcDiscoverBootServer (
    680                Private,
    681                Type,
    682                Layer,
    683                UseBis,
    684                NULL,
    685                Info->IpCnt,
    686                SrvList
    687                );
    688 
    689   } else if (Info->UseUCast) {
    690     //
    691     // Do discover by unicast.
    692     //
    693     for (Index = 0; Index < Info->IpCnt; Index++) {
    694       if (BootSvrEntry == NULL) {
    695         CopyMem (&Private->ServerIp, &SrvList[Index].IpAddr, sizeof (EFI_IP_ADDRESS));
    696       } else {
    697         ASSERT (!Mode->UsingIpv6);
    698         ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS));
    699         CopyMem (&Private->ServerIp, &BootSvrEntry->IpAddr[Index], sizeof (EFI_IPv4_ADDRESS));
    700       }
    701 
    702       Status = PxeBcDiscoverBootServer (
    703                  Private,
    704                  Type,
    705                  Layer,
    706                  UseBis,
    707                  &Private->ServerIp,
    708                  Info->IpCnt,
    709                  SrvList
    710                  );
    711       }
    712   }
    713 
    714   if (!EFI_ERROR (Status)) {
    715     //
    716     // Parse the cached PXE reply packet, and store it into mode data if valid.
    717     //
    718     if (Mode->UsingIpv6) {
    719       Status = PxeBcParseDhcp6Packet (&Private->PxeReply.Dhcp6);
    720       if (!EFI_ERROR (Status)) {
    721         CopyMem (
    722           &Mode->PxeReply.Dhcpv6,
    723           &Private->PxeReply.Dhcp6.Packet.Ack.Dhcp6,
    724           Private->PxeReply.Dhcp6.Packet.Ack.Length
    725           );
    726         Mode->PxeReplyReceived = TRUE;
    727         Mode->PxeDiscoverValid = TRUE;
    728       }
    729     } else {
    730       Status = PxeBcParseDhcp4Packet (&Private->PxeReply.Dhcp4);
    731       if (!EFI_ERROR (Status)) {
    732         CopyMem (
    733           &Mode->PxeReply.Dhcpv4,
    734           &Private->PxeReply.Dhcp4.Packet.Ack.Dhcp4,
    735           Private->PxeReply.Dhcp4.Packet.Ack.Length
    736           );
    737         Mode->PxeReplyReceived = TRUE;
    738         Mode->PxeDiscoverValid = TRUE;
    739       }
    740     }
    741   }
    742 
    743 ON_EXIT:
    744 
    745   if (NewCreatedInfo != NULL && NewCreatedInfo != &DefaultInfo) {
    746     FreePool (NewCreatedInfo);
    747   }
    748 
    749   if (Mode->UsingIpv6) {
    750     Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);
    751   } else {
    752     Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);
    753   }
    754 
    755   //
    756   // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP
    757   // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
    758   //
    759   ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));
    760   IpFilter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
    761   This->SetIpFilter (This, &IpFilter);
    762 
    763   return Status;
    764 }
    765 
    766 
    767 /**
    768   Used to perform TFTP and MTFTP services.
    769 
    770   This function is used to perform TFTP and MTFTP services. This includes the
    771   TFTP operations to get the size of a file, read a directory, read a file, and
    772   write a file. It also includes the MTFTP operations to get the size of a file,
    773   read a directory, and read a file. The type of operation is specified by Operation.
    774   If the callback function that is invoked during the TFTP/MTFTP operation does
    775   not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, then EFI_ABORTED will
    776   be returned.
    777   For read operations, the return data will be placed in the buffer specified by
    778   BufferPtr. If BufferSize is too small to contain the entire downloaded file,
    779   then EFI_BUFFER_TOO_SMALL will be returned and BufferSize will be set to zero,
    780   or the size of the requested file. (NOTE: the size of the requested file is only returned
    781   if the TFTP server supports TFTP options). If BufferSize is large enough for the
    782   read operation, then BufferSize will be set to the size of the downloaded file,
    783   and EFI_SUCCESS will be returned. Applications using the PxeBc.Mtftp() services
    784   should use the get-file-size operations to determine the size of the downloaded
    785   file prior to using the read-file operations-especially when downloading large
    786   (greater than 64 MB) files-instead of making two calls to the read-file operation.
    787   Following this recommendation will save time if the file is larger than expected
    788   and the TFTP server does not support TFTP option extensions. Without TFTP option
    789   extension support, the client must download the entire file, counting and discarding
    790   the received packets, to determine the file size.
    791   For write operations, the data to be sent is in the buffer specified by BufferPtr.
    792   BufferSize specifies the number of bytes to send. If the write operation completes
    793   successfully, then EFI_SUCCESS will be returned.
    794   For TFTP "get file size" operations, the size of the requested file or directory
    795   is returned in BufferSize, and EFI_SUCCESS will be returned. If the TFTP server
    796   does not support options, the file will be downloaded into a bit bucket and the
    797   length of the downloaded file will be returned. For MTFTP "get file size" operations,
    798   if the MTFTP server does not support the "get file size" option, EFI_UNSUPPORTED
    799   will be returned.
    800   This function can take up to 10 seconds to timeout and return control to the caller.
    801   If the TFTP sequence does not complete, EFI_TIMEOUT will be returned.
    802   If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
    803   then the TFTP sequence is stopped and EFI_ABORTED will be returned.
    804 
    805   @param[in]      This          Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
    806   @param[in]      Operation     The type of operation to perform.
    807   @param[in, out] BufferPtr     A pointer to the data buffer.
    808   @param[in]      Overwrite     Only used on write file operations. TRUE if a file on a remote
    809                                 server can be overwritten.
    810   @param[in, out] BufferSize    For get-file-size operations, *BufferSize returns the size of the
    811                                 requested file.
    812   @param[in]      BlockSize     The requested block size to be used during a TFTP transfer.
    813   @param[in]      ServerIp      The TFTP / MTFTP server IP address.
    814   @param[in]      Filename      A Null-terminated ASCII string that specifies a directory name
    815                                 or a file name.
    816   @param[in]      Info          Pointer to the MTFTP information.
    817   @param[in]      DontUseBuffer Set to FALSE for normal TFTP and MTFTP read file operation.
    818 
    819   @retval EFI_SUCCESS           The TFTP/MTFTP operation was completed.
    820   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
    821   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
    822   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
    823   @retval EFI_BUFFER_TOO_SMALL  The buffer is not large enough to complete the read operation.
    824   @retval EFI_ABORTED           The callback function aborted the TFTP/MTFTP operation.
    825   @retval EFI_TIMEOUT           The TFTP/MTFTP operation timed out.
    826   @retval EFI_ICMP_ERROR        An ICMP error packet was received during the MTFTP session.
    827   @retval EFI_TFTP_ERROR        A TFTP error packet was received during the MTFTP session.
    828 
    829 **/
    830 EFI_STATUS
    831 EFIAPI
    832 EfiPxeBcMtftp (
    833   IN     EFI_PXE_BASE_CODE_PROTOCOL       *This,
    834   IN     EFI_PXE_BASE_CODE_TFTP_OPCODE    Operation,
    835   IN OUT VOID                             *BufferPtr    OPTIONAL,
    836   IN     BOOLEAN                          Overwrite,
    837   IN OUT UINT64                           *BufferSize,
    838   IN     UINTN                            *BlockSize    OPTIONAL,
    839   IN     EFI_IP_ADDRESS                   *ServerIp,
    840   IN     UINT8                            *Filename,
    841   IN     EFI_PXE_BASE_CODE_MTFTP_INFO     *Info         OPTIONAL,
    842   IN     BOOLEAN                          DontUseBuffer
    843   )
    844 {
    845   PXEBC_PRIVATE_DATA              *Private;
    846   EFI_PXE_BASE_CODE_MODE          *Mode;
    847   EFI_MTFTP4_CONFIG_DATA          Mtftp4Config;
    848   EFI_MTFTP6_CONFIG_DATA          Mtftp6Config;
    849   VOID                            *Config;
    850   EFI_STATUS                      Status;
    851   EFI_PXE_BASE_CODE_IP_FILTER     IpFilter;
    852 
    853 
    854   if ((This == NULL) ||
    855       (Filename == NULL) ||
    856       (BufferSize == NULL) ||
    857       (ServerIp == NULL) ||
    858       ((BufferPtr == NULL) && DontUseBuffer) ||
    859       ((BlockSize != NULL) && (*BlockSize < PXE_MTFTP_DEFAULT_BLOCK_SIZE))) {
    860     return EFI_INVALID_PARAMETER;
    861   }
    862 
    863   Config    = NULL;
    864   Status    = EFI_DEVICE_ERROR;
    865   Private   = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
    866   Mode      = Private->PxeBc.Mode;
    867 
    868   if (Mode->UsingIpv6) {
    869     if (!NetIp6IsValidUnicast (&ServerIp->v6)) {
    870       return EFI_INVALID_PARAMETER;
    871     }
    872   } else {
    873     if (IP4_IS_UNSPECIFIED (NTOHL (ServerIp->Addr[0])) || IP4_IS_LOCAL_BROADCAST (NTOHL (ServerIp->Addr[0])))   {
    874       return EFI_INVALID_PARAMETER;
    875     }
    876   }
    877 
    878   if (Mode->UsingIpv6) {
    879     //
    880     // Set configuration data for Mtftp6 instance.
    881     //
    882     ZeroMem (&Mtftp6Config, sizeof (EFI_MTFTP6_CONFIG_DATA));
    883     Config                         = &Mtftp6Config;
    884     Mtftp6Config.TimeoutValue      = PXEBC_MTFTP_TIMEOUT;
    885     Mtftp6Config.TryCount          = PXEBC_MTFTP_RETRIES;
    886     CopyMem (&Mtftp6Config.StationIp, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));
    887     CopyMem (&Mtftp6Config.ServerIp, &ServerIp->v6, sizeof (EFI_IPv6_ADDRESS));
    888     //
    889     // Stop Udp6Read instance
    890     //
    891     Private->Udp6Read->Configure (Private->Udp6Read, NULL);
    892   } else {
    893     //
    894     // Set configuration data for Mtftp4 instance.
    895     //
    896     ZeroMem (&Mtftp4Config, sizeof (EFI_MTFTP4_CONFIG_DATA));
    897     Config                         = &Mtftp4Config;
    898     Mtftp4Config.UseDefaultSetting = FALSE;
    899     Mtftp4Config.TimeoutValue      = PXEBC_MTFTP_TIMEOUT;
    900     Mtftp4Config.TryCount          = PXEBC_MTFTP_RETRIES;
    901     CopyMem (&Mtftp4Config.StationIp, &Private->StationIp.v4, sizeof (EFI_IPv4_ADDRESS));
    902     CopyMem (&Mtftp4Config.SubnetMask, &Private->SubnetMask.v4, sizeof (EFI_IPv4_ADDRESS));
    903     CopyMem (&Mtftp4Config.GatewayIp, &Private->GatewayIp.v4, sizeof (EFI_IPv4_ADDRESS));
    904     CopyMem (&Mtftp4Config.ServerIp, &ServerIp->v4, sizeof (EFI_IPv4_ADDRESS));
    905     //
    906     // Stop Udp4Read instance
    907     //
    908     Private->Udp4Read->Configure (Private->Udp4Read, NULL);
    909   }
    910 
    911   Mode->TftpErrorReceived = FALSE;
    912   Mode->IcmpErrorReceived = FALSE;
    913 
    914   switch (Operation) {
    915 
    916   case EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE:
    917     //
    918     // Send TFTP request to get file size.
    919     //
    920     Status = PxeBcTftpGetFileSize (
    921                Private,
    922                Config,
    923                Filename,
    924                BlockSize,
    925                BufferSize
    926                );
    927 
    928     break;
    929 
    930   case EFI_PXE_BASE_CODE_TFTP_READ_FILE:
    931     //
    932     // Send TFTP request to read file.
    933     //
    934     Status = PxeBcTftpReadFile (
    935                Private,
    936                Config,
    937                Filename,
    938                BlockSize,
    939                BufferPtr,
    940                BufferSize,
    941                DontUseBuffer
    942                );
    943 
    944     break;
    945 
    946   case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE:
    947     //
    948     // Send TFTP request to write file.
    949     //
    950     Status = PxeBcTftpWriteFile (
    951                Private,
    952                Config,
    953                Filename,
    954                Overwrite,
    955                BlockSize,
    956                BufferPtr,
    957                BufferSize
    958                );
    959 
    960     break;
    961 
    962   case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY:
    963     //
    964     // Send TFTP request to read directory.
    965     //
    966     Status = PxeBcTftpReadDirectory (
    967                Private,
    968                Config,
    969                Filename,
    970                BlockSize,
    971                BufferPtr,
    972                BufferSize,
    973                DontUseBuffer
    974                );
    975 
    976     break;
    977 
    978   case EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE:
    979   case EFI_PXE_BASE_CODE_MTFTP_READ_FILE:
    980   case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY:
    981     Status = EFI_UNSUPPORTED;
    982 
    983     break;
    984 
    985   default:
    986     Status = EFI_INVALID_PARAMETER;
    987 
    988     break;
    989   }
    990 
    991   if (Status == EFI_ICMP_ERROR) {
    992     Mode->IcmpErrorReceived = TRUE;
    993   }
    994 
    995   //
    996   // Reconfigure the UDP instance with the default configuration.
    997   //
    998   if (Mode->UsingIpv6) {
    999     Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);
   1000   } else {
   1001     Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData);
   1002   }
   1003   //
   1004   // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP
   1005   // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
   1006   //
   1007   ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER));
   1008   IpFilter.Filters = EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP;
   1009   This->SetIpFilter (This, &IpFilter);
   1010 
   1011   return Status;
   1012 }
   1013 
   1014 
   1015 /**
   1016   Writes a UDP packet to the network interface.
   1017 
   1018   This function writes a UDP packet specified by the (optional HeaderPtr and)
   1019   BufferPtr parameters to the network interface. The UDP header is automatically
   1020   built by this routine. It uses the parameters OpFlags, DestIp, DestPort, GatewayIp,
   1021   SrcIp, and SrcPort to build this header. If the packet is successfully built and
   1022   transmitted through the network interface, then EFI_SUCCESS will be returned.
   1023   If a timeout occurs during the transmission of the packet, then EFI_TIMEOUT will
   1024   be returned. If an ICMP error occurs during the transmission of the packet, then
   1025   the IcmpErrorReceived field is set to TRUE, the IcmpError field is filled in and
   1026   EFI_ICMP_ERROR will be returned. If the Callback Protocol does not return
   1027   EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, then EFI_ABORTED will be returned.
   1028 
   1029   @param[in]      This          Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
   1030   @param[in]      OpFlags       The UDP operation flags.
   1031   @param[in]      DestIp        The destination IP address.
   1032   @param[in]      DestPort      The destination UDP port number.
   1033   @param[in]      GatewayIp     The gateway IP address.
   1034   @param[in]      SrcIp         The source IP address.
   1035   @param[in, out] SrcPort       The source UDP port number.
   1036   @param[in]      HeaderSize    An optional field which may be set to the length of a header
   1037                                 at HeaderPtr to be prefixed to the data at BufferPtr.
   1038   @param[in]  HeaderPtr         If HeaderSize is not NULL, a pointer to a header to be
   1039                                 prefixed to the data at BufferPtr.
   1040   @param[in]  BufferSize        A pointer to the size of the data at BufferPtr.
   1041   @param[in]  BufferPtr         A pointer to the data to be written.
   1042 
   1043   @retval EFI_SUCCESS           The UDP Write operation completed.
   1044   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
   1045   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   1046   @retval EFI_BAD_BUFFER_SIZE   The buffer is too long to be transmitted.
   1047   @retval EFI_ABORTED           The callback function aborted the UDP Write operation.
   1048   @retval EFI_TIMEOUT           The UDP Write operation timed out.
   1049   @retval EFI_ICMP_ERROR        An ICMP error packet was received during the UDP write session.
   1050 
   1051 **/
   1052 EFI_STATUS
   1053 EFIAPI
   1054 EfiPxeBcUdpWrite (
   1055   IN     EFI_PXE_BASE_CODE_PROTOCOL       *This,
   1056   IN     UINT16                           OpFlags,
   1057   IN     EFI_IP_ADDRESS                   *DestIp,
   1058   IN     EFI_PXE_BASE_CODE_UDP_PORT       *DestPort,
   1059   IN     EFI_IP_ADDRESS                   *GatewayIp  OPTIONAL,
   1060   IN     EFI_IP_ADDRESS                   *SrcIp      OPTIONAL,
   1061   IN OUT EFI_PXE_BASE_CODE_UDP_PORT       *SrcPort    OPTIONAL,
   1062   IN     UINTN                            *HeaderSize OPTIONAL,
   1063   IN     VOID                             *HeaderPtr  OPTIONAL,
   1064   IN     UINTN                            *BufferSize,
   1065   IN     VOID                             *BufferPtr
   1066   )
   1067 {
   1068   PXEBC_PRIVATE_DATA        *Private;
   1069   EFI_PXE_BASE_CODE_MODE    *Mode;
   1070   EFI_UDP4_SESSION_DATA     Udp4Session;
   1071   EFI_UDP6_SESSION_DATA     Udp6Session;
   1072   EFI_STATUS                Status;
   1073   BOOLEAN                   DoNotFragment;
   1074 
   1075   if (This == NULL || DestIp == NULL || DestPort == NULL) {
   1076     return EFI_INVALID_PARAMETER;
   1077   }
   1078 
   1079   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
   1080   Mode    = Private->PxeBc.Mode;
   1081 
   1082   if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT) != 0) {
   1083     DoNotFragment = FALSE;
   1084   } else {
   1085     DoNotFragment = TRUE;
   1086   }
   1087 
   1088   if (!Mode->UsingIpv6 && GatewayIp != NULL && !NetIp4IsUnicast (NTOHL (GatewayIp->Addr[0]), EFI_NTOHL(Mode->SubnetMask))) {
   1089     //
   1090     // Gateway is provided but it's not a unicast IPv4 address, while it will be ignored for IPv6.
   1091     //
   1092     return EFI_INVALID_PARAMETER;
   1093   }
   1094 
   1095   if (HeaderSize != NULL && (*HeaderSize == 0 || HeaderPtr == NULL)) {
   1096     return EFI_INVALID_PARAMETER;
   1097   }
   1098 
   1099   if (BufferSize == NULL || (*BufferSize != 0 && BufferPtr == NULL)) {
   1100     return EFI_INVALID_PARAMETER;
   1101   }
   1102 
   1103   if (!Mode->Started) {
   1104     return EFI_NOT_STARTED;
   1105   }
   1106 
   1107   if (!Private->IsAddressOk && SrcIp == NULL) {
   1108     return EFI_INVALID_PARAMETER;
   1109   }
   1110 
   1111   if (Private->CurSrcPort == 0 ||
   1112       (SrcPort != NULL && *SrcPort != Private->CurSrcPort)) {
   1113     //
   1114     // Reconfigure UDPv4/UDPv6 for UdpWrite if the source port changed.
   1115     //
   1116     if (SrcPort != NULL) {
   1117       Private->CurSrcPort = *SrcPort;
   1118     }
   1119   }
   1120 
   1121   if (Mode->UsingIpv6) {
   1122     Status = PxeBcConfigUdp6Write (
   1123                Private->Udp6Write,
   1124                &Private->StationIp.v6,
   1125                &Private->CurSrcPort
   1126                );
   1127   } else {
   1128     //
   1129     // Configure the UDPv4 instance with gateway information from DHCP server as default.
   1130     //
   1131     Status = PxeBcConfigUdp4Write (
   1132                Private->Udp4Write,
   1133                &Private->StationIp.v4,
   1134                &Private->SubnetMask.v4,
   1135                &Private->GatewayIp.v4,
   1136                &Private->CurSrcPort,
   1137                DoNotFragment,
   1138                Private->Mode.TTL,
   1139                Private->Mode.ToS
   1140                );
   1141   }
   1142 
   1143   if (EFI_ERROR (Status)) {
   1144     Private->CurSrcPort = 0;
   1145     return EFI_INVALID_PARAMETER;
   1146   } else if (SrcPort != NULL) {
   1147     *SrcPort = Private->CurSrcPort;
   1148   }
   1149 
   1150   //
   1151   // Start a timer as timeout event for this blocking API.
   1152   //
   1153   gBS->SetTimer (Private->UdpTimeOutEvent, TimerRelative, PXEBC_UDP_TIMEOUT);
   1154 
   1155   if (Mode->UsingIpv6) {
   1156     //
   1157     // Construct UDPv6 session data.
   1158     //
   1159     ZeroMem (&Udp6Session, sizeof (EFI_UDP6_SESSION_DATA));
   1160     CopyMem (&Udp6Session.DestinationAddress, DestIp, sizeof (EFI_IPv6_ADDRESS));
   1161     Udp6Session.DestinationPort = *DestPort;
   1162     if (SrcIp != NULL) {
   1163       CopyMem (&Udp6Session.SourceAddress, SrcIp, sizeof (EFI_IPv6_ADDRESS));
   1164     }
   1165     if (SrcPort != NULL) {
   1166       Udp6Session.SourcePort = *SrcPort;
   1167     }
   1168 
   1169     Status = PxeBcUdp6Write (
   1170                Private->Udp6Write,
   1171                &Udp6Session,
   1172                Private->UdpTimeOutEvent,
   1173                HeaderSize,
   1174                HeaderPtr,
   1175                BufferSize,
   1176                BufferPtr
   1177                );
   1178   } else {
   1179     //
   1180     // Construct UDPv4 session data.
   1181     //
   1182     ZeroMem (&Udp4Session, sizeof (EFI_UDP4_SESSION_DATA));
   1183     CopyMem (&Udp4Session.DestinationAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));
   1184     Udp4Session.DestinationPort = *DestPort;
   1185     if (SrcIp != NULL) {
   1186       CopyMem (&Udp4Session.SourceAddress, SrcIp, sizeof (EFI_IPv4_ADDRESS));
   1187     }
   1188     if (SrcPort != NULL) {
   1189       Udp4Session.SourcePort = *SrcPort;
   1190     }
   1191     //
   1192     // Override the gateway information if user specified.
   1193     //
   1194     Status = PxeBcUdp4Write (
   1195                Private->Udp4Write,
   1196                &Udp4Session,
   1197                Private->UdpTimeOutEvent,
   1198                (EFI_IPv4_ADDRESS *) GatewayIp,
   1199                HeaderSize,
   1200                HeaderPtr,
   1201                BufferSize,
   1202                BufferPtr
   1203                );
   1204   }
   1205 
   1206   gBS->SetTimer (Private->UdpTimeOutEvent, TimerCancel, 0);
   1207 
   1208 
   1209   //
   1210   // Reset the UdpWrite instance.
   1211   //
   1212   if (Mode->UsingIpv6) {
   1213     Private->Udp6Write->Configure (Private->Udp6Write, NULL);
   1214   } else {
   1215     Private->Udp4Write->Configure (Private->Udp4Write, NULL);
   1216   }
   1217 
   1218   return Status;
   1219 }
   1220 
   1221 
   1222 /**
   1223   Reads a UDP packet from the network interface.
   1224 +
   1225   This function reads a UDP packet from a network interface. The data contents
   1226   are returned in (the optional HeaderPtr and) BufferPtr, and the size of the
   1227   buffer received is returned in BufferSize . If the input BufferSize is smaller
   1228   than the UDP packet received (less optional HeaderSize), it will be set to the
   1229   required size, and EFI_BUFFER_TOO_SMALL will be returned. In this case, the
   1230   contents of BufferPtr are undefined, and the packet is lost. If a UDP packet is
   1231   successfully received, then EFI_SUCCESS will be returned, and the information
   1232   from the UDP header will be returned in DestIp, DestPort, SrcIp, and SrcPort if
   1233   they are not NULL. Depending on the values of OpFlags and the DestIp, DestPort,
   1234   SrcIp, and SrcPort input values, different types of UDP packet receive filtering
   1235   will be performed. The following tables summarize these receive filter operations.
   1236 
   1237   @param[in]      This          Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
   1238   @param[in]      OpFlags       The UDP operation flags.
   1239   @param[in, out] DestIp        The destination IP address.
   1240   @param[in, out] DestPort      The destination UDP port number.
   1241   @param[in, out] SrcIp         The source IP address.
   1242   @param[in, out] SrcPort       The source UDP port number.
   1243   @param[in]      HeaderSize    An optional field which may be set to the length of a
   1244                                 header at HeaderPtr to be prefixed to the data at BufferPtr.
   1245   @param[in]      HeaderPtr     If HeaderSize is not NULL, a pointer to a header to be
   1246                                 prefixed to the data at BufferPtr.
   1247   @param[in, out] BufferSize    A pointer to the size of the data at BufferPtr.
   1248   @param[in]      BufferPtr     A pointer to the data to be read.
   1249 
   1250   @retval EFI_SUCCESS           The UDP Read operation was completed.
   1251   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
   1252   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   1253   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
   1254   @retval EFI_BUFFER_TOO_SMALL  The packet is larger than Buffer can hold.
   1255   @retval EFI_ABORTED           The callback function aborted the UDP Read operation.
   1256   @retval EFI_TIMEOUT           The UDP Read operation timed out.
   1257 
   1258 **/
   1259 EFI_STATUS
   1260 EFIAPI
   1261 EfiPxeBcUdpRead (
   1262   IN     EFI_PXE_BASE_CODE_PROTOCOL   *This,
   1263   IN     UINT16                       OpFlags,
   1264   IN OUT EFI_IP_ADDRESS               *DestIp      OPTIONAL,
   1265   IN OUT EFI_PXE_BASE_CODE_UDP_PORT   *DestPort    OPTIONAL,
   1266   IN OUT EFI_IP_ADDRESS               *SrcIp       OPTIONAL,
   1267   IN OUT EFI_PXE_BASE_CODE_UDP_PORT   *SrcPort     OPTIONAL,
   1268   IN     UINTN                        *HeaderSize  OPTIONAL,
   1269   IN     VOID                         *HeaderPtr   OPTIONAL,
   1270   IN OUT UINTN                        *BufferSize,
   1271   IN     VOID                         *BufferPtr
   1272   )
   1273 {
   1274   PXEBC_PRIVATE_DATA          *Private;
   1275   EFI_PXE_BASE_CODE_MODE      *Mode;
   1276   EFI_UDP4_COMPLETION_TOKEN   Udp4Token;
   1277   EFI_UDP6_COMPLETION_TOKEN   Udp6Token;
   1278   EFI_UDP4_RECEIVE_DATA       *Udp4Rx;
   1279   EFI_UDP6_RECEIVE_DATA       *Udp6Rx;
   1280   EFI_STATUS                  Status;
   1281   BOOLEAN                     IsDone;
   1282   BOOLEAN                     IsMatched;
   1283   UINTN                       CopiedLen;
   1284   UINTN                       HeaderLen;
   1285   UINTN                       HeaderCopiedLen;
   1286   UINTN                       BufferCopiedLen;
   1287   UINT32                      FragmentLength;
   1288   UINTN                       FragmentIndex;
   1289   UINT8                       *FragmentBuffer;
   1290 
   1291   if (This == NULL) {
   1292     return EFI_INVALID_PARAMETER;
   1293   }
   1294 
   1295   Private   = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
   1296   Mode      = Private->PxeBc.Mode;
   1297   IsDone    = FALSE;
   1298   IsMatched = FALSE;
   1299   Udp4Rx    = NULL;
   1300   Udp6Rx    = NULL;
   1301 
   1302   if (((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) == 0 && DestPort == NULL) ||
   1303       ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) == 0 && SrcIp == NULL) ||
   1304       ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) == 0 && SrcPort == NULL)) {
   1305     return EFI_INVALID_PARAMETER;
   1306   }
   1307 
   1308   if ((HeaderSize != NULL && *HeaderSize == 0) || (HeaderSize != NULL && HeaderPtr == NULL)) {
   1309     return EFI_INVALID_PARAMETER;
   1310   }
   1311 
   1312   if ((BufferSize == NULL) || (BufferPtr == NULL)) {
   1313     return EFI_INVALID_PARAMETER;
   1314   }
   1315 
   1316   if (!Mode->Started) {
   1317     return EFI_NOT_STARTED;
   1318   }
   1319 
   1320   ZeroMem (&Udp6Token, sizeof (EFI_UDP6_COMPLETION_TOKEN));
   1321   ZeroMem (&Udp4Token, sizeof (EFI_UDP4_COMPLETION_TOKEN));
   1322 
   1323   if (Mode->UsingIpv6) {
   1324     Status = gBS->CreateEvent (
   1325                     EVT_NOTIFY_SIGNAL,
   1326                     TPL_NOTIFY,
   1327                     PxeBcCommonNotify,
   1328                     &IsDone,
   1329                     &Udp6Token.Event
   1330                     );
   1331     if (EFI_ERROR (Status)) {
   1332       return EFI_OUT_OF_RESOURCES;
   1333     }
   1334   } else {
   1335     Status = gBS->CreateEvent (
   1336                     EVT_NOTIFY_SIGNAL,
   1337                     TPL_NOTIFY,
   1338                     PxeBcCommonNotify,
   1339                     &IsDone,
   1340                     &Udp4Token.Event
   1341                     );
   1342     if (EFI_ERROR (Status)) {
   1343       return EFI_OUT_OF_RESOURCES;
   1344     }
   1345   }
   1346 
   1347   //
   1348   // Start a timer as timeout event for this blocking API.
   1349   //
   1350   gBS->SetTimer (Private->UdpTimeOutEvent, TimerRelative, PXEBC_UDP_TIMEOUT);
   1351   Mode->IcmpErrorReceived = FALSE;
   1352 
   1353   //
   1354   // Read packet by Udp4Read/Udp6Read until matched or timeout.
   1355   //
   1356   while (!IsMatched && !EFI_ERROR (Status)) {
   1357     if (Mode->UsingIpv6) {
   1358       Status = PxeBcUdp6Read (
   1359                  Private->Udp6Read,
   1360                  &Udp6Token,
   1361                  Mode,
   1362                  Private->UdpTimeOutEvent,
   1363                  OpFlags,
   1364                  &IsDone,
   1365                  &IsMatched,
   1366                  DestIp,
   1367                  DestPort,
   1368                  SrcIp,
   1369                  SrcPort
   1370                  );
   1371     } else {
   1372       Status = PxeBcUdp4Read (
   1373                  Private->Udp4Read,
   1374                  &Udp4Token,
   1375                  Mode,
   1376                  Private->UdpTimeOutEvent,
   1377                  OpFlags,
   1378                  &IsDone,
   1379                  &IsMatched,
   1380                  DestIp,
   1381                  DestPort,
   1382                  SrcIp,
   1383                  SrcPort
   1384                  );
   1385     }
   1386   }
   1387 
   1388   if (Status == EFI_ICMP_ERROR ||
   1389       Status == EFI_NETWORK_UNREACHABLE ||
   1390       Status == EFI_HOST_UNREACHABLE ||
   1391       Status == EFI_PROTOCOL_UNREACHABLE ||
   1392       Status == EFI_PORT_UNREACHABLE) {
   1393     //
   1394     // Get different return status for icmp error from Udp, refers to UEFI spec.
   1395     //
   1396     Mode->IcmpErrorReceived = TRUE;
   1397   }
   1398   gBS->SetTimer (Private->UdpTimeOutEvent, TimerCancel, 0);
   1399 
   1400   if (IsMatched) {
   1401     //
   1402     // Copy the rececived packet to user if matched by filter.
   1403     //
   1404     if (Mode->UsingIpv6) {
   1405       Udp6Rx = Udp6Token.Packet.RxData;
   1406       ASSERT (Udp6Rx != NULL);
   1407 
   1408       HeaderLen = 0;
   1409       if (HeaderSize != NULL) {
   1410         HeaderLen = MIN (*HeaderSize, Udp6Rx->DataLength);
   1411       }
   1412 
   1413       if (Udp6Rx->DataLength - HeaderLen > *BufferSize) {
   1414         Status = EFI_BUFFER_TOO_SMALL;
   1415       } else {
   1416         if (HeaderSize != NULL) {
   1417           *HeaderSize = HeaderLen;
   1418         }
   1419         *BufferSize = Udp6Rx->DataLength - HeaderLen;
   1420 
   1421         HeaderCopiedLen = 0;
   1422         BufferCopiedLen = 0;
   1423         for (FragmentIndex = 0; FragmentIndex < Udp6Rx->FragmentCount; FragmentIndex++) {
   1424           FragmentLength = Udp6Rx->FragmentTable[FragmentIndex].FragmentLength;
   1425           FragmentBuffer = Udp6Rx->FragmentTable[FragmentIndex].FragmentBuffer;
   1426           if (HeaderCopiedLen + FragmentLength < HeaderLen) {
   1427             //
   1428             // Copy the header part of received data.
   1429             //
   1430             CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, FragmentLength);
   1431             HeaderCopiedLen += FragmentLength;
   1432           } else if (HeaderCopiedLen < HeaderLen) {
   1433             //
   1434             // Copy the header part of received data.
   1435             //
   1436             CopiedLen = HeaderLen - HeaderCopiedLen;
   1437             CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, CopiedLen);
   1438             HeaderCopiedLen += CopiedLen;
   1439 
   1440             //
   1441             // Copy the other part of received data.
   1442             //
   1443             CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer + CopiedLen, FragmentLength - CopiedLen);
   1444             BufferCopiedLen += (FragmentLength - CopiedLen);
   1445           } else {
   1446             //
   1447             // Copy the other part of received data.
   1448             //
   1449             CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer, FragmentLength);
   1450             BufferCopiedLen += FragmentLength;
   1451           }
   1452         }
   1453       }
   1454       //
   1455       // Recycle the receiving buffer after copy to user.
   1456       //
   1457       gBS->SignalEvent (Udp6Rx->RecycleSignal);
   1458     } else {
   1459       Udp4Rx = Udp4Token.Packet.RxData;
   1460       ASSERT (Udp4Rx != NULL);
   1461 
   1462       HeaderLen = 0;
   1463       if (HeaderSize != NULL) {
   1464         HeaderLen = MIN (*HeaderSize, Udp4Rx->DataLength);
   1465       }
   1466 
   1467       if (Udp4Rx->DataLength - HeaderLen > *BufferSize) {
   1468         Status = EFI_BUFFER_TOO_SMALL;
   1469       } else {
   1470         if (HeaderSize != NULL) {
   1471           *HeaderSize = HeaderLen;
   1472         }
   1473         *BufferSize = Udp4Rx->DataLength - HeaderLen;
   1474 
   1475         HeaderCopiedLen = 0;
   1476         BufferCopiedLen = 0;
   1477         for (FragmentIndex = 0; FragmentIndex < Udp4Rx->FragmentCount; FragmentIndex++) {
   1478           FragmentLength = Udp4Rx->FragmentTable[FragmentIndex].FragmentLength;
   1479           FragmentBuffer = Udp4Rx->FragmentTable[FragmentIndex].FragmentBuffer;
   1480           if (HeaderCopiedLen + FragmentLength < HeaderLen) {
   1481             //
   1482             // Copy the header part of received data.
   1483             //
   1484             CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, FragmentLength);
   1485             HeaderCopiedLen += FragmentLength;
   1486           } else if (HeaderCopiedLen < HeaderLen) {
   1487             //
   1488             // Copy the header part of received data.
   1489             //
   1490             CopiedLen = HeaderLen - HeaderCopiedLen;
   1491             CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, CopiedLen);
   1492             HeaderCopiedLen += CopiedLen;
   1493 
   1494             //
   1495             // Copy the other part of received data.
   1496             //
   1497             CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer + CopiedLen, FragmentLength - CopiedLen);
   1498             BufferCopiedLen += (FragmentLength - CopiedLen);
   1499           } else {
   1500             //
   1501             // Copy the other part of received data.
   1502             //
   1503             CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer, FragmentLength);
   1504             BufferCopiedLen += FragmentLength;
   1505           }
   1506         }
   1507       }
   1508       //
   1509       // Recycle the receiving buffer after copy to user.
   1510       //
   1511       gBS->SignalEvent (Udp4Rx->RecycleSignal);
   1512     }
   1513   }
   1514 
   1515   if (Mode->UsingIpv6) {
   1516     Private->Udp6Read->Cancel (Private->Udp6Read, &Udp6Token);
   1517     gBS->CloseEvent (Udp6Token.Event);
   1518   } else {
   1519     Private->Udp4Read->Cancel (Private->Udp4Read, &Udp4Token);
   1520     gBS->CloseEvent (Udp4Token.Event);
   1521   }
   1522 
   1523   return Status;
   1524 }
   1525 
   1526 
   1527 /**
   1528   Updates the IP receive filters of a network device and enables software filtering.
   1529 
   1530   The NewFilter field is used to modify the network device's current IP receive
   1531   filter settings and to enable a software filter. This function updates the IpFilter
   1532   field of the EFI_PXE_BASE_CODE_MODE structure with the contents of NewIpFilter.
   1533   The software filter is used when the USE_FILTER in OpFlags is set to UdpRead().
   1534   The current hardware filter remains in effect no matter what the settings of OpFlags.
   1535   This is so that the meaning of ANY_DEST_IP set in OpFlags to UdpRead() is from those
   1536   packets whose reception is enabled in hardware-physical NIC address (unicast),
   1537   broadcast address, logical address or addresses (multicast), or all (promiscuous).
   1538   UdpRead() does not modify the IP filter settings.
   1539   Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP receive
   1540   filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP.
   1541   If an application or driver wishes to preserve the IP receive filter settings,
   1542   it will have to preserve the IP receive filter settings before these calls, and
   1543   use SetIpFilter() to restore them after the calls. If incompatible filtering is
   1544   requested (for example, PROMISCUOUS with anything else), or if the device does not
   1545   support a requested filter setting and it cannot be accommodated in software
   1546   (for example, PROMISCUOUS not supported), EFI_INVALID_PARAMETER will be returned.
   1547   The IPlist field is used to enable IPs other than the StationIP. They may be
   1548   multicast or unicast. If IPcnt is set as well as EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP,
   1549   then both the StationIP and the IPs from the IPlist will be used.
   1550 
   1551   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
   1552   @param[in]  NewFilter         Pointer to the new set of IP receive filters.
   1553 
   1554   @retval EFI_SUCCESS           The IP receive filter settings were updated.
   1555   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
   1556   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   1557 
   1558 **/
   1559 EFI_STATUS
   1560 EFIAPI
   1561 EfiPxeBcSetIpFilter (
   1562   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
   1563   IN EFI_PXE_BASE_CODE_IP_FILTER      *NewFilter
   1564   )
   1565 {
   1566   EFI_STATUS                Status;
   1567   PXEBC_PRIVATE_DATA        *Private;
   1568   EFI_PXE_BASE_CODE_MODE    *Mode;
   1569   EFI_UDP4_CONFIG_DATA      *Udp4Cfg;
   1570   EFI_UDP6_CONFIG_DATA      *Udp6Cfg;
   1571   UINTN                     Index;
   1572   BOOLEAN                   NeedPromiscuous;
   1573   BOOLEAN                   AcceptPromiscuous;
   1574   BOOLEAN                   AcceptBroadcast;
   1575   BOOLEAN                   MultiCastUpdate;
   1576 
   1577   if (This == NULL || NewFilter == NULL) {
   1578     return EFI_INVALID_PARAMETER;
   1579   }
   1580 
   1581   Private         = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
   1582   Mode            = Private->PxeBc.Mode;
   1583   Status          = EFI_SUCCESS;
   1584   NeedPromiscuous = FALSE;
   1585 
   1586   if (!Mode->Started) {
   1587     return EFI_NOT_STARTED;
   1588   }
   1589 
   1590   for (Index = 0; Index < NewFilter->IpCnt; Index++) {
   1591     ASSERT (Index < EFI_PXE_BASE_CODE_MAX_IPCNT);
   1592     if (!Mode->UsingIpv6 &&
   1593         IP4_IS_LOCAL_BROADCAST (EFI_IP4 (NewFilter->IpList[Index].v4))) {
   1594       //
   1595       // IPv4 broadcast address should not be in IP filter.
   1596       //
   1597       return EFI_INVALID_PARAMETER;
   1598     }
   1599     if (Mode->UsingIpv6) {
   1600       if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0 &&
   1601           NetIp6IsValidUnicast (&NewFilter->IpList[Index].v6)) {
   1602         NeedPromiscuous = TRUE;
   1603       }
   1604     } else if ((EFI_NTOHL(Mode->StationIp) != 0) &&
   1605                (EFI_NTOHL(Mode->SubnetMask) != 0) &&
   1606                IP4_NET_EQUAL(EFI_NTOHL(Mode->StationIp), EFI_NTOHL(NewFilter->IpList[Index].v4), EFI_NTOHL(Mode->SubnetMask.v4)) &&
   1607                NetIp4IsUnicast (EFI_IP4 (NewFilter->IpList[Index].v4), EFI_NTOHL(Mode->SubnetMask)) &&
   1608                ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0)) {
   1609       NeedPromiscuous = TRUE;
   1610     }
   1611   }
   1612 
   1613   AcceptPromiscuous = FALSE;
   1614   AcceptBroadcast   = FALSE;
   1615   MultiCastUpdate   = FALSE;
   1616 
   1617   if (NeedPromiscuous ||
   1618       (NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != 0 ||
   1619       (NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) != 0) {
   1620     //
   1621     // Configure UDPv4/UDPv6 as promiscuous mode to receive all packets.
   1622     //
   1623     AcceptPromiscuous = TRUE;
   1624   } else if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0) {
   1625     //
   1626     // Configure UDPv4 to receive all broadcast packets.
   1627     //
   1628     AcceptBroadcast  = TRUE;
   1629   }
   1630 
   1631   //
   1632   // In multicast condition when Promiscuous FALSE and IpCnt no-zero.
   1633   // Here check if there is any update of the multicast ip address. If yes,
   1634   // we need leave the old multicast group (by Config UDP instance to NULL),
   1635   // and join the new multicast group.
   1636   //
   1637   if (!AcceptPromiscuous) {
   1638     if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0) {
   1639       if (Mode->IpFilter.IpCnt != NewFilter->IpCnt) {
   1640         MultiCastUpdate = TRUE;
   1641       } else if (CompareMem (Mode->IpFilter.IpList, NewFilter->IpList, NewFilter->IpCnt * sizeof (EFI_IP_ADDRESS)) != 0 ) {
   1642         MultiCastUpdate = TRUE;
   1643       }
   1644     }
   1645   }
   1646 
   1647   if (!Mode->UsingIpv6) {
   1648     //
   1649     // Check whether we need reconfigure the UDP4 instance.
   1650     //
   1651     Udp4Cfg = &Private->Udp4CfgData;
   1652     if ((AcceptPromiscuous != Udp4Cfg->AcceptPromiscuous)   ||
   1653     	  (AcceptBroadcast != Udp4Cfg->AcceptBroadcast)     || MultiCastUpdate) {
   1654       //
   1655       // Clear the UDP4 instance configuration, all joined groups will be left
   1656       // during the operation.
   1657       //
   1658       Private->Udp4Read->Configure (Private->Udp4Read, NULL);
   1659 
   1660       //
   1661       // Configure the UDP instance with the new configuration.
   1662       //
   1663       Udp4Cfg->AcceptPromiscuous = AcceptPromiscuous;
   1664       Udp4Cfg->AcceptBroadcast   = AcceptBroadcast;
   1665       Status = Private->Udp4Read->Configure (Private->Udp4Read, Udp4Cfg);
   1666       if (EFI_ERROR (Status)) {
   1667         return Status;
   1668       }
   1669 
   1670       //
   1671       // In not Promiscuous mode, need to join the new multicast group.
   1672       //
   1673       if (!AcceptPromiscuous) {
   1674         for (Index = 0; Index < NewFilter->IpCnt; ++Index) {
   1675           if (IP4_IS_MULTICAST (EFI_NTOHL (NewFilter->IpList[Index].v4))) {
   1676             //
   1677             // Join the mutilcast group.
   1678             //
   1679             Status = Private->Udp4Read->Groups (Private->Udp4Read, TRUE, &NewFilter->IpList[Index].v4);
   1680             if (EFI_ERROR (Status)) {
   1681               return Status;
   1682             }
   1683           }
   1684         }
   1685       }
   1686     }
   1687   } else {
   1688     //
   1689     // Check whether we need reconfigure the UDP6 instance.
   1690     //
   1691     Udp6Cfg = &Private->Udp6CfgData;
   1692     if ((AcceptPromiscuous != Udp6Cfg->AcceptPromiscuous) || MultiCastUpdate) {
   1693       //
   1694       // Clear the UDP6 instance configuration, all joined groups will be left
   1695       // during the operation.
   1696       //
   1697       Private->Udp6Read->Configure (Private->Udp6Read, NULL);
   1698 
   1699       //
   1700       // Configure the UDP instance with the new configuration.
   1701       //
   1702       Udp6Cfg->AcceptPromiscuous = AcceptPromiscuous;
   1703       Status = Private->Udp6Read->Configure (Private->Udp6Read, Udp6Cfg);
   1704       if (EFI_ERROR (Status)) {
   1705         return Status;
   1706       }
   1707 
   1708       //
   1709       // In not Promiscuous mode, need to join the new multicast group.
   1710       //
   1711       if (!AcceptPromiscuous) {
   1712         for (Index = 0; Index < NewFilter->IpCnt; ++Index) {
   1713           if (IP6_IS_MULTICAST (&NewFilter->IpList[Index].v6)) {
   1714             //
   1715             // Join the mutilcast group.
   1716             //
   1717             Status = Private->Udp6Read->Groups (Private->Udp6Read, TRUE, &NewFilter->IpList[Index].v6);
   1718             if (EFI_ERROR (Status)) {
   1719               return Status;
   1720             }
   1721           }
   1722         }
   1723       }
   1724     }
   1725   }
   1726 
   1727   //
   1728   // Save the new IP filter into mode data.
   1729   //
   1730   CopyMem (&Mode->IpFilter, NewFilter, sizeof (Mode->IpFilter));
   1731 
   1732   return Status;
   1733 }
   1734 
   1735 
   1736 /**
   1737   Uses the ARP protocol to resolve a MAC address. It is not supported for IPv6.
   1738 
   1739   This function uses the ARP protocol to resolve a MAC address. The IP address specified
   1740   by IpAddr is used to resolve a MAC address. If the ARP protocol succeeds in resolving
   1741   the specified address, then the ArpCacheEntries and ArpCache fields of the mode data
   1742   are updated, and EFI_SUCCESS is returned. If MacAddr is not NULL, the resolved
   1743   MAC address is placed there as well.  If the PXE Base Code protocol is in the
   1744   stopped state, then EFI_NOT_STARTED is returned. If the ARP protocol encounters
   1745   a timeout condition while attempting to resolve an address, then EFI_TIMEOUT is
   1746   returned. If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE,
   1747   then EFI_ABORTED is returned.
   1748 
   1749   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
   1750   @param[in]  IpAddr            Pointer to the IP address that is used to resolve a MAC address.
   1751   @param[in]  MacAddr           If not NULL, a pointer to the MAC address that was resolved with the
   1752                                 ARP protocol.
   1753 
   1754   @retval EFI_SUCCESS           The IP or MAC address was resolved.
   1755   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
   1756   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   1757   @retval EFI_DEVICE_ERROR      The network device encountered an error during this operation.
   1758   @retval EFI_ICMP_ERROR        An error occur with the ICMP packet message.
   1759 
   1760 **/
   1761 EFI_STATUS
   1762 EFIAPI
   1763 EfiPxeBcArp (
   1764   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
   1765   IN EFI_IP_ADDRESS                   *IpAddr,
   1766   IN EFI_MAC_ADDRESS                  *MacAddr OPTIONAL
   1767   )
   1768 {
   1769   PXEBC_PRIVATE_DATA      *Private;
   1770   EFI_PXE_BASE_CODE_MODE  *Mode;
   1771   EFI_EVENT               ResolvedEvent;
   1772   EFI_STATUS              Status;
   1773   EFI_MAC_ADDRESS         TempMac;
   1774   EFI_MAC_ADDRESS         ZeroMac;
   1775   BOOLEAN                 IsResolved;
   1776 
   1777   if (This == NULL || IpAddr == NULL) {
   1778     return EFI_INVALID_PARAMETER;
   1779   }
   1780 
   1781   Private       = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
   1782   Mode          = Private->PxeBc.Mode;
   1783   ResolvedEvent = NULL;
   1784   Status        = EFI_SUCCESS;
   1785   IsResolved    = FALSE;
   1786 
   1787   if (!Mode->Started) {
   1788     return EFI_NOT_STARTED;
   1789   }
   1790 
   1791   if (Mode->UsingIpv6) {
   1792     return EFI_UNSUPPORTED;
   1793   }
   1794 
   1795   //
   1796   // Station address should be ready before do arp.
   1797   //
   1798   if (!Private->IsAddressOk) {
   1799     return EFI_INVALID_PARAMETER;
   1800   }
   1801 
   1802   Mode->IcmpErrorReceived = FALSE;
   1803   ZeroMem (&TempMac, sizeof (EFI_MAC_ADDRESS));
   1804   ZeroMem (&ZeroMac, sizeof (EFI_MAC_ADDRESS));
   1805 
   1806   if (!Mode->AutoArp) {
   1807     //
   1808     // If AutoArp is FALSE, only search in the current Arp cache.
   1809     //
   1810     PxeBcArpCacheUpdate (NULL, Private);
   1811     if (!PxeBcCheckArpCache (Mode, &IpAddr->v4, &TempMac)) {
   1812       Status = EFI_DEVICE_ERROR;
   1813       goto ON_EXIT;
   1814     }
   1815   } else {
   1816     Status = gBS->CreateEvent (
   1817                     EVT_NOTIFY_SIGNAL,
   1818                     TPL_NOTIFY,
   1819                     PxeBcCommonNotify,
   1820                     &IsResolved,
   1821                     &ResolvedEvent
   1822                     );
   1823     if (EFI_ERROR (Status)) {
   1824       goto ON_EXIT;
   1825     }
   1826 
   1827     //
   1828     // If AutoArp is TRUE, try to send Arp request on initiative.
   1829     //
   1830     Status = Private->Arp->Request (Private->Arp, &IpAddr->v4, ResolvedEvent, &TempMac);
   1831     if (EFI_ERROR (Status) && Status != EFI_NOT_READY) {
   1832       goto ON_EXIT;
   1833     }
   1834 
   1835     while (!IsResolved) {
   1836       if (CompareMem (&TempMac, &ZeroMac, sizeof (EFI_MAC_ADDRESS)) != 0) {
   1837         break;
   1838       }
   1839     }
   1840     if (CompareMem (&TempMac, &ZeroMac, sizeof (EFI_MAC_ADDRESS)) != 0) {
   1841       Status = EFI_SUCCESS;
   1842     } else {
   1843       Status = EFI_TIMEOUT;
   1844     }
   1845   }
   1846 
   1847   //
   1848   // Copy the Mac address to user if needed.
   1849   //
   1850   if (MacAddr != NULL && !EFI_ERROR (Status)) {
   1851     CopyMem (MacAddr, &TempMac, sizeof (EFI_MAC_ADDRESS));
   1852   }
   1853 
   1854 ON_EXIT:
   1855   if (ResolvedEvent != NULL) {
   1856     gBS->CloseEvent (ResolvedEvent);
   1857   }
   1858   return Status;
   1859 }
   1860 
   1861 
   1862 /**
   1863   Updates the parameters that affect the operation of the PXE Base Code Protocol.
   1864 
   1865   This function sets parameters that affect the operation of the PXE Base Code Protocol.
   1866   The parameter specified by NewAutoArp is used to control the generation of ARP
   1867   protocol packets. If NewAutoArp is TRUE, then ARP Protocol packets will be generated
   1868   as required by the PXE Base Code Protocol. If NewAutoArp is FALSE, then no ARP
   1869   Protocol packets will be generated. In this case, the only mappings that are
   1870   available are those stored in the ArpCache of the EFI_PXE_BASE_CODE_MODE structure.
   1871   If there are not enough mappings in the ArpCache to perform a PXE Base Code Protocol
   1872   service, then the service will fail. This function updates the AutoArp field of
   1873   the EFI_PXE_BASE_CODE_MODE structure to NewAutoArp.
   1874   The SetParameters() call must be invoked after a Callback Protocol is installed
   1875   to enable the use of callbacks.
   1876 
   1877   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
   1878   @param[in]  NewAutoArp        If not NULL, a pointer to a value that specifies whether to replace the
   1879                                 current value of AutoARP.
   1880   @param[in]  NewSendGUID       If not NULL, a pointer to a value that specifies whether to replace the
   1881                                 current value of SendGUID.
   1882   @param[in]  NewTTL            If not NULL, a pointer to be used in place of the current value of TTL,
   1883                                 the "time to live" field of the IP header.
   1884   @param[in]  NewToS            If not NULL, a pointer to be used in place of the current value of ToS,
   1885                                 the "type of service" field of the IP header.
   1886   @param[in]  NewMakeCallback   If not NULL, a pointer to a value that specifies whether to replace the
   1887                                 current value of the MakeCallback field of the Mode structure.
   1888 
   1889   @retval EFI_SUCCESS           The new parameters values were updated.
   1890   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
   1891   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   1892 
   1893 **/
   1894 EFI_STATUS
   1895 EFIAPI
   1896 EfiPxeBcSetParameters (
   1897   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
   1898   IN BOOLEAN                          *NewAutoArp         OPTIONAL,
   1899   IN BOOLEAN                          *NewSendGUID        OPTIONAL,
   1900   IN UINT8                            *NewTTL             OPTIONAL,
   1901   IN UINT8                            *NewToS             OPTIONAL,
   1902   IN BOOLEAN                          *NewMakeCallback    OPTIONAL
   1903   )
   1904 {
   1905   PXEBC_PRIVATE_DATA      *Private;
   1906   EFI_PXE_BASE_CODE_MODE  *Mode;
   1907   EFI_GUID                SystemGuid;
   1908   EFI_STATUS              Status;
   1909 
   1910   if (This == NULL) {
   1911     return EFI_INVALID_PARAMETER;
   1912   }
   1913 
   1914   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
   1915   Mode    = Private->PxeBc.Mode;
   1916 
   1917   if (!Mode->Started) {
   1918     return EFI_NOT_STARTED;
   1919   }
   1920 
   1921   if (NewMakeCallback != NULL) {
   1922     if (*NewMakeCallback) {
   1923       //
   1924       // Update the previous PxeBcCallback protocol.
   1925       //
   1926       Status = gBS->HandleProtocol (
   1927                       Private->Controller,
   1928                       &gEfiPxeBaseCodeCallbackProtocolGuid,
   1929                       (VOID **) &Private->PxeBcCallback
   1930                       );
   1931 
   1932       if (EFI_ERROR (Status) || (Private->PxeBcCallback->Callback == NULL)) {
   1933         return EFI_INVALID_PARAMETER;
   1934       }
   1935     } else {
   1936       Private->PxeBcCallback = NULL;
   1937     }
   1938     Mode->MakeCallbacks = *NewMakeCallback;
   1939   }
   1940 
   1941   if (NewSendGUID != NULL) {
   1942     if (*NewSendGUID && EFI_ERROR (NetLibGetSystemGuid (&SystemGuid))) {
   1943       return EFI_INVALID_PARAMETER;
   1944     }
   1945     Mode->SendGUID = *NewSendGUID;
   1946   }
   1947 
   1948   if (NewAutoArp != NULL) {
   1949     Mode->AutoArp = *NewAutoArp;
   1950   }
   1951 
   1952   if (NewTTL != NULL) {
   1953     Mode->TTL = *NewTTL;
   1954   }
   1955 
   1956   if (NewToS != NULL) {
   1957     Mode->ToS = *NewToS;
   1958   }
   1959 
   1960   return EFI_SUCCESS;
   1961 }
   1962 
   1963 
   1964 /**
   1965   Updates the station IP address and/or subnet mask values of a network device.
   1966 
   1967   This function updates the station IP address and/or subnet mask values of a network
   1968   device. The NewStationIp field is used to modify the network device's current IP address.
   1969   If NewStationIP is NULL, then the current IP address will not be modified. Otherwise,
   1970   this function updates the StationIp field of the EFI_PXE_BASE_CODE_MODE structure
   1971   with NewStationIp. The NewSubnetMask field is used to modify the network device's current subnet
   1972   mask. If NewSubnetMask is NULL, then the current subnet mask will not be modified.
   1973   Otherwise, this function updates the SubnetMask field of the EFI_PXE_BASE_CODE_MODE
   1974   structure with NewSubnetMask.
   1975 
   1976   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
   1977   @param[in]  NewStationIp      Pointer to the new IP address to be used by the network device.
   1978   @param[in]  NewSubnetMask     Pointer to the new subnet mask to be used by the network device.
   1979 
   1980   @retval EFI_SUCCESS           The new station IP address and/or subnet mask were updated.
   1981   @retval EFI_NOT_STARTED       The PXE Base Code Protocol is in the stopped state.
   1982   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
   1983 
   1984 **/
   1985 EFI_STATUS
   1986 EFIAPI
   1987 EfiPxeBcSetStationIP (
   1988   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
   1989   IN EFI_IP_ADDRESS                   *NewStationIp    OPTIONAL,
   1990   IN EFI_IP_ADDRESS                   *NewSubnetMask   OPTIONAL
   1991   )
   1992 {
   1993   EFI_STATUS              Status;
   1994   PXEBC_PRIVATE_DATA      *Private;
   1995   EFI_PXE_BASE_CODE_MODE  *Mode;
   1996   EFI_ARP_CONFIG_DATA     ArpConfigData;
   1997 
   1998   if (This == NULL) {
   1999     return EFI_INVALID_PARAMETER;
   2000   }
   2001 
   2002   if (NewStationIp != NULL && !NetIp6IsValidUnicast (&NewStationIp->v6)) {
   2003     return EFI_INVALID_PARAMETER;
   2004   }
   2005 
   2006   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
   2007   Mode    = Private->PxeBc.Mode;
   2008   Status  = EFI_SUCCESS;
   2009 
   2010   if (!Mode->UsingIpv6 &&
   2011       NewSubnetMask != NULL &&
   2012       !IP4_IS_VALID_NETMASK (NTOHL (NewSubnetMask->Addr[0]))) {
   2013     return EFI_INVALID_PARAMETER;
   2014   }
   2015 
   2016   if (!Mode->UsingIpv6 && NewStationIp != NULL) {
   2017     if (IP4_IS_UNSPECIFIED(NTOHL (NewStationIp->Addr[0])) ||
   2018         IP4_IS_LOCAL_BROADCAST(NTOHL (NewStationIp->Addr[0])) ||
   2019         (NewSubnetMask != NULL && !NetIp4IsUnicast (NTOHL (NewStationIp->Addr[0]), NTOHL (NewSubnetMask->Addr[0])))) {
   2020       return EFI_INVALID_PARAMETER;
   2021     }
   2022   }
   2023 
   2024   if (!Mode->Started) {
   2025     return EFI_NOT_STARTED;
   2026   }
   2027 
   2028   if (Mode->UsingIpv6 && NewStationIp != NULL) {
   2029     //
   2030     // Set the IPv6 address by Ip6Config protocol.
   2031     //
   2032     Status = PxeBcRegisterIp6Address (Private, &NewStationIp->v6);
   2033     if (EFI_ERROR (Status)) {
   2034       goto ON_EXIT;
   2035     }
   2036   } else if (!Mode->UsingIpv6 && NewStationIp != NULL) {
   2037     //
   2038     // Configure the corresponding ARP with the IPv4 address.
   2039     //
   2040     ZeroMem (&ArpConfigData, sizeof (EFI_ARP_CONFIG_DATA));
   2041 
   2042     ArpConfigData.SwAddressType   = 0x0800;
   2043     ArpConfigData.SwAddressLength = (UINT8) sizeof (EFI_IPv4_ADDRESS);
   2044     ArpConfigData.StationAddress  = &NewStationIp->v4;
   2045 
   2046     Private->Arp->Configure (Private->Arp, NULL);
   2047     Private->Arp->Configure (Private->Arp, &ArpConfigData);
   2048 
   2049     if (NewSubnetMask != NULL) {
   2050       Mode->RouteTableEntries                = 1;
   2051       Mode->RouteTable[0].IpAddr.Addr[0]     = NewStationIp->Addr[0] & NewSubnetMask->Addr[0];
   2052       Mode->RouteTable[0].SubnetMask.Addr[0] = NewSubnetMask->Addr[0];
   2053       Mode->RouteTable[0].GwAddr.Addr[0]     = 0;
   2054     }
   2055 
   2056     Private->IsAddressOk = TRUE;
   2057   }
   2058 
   2059   if (NewStationIp != NULL) {
   2060     CopyMem (&Mode->StationIp, NewStationIp, sizeof (EFI_IP_ADDRESS));
   2061     CopyMem (&Private->StationIp, NewStationIp, sizeof (EFI_IP_ADDRESS));
   2062   }
   2063 
   2064   if (!Mode->UsingIpv6 && NewSubnetMask != NULL) {
   2065     CopyMem (&Mode->SubnetMask, NewSubnetMask, sizeof (EFI_IP_ADDRESS));
   2066     CopyMem (&Private->SubnetMask ,NewSubnetMask, sizeof (EFI_IP_ADDRESS));
   2067   }
   2068 
   2069   Status = PxeBcFlushStationIp (Private, NewStationIp, NewSubnetMask);
   2070 ON_EXIT:
   2071   return Status;
   2072 }
   2073 
   2074 
   2075 /**
   2076   Updates the contents of the cached DHCP and Discover packets.
   2077 
   2078   The pointers to the new packets are used to update the contents of the cached
   2079   packets in the EFI_PXE_BASE_CODE_MODE structure.
   2080 
   2081   @param[in]  This                   Pointer to the EFI_PXE_BASE_CODE_PROTOCOL instance.
   2082   @param[in]  NewDhcpDiscoverValid   Pointer to a value that will replace the current
   2083                                      DhcpDiscoverValid field.
   2084   @param[in]  NewDhcpAckReceived     Pointer to a value that will replace the current
   2085                                      DhcpAckReceived field.
   2086   @param[in]  NewProxyOfferReceived  Pointer to a value that will replace the current
   2087                                      ProxyOfferReceived field.
   2088   @param[in]  NewPxeDiscoverValid    Pointer to a value that will replace the current
   2089                                      ProxyOfferReceived field.
   2090   @param[in]  NewPxeReplyReceived    Pointer to a value that will replace the current
   2091                                      PxeReplyReceived field.
   2092   @param[in]  NewPxeBisReplyReceived Pointer to a value that will replace the current
   2093                                      PxeBisReplyReceived field.
   2094   @param[in]  NewDhcpDiscover        Pointer to the new cached DHCP Discover packet contents.
   2095   @param[in]  NewDhcpAck             Pointer to the new cached DHCP Ack packet contents.
   2096   @param[in]  NewProxyOffer          Pointer to the new cached Proxy Offer packet contents.
   2097   @param[in]  NewPxeDiscover         Pointer to the new cached PXE Discover packet contents.
   2098   @param[in]  NewPxeReply            Pointer to the new cached PXE Reply packet contents.
   2099   @param[in]  NewPxeBisReply         Pointer to the new cached PXE BIS Reply packet contents.
   2100 
   2101   @retval EFI_SUCCESS            The cached packet contents were updated.
   2102   @retval EFI_NOT_STARTED        The PXE Base Code Protocol is in the stopped state.
   2103   @retval EFI_INVALID_PARAMETER  This is NULL or does not point to a valid
   2104                                  EFI_PXE_BASE_CODE_PROTOCOL structure.
   2105 
   2106 **/
   2107 EFI_STATUS
   2108 EFIAPI
   2109 EfiPxeBcSetPackets (
   2110   IN EFI_PXE_BASE_CODE_PROTOCOL       *This,
   2111   IN BOOLEAN                          *NewDhcpDiscoverValid      OPTIONAL,
   2112   IN BOOLEAN                          *NewDhcpAckReceived        OPTIONAL,
   2113   IN BOOLEAN                          *NewProxyOfferReceived     OPTIONAL,
   2114   IN BOOLEAN                          *NewPxeDiscoverValid       OPTIONAL,
   2115   IN BOOLEAN                          *NewPxeReplyReceived       OPTIONAL,
   2116   IN BOOLEAN                          *NewPxeBisReplyReceived    OPTIONAL,
   2117   IN EFI_PXE_BASE_CODE_PACKET         *NewDhcpDiscover           OPTIONAL,
   2118   IN EFI_PXE_BASE_CODE_PACKET         *NewDhcpAck                OPTIONAL,
   2119   IN EFI_PXE_BASE_CODE_PACKET         *NewProxyOffer             OPTIONAL,
   2120   IN EFI_PXE_BASE_CODE_PACKET         *NewPxeDiscover            OPTIONAL,
   2121   IN EFI_PXE_BASE_CODE_PACKET         *NewPxeReply               OPTIONAL,
   2122   IN EFI_PXE_BASE_CODE_PACKET         *NewPxeBisReply            OPTIONAL
   2123   )
   2124 {
   2125   PXEBC_PRIVATE_DATA      *Private;
   2126   EFI_PXE_BASE_CODE_MODE  *Mode;
   2127 
   2128   if (This == NULL) {
   2129     return EFI_INVALID_PARAMETER;
   2130   }
   2131 
   2132   Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
   2133   Mode    = Private->PxeBc.Mode;
   2134 
   2135   if (!Mode->Started) {
   2136     return EFI_NOT_STARTED;
   2137   }
   2138 
   2139   if (NewDhcpDiscoverValid != NULL) {
   2140     Mode->DhcpDiscoverValid = *NewDhcpDiscoverValid;
   2141   }
   2142 
   2143   if (NewDhcpAckReceived != NULL) {
   2144     Mode->DhcpAckReceived = *NewDhcpAckReceived;
   2145   }
   2146 
   2147   if (NewProxyOfferReceived != NULL) {
   2148     Mode->ProxyOfferReceived = *NewProxyOfferReceived;
   2149   }
   2150 
   2151   if (NewPxeDiscoverValid != NULL) {
   2152     Mode->PxeDiscoverValid = *NewPxeDiscoverValid;
   2153   }
   2154 
   2155   if (NewPxeReplyReceived != NULL) {
   2156     Mode->PxeReplyReceived = *NewPxeReplyReceived;
   2157   }
   2158 
   2159   if (NewPxeBisReplyReceived != NULL) {
   2160     Mode->PxeBisReplyReceived = *NewPxeBisReplyReceived;
   2161   }
   2162 
   2163   if (NewDhcpDiscover != NULL) {
   2164     CopyMem (&Mode->DhcpDiscover, NewDhcpDiscover, sizeof (EFI_PXE_BASE_CODE_PACKET));
   2165   }
   2166 
   2167   if (NewDhcpAck != NULL) {
   2168     CopyMem (&Mode->DhcpAck, NewDhcpAck, sizeof (EFI_PXE_BASE_CODE_PACKET));
   2169   }
   2170 
   2171   if (NewProxyOffer != NULL) {
   2172     CopyMem (&Mode->ProxyOffer, NewProxyOffer, sizeof (EFI_PXE_BASE_CODE_PACKET));
   2173   }
   2174 
   2175   if (NewPxeDiscover != NULL) {
   2176     CopyMem (&Mode->PxeDiscover, NewPxeDiscover, sizeof (EFI_PXE_BASE_CODE_PACKET));
   2177   }
   2178 
   2179   if (NewPxeReply != NULL) {
   2180     CopyMem (&Mode->PxeReply, NewPxeReply, sizeof (EFI_PXE_BASE_CODE_PACKET));
   2181   }
   2182 
   2183   if (NewPxeBisReply != NULL) {
   2184     CopyMem (&Mode->PxeBisReply, NewPxeBisReply, sizeof (EFI_PXE_BASE_CODE_PACKET));
   2185   }
   2186 
   2187   return EFI_SUCCESS;
   2188 }
   2189 
   2190 EFI_PXE_BASE_CODE_PROTOCOL  gPxeBcProtocolTemplate = {
   2191   EFI_PXE_BASE_CODE_PROTOCOL_REVISION,
   2192   EfiPxeBcStart,
   2193   EfiPxeBcStop,
   2194   EfiPxeBcDhcp,
   2195   EfiPxeBcDiscover,
   2196   EfiPxeBcMtftp,
   2197   EfiPxeBcUdpWrite,
   2198   EfiPxeBcUdpRead,
   2199   EfiPxeBcSetIpFilter,
   2200   EfiPxeBcArp,
   2201   EfiPxeBcSetParameters,
   2202   EfiPxeBcSetStationIP,
   2203   EfiPxeBcSetPackets,
   2204   NULL
   2205 };
   2206 
   2207 
   2208 /**
   2209   Callback function that is invoked when the PXE Base Code Protocol is about to transmit, has
   2210   received, or is waiting to receive a packet.
   2211 
   2212   This function is invoked when the PXE Base Code Protocol is about to transmit, has received,
   2213   or is waiting to receive a packet. Parameters Function and Received specify the type of event.
   2214   Parameters PacketLen and Packet specify the packet that generated the event. If these fields
   2215   are zero and NULL respectively, then this is a status update callback. If the operation specified
   2216   by Function is to continue, then CALLBACK_STATUS_CONTINUE should be returned. If the operation
   2217   specified by Function should be aborted, then CALLBACK_STATUS_ABORT should be returned. Due to
   2218   the polling nature of UEFI device drivers, a callback function should not execute for more than 5 ms.
   2219   The SetParameters() function must be called after a Callback Protocol is installed to enable the
   2220   use of callbacks.
   2221 
   2222   @param[in]  This              Pointer to the EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL instance.
   2223   @param[in]  Function          The PXE Base Code Protocol function that is waiting for an event.
   2224   @param[in]  Received          TRUE if the callback is being invoked due to a receive event. FALSE if
   2225                                 the callback is being invoked due to a transmit event.
   2226   @param[in]  PacketLength      The length, in bytes, of Packet. This field will have a value of zero if
   2227                                 this is a wait for receive event.
   2228   @param[in]  PacketPtr         If Received is TRUE, a pointer to the packet that was just received;
   2229                                 otherwise a pointer to the packet that is about to be transmitted.
   2230 
   2231   @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE If Function specifies a continue operation.
   2232   @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT    If Function specifies an abort operation.
   2233 
   2234 **/
   2235 EFI_PXE_BASE_CODE_CALLBACK_STATUS
   2236 EFIAPI
   2237 EfiPxeLoadFileCallback (
   2238   IN EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL  *This,
   2239   IN EFI_PXE_BASE_CODE_FUNCTION           Function,
   2240   IN BOOLEAN                              Received,
   2241   IN UINT32                               PacketLength,
   2242   IN EFI_PXE_BASE_CODE_PACKET             *PacketPtr     OPTIONAL
   2243   )
   2244 {
   2245   EFI_INPUT_KEY       Key;
   2246   EFI_STATUS          Status;
   2247 
   2248   //
   2249   // Catch Ctrl-C or ESC to abort.
   2250   //
   2251   Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
   2252 
   2253   if (!EFI_ERROR (Status)) {
   2254 
   2255     if (Key.ScanCode == SCAN_ESC || Key.UnicodeChar == (0x1F & 'c')) {
   2256 
   2257       return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;
   2258     }
   2259   }
   2260   //
   2261   // No print if receive packet
   2262   //
   2263   if (Received) {
   2264     return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
   2265   }
   2266   //
   2267   // Print only for three functions
   2268   //
   2269   switch (Function) {
   2270 
   2271   case EFI_PXE_BASE_CODE_FUNCTION_MTFTP:
   2272     //
   2273     // Print only for open MTFTP packets, not every MTFTP packets
   2274     //
   2275     if (PacketLength != 0 && PacketPtr != NULL) {
   2276       if (PacketPtr->Raw[0x1C] != 0x00 || PacketPtr->Raw[0x1D] != 0x01) {
   2277         return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
   2278       }
   2279     }
   2280     break;
   2281 
   2282   case EFI_PXE_BASE_CODE_FUNCTION_DHCP:
   2283   case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER:
   2284     break;
   2285 
   2286   default:
   2287     return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
   2288   }
   2289 
   2290   if (PacketLength != 0 && PacketPtr != NULL) {
   2291     //
   2292     // Print '.' when transmit a packet
   2293     //
   2294     AsciiPrint (".");
   2295   }
   2296 
   2297   return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
   2298 }
   2299 
   2300 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL gPxeBcCallBackTemplate = {
   2301   EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL_REVISION,
   2302   EfiPxeLoadFileCallback
   2303 };
   2304 
   2305 
   2306 /**
   2307   Causes the driver to load a specified file.
   2308 
   2309   @param[in]      This                Protocol instance pointer.
   2310   @param[in]      FilePath            The device specific path of the file to load.
   2311   @param[in]      BootPolicy          If TRUE, indicates that the request originates from the
   2312                                       boot manager is attempting to load FilePath as a boot
   2313                                       selection. If FALSE, then FilePath must match an exact file
   2314                                       to be loaded.
   2315   @param[in, out] BufferSize          On input the size of Buffer in bytes. On output with a return
   2316                                       code of EFI_SUCCESS, the amount of data transferred to
   2317                                       Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL,
   2318                                       the size of Buffer required to retrieve the requested file.
   2319   @param[in]      Buffer              The memory buffer to transfer the file to. IF Buffer is NULL,
   2320                                       then no the size of the requested file is returned in
   2321                                       BufferSize.
   2322 
   2323   @retval EFI_SUCCESS                 The file was loaded.
   2324   @retval EFI_UNSUPPORTED             The device does not support the provided BootPolicy.
   2325   @retval EFI_INVALID_PARAMETER       FilePath is not a valid device path, or
   2326                                       BufferSize is NULL.
   2327   @retval EFI_NO_MEDIA                No medium was present to load the file.
   2328   @retval EFI_DEVICE_ERROR            The file was not loaded due to a device error.
   2329   @retval EFI_NO_RESPONSE             The remote system did not respond.
   2330   @retval EFI_NOT_FOUND               The file was not found.
   2331   @retval EFI_ABORTED                 The file load process was manually cancelled.
   2332 
   2333 **/
   2334 EFI_STATUS
   2335 EFIAPI
   2336 EfiPxeLoadFile (
   2337   IN     EFI_LOAD_FILE_PROTOCOL           *This,
   2338   IN     EFI_DEVICE_PATH_PROTOCOL         *FilePath,
   2339   IN     BOOLEAN                          BootPolicy,
   2340   IN OUT UINTN                            *BufferSize,
   2341   IN     VOID                             *Buffer       OPTIONAL
   2342   )
   2343 {
   2344   PXEBC_PRIVATE_DATA          *Private;
   2345   PXEBC_VIRTUAL_NIC           *VirtualNic;
   2346   EFI_PXE_BASE_CODE_PROTOCOL  *PxeBc;
   2347   BOOLEAN                     UsingIpv6;
   2348   EFI_STATUS                  Status;
   2349   BOOLEAN                     MediaPresent;
   2350 
   2351   if (FilePath == NULL || !IsDevicePathEnd (FilePath)) {
   2352     return EFI_INVALID_PARAMETER;
   2353   }
   2354 
   2355   VirtualNic = PXEBC_VIRTUAL_NIC_FROM_LOADFILE (This);
   2356   Private    = VirtualNic->Private;
   2357   PxeBc      = &Private->PxeBc;
   2358   UsingIpv6  = FALSE;
   2359   Status     = EFI_DEVICE_ERROR;
   2360 
   2361   if (This == NULL || BufferSize == NULL) {
   2362     return EFI_INVALID_PARAMETER;
   2363   }
   2364 
   2365   //
   2366   // Only support BootPolicy
   2367   //
   2368   if (!BootPolicy) {
   2369     return EFI_UNSUPPORTED;
   2370   }
   2371 
   2372   //
   2373   // Check media status before PXE start
   2374   //
   2375   MediaPresent = TRUE;
   2376   NetLibDetectMedia (Private->Controller, &MediaPresent);
   2377   if (!MediaPresent) {
   2378     return EFI_NO_MEDIA;
   2379   }
   2380 
   2381   //
   2382   // Check whether the virtual nic is using IPv6 or not.
   2383   //
   2384   if (VirtualNic == Private->Ip6Nic) {
   2385     UsingIpv6 = TRUE;
   2386   }
   2387 
   2388   //
   2389   // Start Pxe Base Code to initialize PXE boot.
   2390   //
   2391   Status = PxeBc->Start (PxeBc, UsingIpv6);
   2392   if (Status == EFI_ALREADY_STARTED && UsingIpv6 != PxeBc->Mode->UsingIpv6) {
   2393     //
   2394     // PxeBc protocol has already been started but not on the required IP version, restart it.
   2395     //
   2396     Status = PxeBc->Stop (PxeBc);
   2397     if (!EFI_ERROR (Status)) {
   2398       Status = PxeBc->Start (PxeBc, UsingIpv6);
   2399     }
   2400   }
   2401   if (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED) {
   2402     Status = PxeBcLoadBootFile (Private, BufferSize, Buffer);
   2403   }
   2404 
   2405   if (Status != EFI_SUCCESS &&
   2406       Status != EFI_UNSUPPORTED &&
   2407       Status != EFI_BUFFER_TOO_SMALL) {
   2408     //
   2409     // There are three cases, which needn't stop pxebc here.
   2410     //   1. success to download file.
   2411     //   2. success to get file size.
   2412     //   3. unsupported.
   2413     //
   2414     PxeBc->Stop (PxeBc);
   2415   } else {
   2416     //
   2417     // The DHCP4 can have only one configured child instance so we need to stop
   2418     // reset the DHCP4 child before we return. Otherwise these programs which
   2419     // also need to use DHCP4 will be impacted.
   2420     //
   2421     if (!PxeBc->Mode->UsingIpv6) {
   2422       Private->Dhcp4->Stop (Private->Dhcp4);
   2423       Private->Dhcp4->Configure (Private->Dhcp4, NULL);
   2424     }
   2425   }
   2426 
   2427   return Status;
   2428 }
   2429 
   2430 EFI_LOAD_FILE_PROTOCOL  gLoadFileProtocolTemplate = { EfiPxeLoadFile };
   2431 
   2432