Home | History | Annotate | Download | only in UefiPxeBcDxe
      1 /** @file
      2   Support functions implementation for UefiPxeBc Driver.
      3 
      4   Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php.
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "PxeBcImpl.h"
     17 
     18 
     19 /**
     20   Flush the previous configration using the new station Ip address.
     21 
     22   @param[in]   Private        The pointer to the PxeBc private data.
     23   @param[in]   StationIp      The pointer to the station Ip address.
     24   @param[in]   SubnetMask     The pointer to the subnet mask address for v4.
     25 
     26   @retval EFI_SUCCESS         Successfully flushed the previous configuration.
     27   @retval Others              Failed to flush using the new station Ip.
     28 
     29 **/
     30 EFI_STATUS
     31 PxeBcFlushStationIp (
     32   PXEBC_PRIVATE_DATA       *Private,
     33   EFI_IP_ADDRESS           *StationIp,
     34   EFI_IP_ADDRESS           *SubnetMask     OPTIONAL
     35   )
     36 {
     37   EFI_PXE_BASE_CODE_MODE   *Mode;
     38   EFI_STATUS               Status;
     39 
     40   ASSERT (StationIp != NULL);
     41 
     42   Mode   = Private->PxeBc.Mode;
     43   Status = EFI_SUCCESS;
     44 
     45   if (Mode->UsingIpv6) {
     46 
     47     CopyMem (&Private->Udp6CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));
     48     CopyMem (&Private->Ip6CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));
     49 
     50     //
     51     // Reconfigure the Ip6 instance to capture background ICMP6 packets with new station Ip address.
     52     //
     53     Private->Ip6->Cancel (Private->Ip6, &Private->Icmp6Token);
     54     Private->Ip6->Configure (Private->Ip6, NULL);
     55 
     56     Status = Private->Ip6->Configure (Private->Ip6, &Private->Ip6CfgData);
     57     if (EFI_ERROR (Status)) {
     58       goto ON_EXIT;
     59     }
     60 
     61     Status = Private->Ip6->Receive (Private->Ip6, &Private->Icmp6Token);
     62   } else {
     63     ASSERT (SubnetMask != NULL);
     64     CopyMem (&Private->Udp4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));
     65     CopyMem (&Private->Udp4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));
     66     CopyMem (&Private->Ip4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));
     67     CopyMem (&Private->Ip4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));
     68 
     69     //
     70     // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.
     71     //
     72     Private->Ip4->Cancel (Private->Ip4, &Private->IcmpToken);
     73     Private->Ip4->Configure (Private->Ip4, NULL);
     74 
     75     Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4CfgData);
     76     if (EFI_ERROR (Status)) {
     77       goto ON_EXIT;
     78     }
     79 
     80     Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpToken);
     81   }
     82 
     83 ON_EXIT:
     84   return Status;
     85 }
     86 
     87 
     88 /**
     89   Notify the callback function when an event is triggered.
     90 
     91   @param[in]  Event           The triggered event.
     92   @param[in]  Context         The opaque parameter to the function.
     93 
     94 **/
     95 VOID
     96 EFIAPI
     97 PxeBcCommonNotify (
     98   IN EFI_EVENT           Event,
     99   IN VOID                *Context
    100   )
    101 {
    102   *((BOOLEAN *) Context) = TRUE;
    103 }
    104 
    105 
    106 /**
    107   Do arp resolution from arp cache in PxeBcMode.
    108 
    109   @param  Mode           The pointer to EFI_PXE_BASE_CODE_MODE.
    110   @param  Ip4Addr        The Ip4 address for resolution.
    111   @param  MacAddress     The resoluted MAC address if the resolution is successful.
    112                          The value is undefined if the resolution fails.
    113 
    114   @retval TRUE           Found an matched entry.
    115   @retval FALSE          Did not find a matched entry.
    116 
    117 **/
    118 BOOLEAN
    119 PxeBcCheckArpCache (
    120   IN  EFI_PXE_BASE_CODE_MODE    *Mode,
    121   IN  EFI_IPv4_ADDRESS          *Ip4Addr,
    122   OUT EFI_MAC_ADDRESS           *MacAddress
    123   )
    124 {
    125   UINT32       Index;
    126 
    127   ASSERT (!Mode->UsingIpv6);
    128 
    129   //
    130   // Check whether the current Arp cache in mode data contains this information or not.
    131   //
    132   for (Index = 0; Index < Mode->ArpCacheEntries; Index++) {
    133     if (EFI_IP4_EQUAL (&Mode->ArpCache[Index].IpAddr.v4, Ip4Addr)) {
    134       CopyMem (
    135         MacAddress,
    136         &Mode->ArpCache[Index].MacAddr,
    137         sizeof (EFI_MAC_ADDRESS)
    138         );
    139       return TRUE;
    140     }
    141   }
    142 
    143   return FALSE;
    144 }
    145 
    146 
    147 /**
    148   Update the arp cache periodically.
    149 
    150   @param  Event              The pointer to EFI_PXE_BC_PROTOCOL.
    151   @param  Context            Context of the timer event.
    152 
    153 **/
    154 VOID
    155 EFIAPI
    156 PxeBcArpCacheUpdate (
    157   IN EFI_EVENT            Event,
    158   IN VOID                 *Context
    159   )
    160 {
    161   PXEBC_PRIVATE_DATA      *Private;
    162   EFI_PXE_BASE_CODE_MODE  *Mode;
    163   EFI_ARP_FIND_DATA       *ArpEntry;
    164   UINT32                  EntryLength;
    165   UINT32                  EntryCount;
    166   UINT32                  Index;
    167   EFI_STATUS              Status;
    168 
    169   Private = (PXEBC_PRIVATE_DATA *) Context;
    170   Mode    = Private->PxeBc.Mode;
    171 
    172   ASSERT (!Mode->UsingIpv6);
    173 
    174   //
    175   // Get the current Arp cache from Arp driver.
    176   //
    177   Status = Private->Arp->Find (
    178                            Private->Arp,
    179                            TRUE,
    180                            NULL,
    181                            &EntryLength,
    182                            &EntryCount,
    183                            &ArpEntry,
    184                            TRUE
    185                            );
    186   if (EFI_ERROR (Status)) {
    187     return;
    188   }
    189 
    190   //
    191   // Update the Arp cache in mode data.
    192   //
    193   Mode->ArpCacheEntries = MIN (EntryCount, EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES);
    194 
    195   for (Index = 0; Index < Mode->ArpCacheEntries; Index++) {
    196     CopyMem (
    197       &Mode->ArpCache[Index].IpAddr,
    198       ArpEntry + 1,
    199       ArpEntry->SwAddressLength
    200       );
    201     CopyMem (
    202       &Mode->ArpCache[Index].MacAddr,
    203       (UINT8 *) (ArpEntry + 1) + ArpEntry->SwAddressLength,
    204       ArpEntry->HwAddressLength
    205       );
    206     ArpEntry = (EFI_ARP_FIND_DATA *) ((UINT8 *) ArpEntry + EntryLength);
    207   }
    208 }
    209 
    210 
    211 /**
    212   Notify function to handle the received ICMP message in DPC.
    213 
    214   @param  Context               The PXEBC private data.
    215 
    216 **/
    217 VOID
    218 EFIAPI
    219 PxeBcIcmpErrorDpcHandle (
    220   IN VOID                      *Context
    221   )
    222 {
    223   EFI_STATUS                   Status;
    224   EFI_IP4_RECEIVE_DATA         *RxData;
    225   EFI_IP4_PROTOCOL             *Ip4;
    226   PXEBC_PRIVATE_DATA           *Private;
    227   EFI_PXE_BASE_CODE_MODE       *Mode;
    228   UINT8                        Type;
    229   UINTN                        Index;
    230   UINT32                       CopiedLen;
    231   UINT8                        *IcmpError;
    232 
    233   Private = (PXEBC_PRIVATE_DATA *) Context;
    234   Mode    = &Private->Mode;
    235   Status  = Private->IcmpToken.Status;
    236   RxData  = Private->IcmpToken.Packet.RxData;
    237   Ip4     = Private->Ip4;
    238 
    239   ASSERT (!Mode->UsingIpv6);
    240 
    241   if (Status == EFI_ABORTED) {
    242     //
    243     // It's triggered by user cancellation.
    244     //
    245     return;
    246   }
    247 
    248   if (RxData == NULL) {
    249     goto ON_EXIT;
    250   }
    251 
    252   if (Status != EFI_ICMP_ERROR) {
    253     //
    254     // The return status should be recognized as EFI_ICMP_ERROR.
    255     //
    256     gBS->SignalEvent (RxData->RecycleSignal);
    257     goto ON_EXIT;
    258   }
    259 
    260   if (EFI_IP4 (RxData->Header->SourceAddress) != 0 &&
    261       !NetIp4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) {
    262     //
    263     // The source address of the received packet should be a valid unicast address.
    264     //
    265     gBS->SignalEvent (RxData->RecycleSignal);
    266     goto ON_EXIT;
    267   }
    268 
    269   if (!EFI_IP4_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v4)) {
    270     //
    271     // The destination address of the received packet should be equal to the host address.
    272     //
    273     gBS->SignalEvent (RxData->RecycleSignal);
    274     goto ON_EXIT;
    275   }
    276 
    277   if (RxData->Header->Protocol != EFI_IP_PROTO_ICMP) {
    278     //
    279     // The protocol value in the header of the receveid packet should be EFI_IP_PROTO_ICMP.
    280     //
    281     gBS->SignalEvent (RxData->RecycleSignal);
    282     goto ON_EXIT;
    283   }
    284 
    285   Type = *((UINT8 *) RxData->FragmentTable[0].FragmentBuffer);
    286 
    287   if (Type != ICMP_DEST_UNREACHABLE &&
    288       Type != ICMP_SOURCE_QUENCH &&
    289       Type != ICMP_REDIRECT &&
    290       Type != ICMP_TIME_EXCEEDED &&
    291       Type != ICMP_PARAMETER_PROBLEM) {
    292     //
    293     // The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE.
    294     //
    295     gBS->SignalEvent (RxData->RecycleSignal);
    296     goto ON_EXIT;
    297   }
    298 
    299   //
    300   // Copy the right ICMP error message into mode data.
    301   //
    302   CopiedLen = 0;
    303   IcmpError = (UINT8 *) &Mode->IcmpError;
    304 
    305   for (Index = 0; Index < RxData->FragmentCount; Index++) {
    306     CopiedLen += RxData->FragmentTable[Index].FragmentLength;
    307     if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {
    308       CopyMem (
    309         IcmpError,
    310         RxData->FragmentTable[Index].FragmentBuffer,
    311         RxData->FragmentTable[Index].FragmentLength
    312         );
    313     } else {
    314       CopyMem (
    315         IcmpError,
    316         RxData->FragmentTable[Index].FragmentBuffer,
    317         CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
    318         );
    319     }
    320     IcmpError += CopiedLen;
    321   }
    322 
    323 ON_EXIT:
    324   Private->IcmpToken.Status = EFI_NOT_READY;
    325   Ip4->Receive (Ip4, &Private->IcmpToken);
    326 }
    327 
    328 
    329 /**
    330   Callback function to update the latest ICMP6 error message.
    331 
    332   @param  Event                 The event signalled.
    333   @param  Context               The context passed in using the event notifier.
    334 
    335 **/
    336 VOID
    337 EFIAPI
    338 PxeBcIcmpErrorUpdate (
    339   IN EFI_EVENT            Event,
    340   IN VOID                 *Context
    341   )
    342 {
    343   QueueDpc (TPL_CALLBACK, PxeBcIcmpErrorDpcHandle, Context);
    344 }
    345 
    346 
    347 /**
    348   Notify function to handle the received ICMP6 message in DPC.
    349 
    350   @param  Context               The PXEBC private data.
    351 
    352 **/
    353 VOID
    354 EFIAPI
    355 PxeBcIcmp6ErrorDpcHandle (
    356   IN VOID                 *Context
    357   )
    358 {
    359   PXEBC_PRIVATE_DATA      *Private;
    360   EFI_IP6_RECEIVE_DATA    *RxData;
    361   EFI_IP6_PROTOCOL        *Ip6;
    362   EFI_PXE_BASE_CODE_MODE  *Mode;
    363   EFI_STATUS              Status;
    364   UINTN                   Index;
    365   UINT8                   Type;
    366   UINT32                  CopiedLen;
    367   UINT8                   *Icmp6Error;
    368 
    369   Private = (PXEBC_PRIVATE_DATA *) Context;
    370   Mode    = &Private->Mode;
    371   Status  = Private->Icmp6Token.Status;
    372   RxData  = Private->Icmp6Token.Packet.RxData;
    373   Ip6     = Private->Ip6;
    374 
    375   ASSERT (Mode->UsingIpv6);
    376 
    377   if (Status == EFI_ABORTED) {
    378     //
    379     // It's triggered by user cancellation.
    380     //
    381     return;
    382   }
    383 
    384   if (RxData == NULL) {
    385     goto ON_EXIT;
    386   }
    387 
    388   if (Status != EFI_ICMP_ERROR) {
    389     //
    390     // The return status should be recognized as EFI_ICMP_ERROR.
    391     //
    392     gBS->SignalEvent (RxData->RecycleSignal);
    393     goto ON_EXIT;
    394   }
    395 
    396   if (!NetIp6IsValidUnicast (&RxData->Header->SourceAddress)) {
    397     //
    398     // The source address of the received packet should be a valid unicast address.
    399     //
    400     gBS->SignalEvent (RxData->RecycleSignal);
    401     goto ON_EXIT;
    402   }
    403 
    404   if (!NetIp6IsUnspecifiedAddr (&Mode->StationIp.v6) &&
    405       !EFI_IP6_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v6)) {
    406     //
    407     // The destination address of the received packet should be equal to the host address.
    408     //
    409     gBS->SignalEvent (RxData->RecycleSignal);
    410     goto ON_EXIT;
    411   }
    412 
    413   if (RxData->Header->NextHeader != IP6_ICMP) {
    414     //
    415     // The nextheader in the header of the receveid packet should be IP6_ICMP.
    416     //
    417     gBS->SignalEvent (RxData->RecycleSignal);
    418     goto ON_EXIT;
    419   }
    420 
    421   Type = *((UINT8 *) RxData->FragmentTable[0].FragmentBuffer);
    422 
    423   if (Type != ICMP_V6_DEST_UNREACHABLE &&
    424       Type != ICMP_V6_PACKET_TOO_BIG &&
    425       Type != ICMP_V6_PACKET_TOO_BIG &&
    426       Type != ICMP_V6_PARAMETER_PROBLEM) {
    427     //
    428     // The type of the receveid packet should be an ICMP6 error message.
    429     //
    430     gBS->SignalEvent (RxData->RecycleSignal);
    431     goto ON_EXIT;
    432   }
    433 
    434   //
    435   // Copy the right ICMP6 error message into mode data.
    436   //
    437   CopiedLen  = 0;
    438   Icmp6Error = (UINT8 *) &Mode->IcmpError;
    439 
    440   for (Index = 0; Index < RxData->FragmentCount; Index++) {
    441     CopiedLen += RxData->FragmentTable[Index].FragmentLength;
    442     if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {
    443       CopyMem (
    444         Icmp6Error,
    445         RxData->FragmentTable[Index].FragmentBuffer,
    446         RxData->FragmentTable[Index].FragmentLength
    447         );
    448     } else {
    449       CopyMem (
    450         Icmp6Error,
    451         RxData->FragmentTable[Index].FragmentBuffer,
    452         CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
    453         );
    454     }
    455     Icmp6Error += CopiedLen;
    456   }
    457 
    458 ON_EXIT:
    459   Private->Icmp6Token.Status = EFI_NOT_READY;
    460   Ip6->Receive (Ip6, &Private->Icmp6Token);
    461 }
    462 
    463 
    464 /**
    465   Callback function to update the latest ICMP6 error message.
    466 
    467   @param  Event                 The event signalled.
    468   @param  Context               The context passed in using the event notifier.
    469 
    470 **/
    471 VOID
    472 EFIAPI
    473 PxeBcIcmp6ErrorUpdate (
    474   IN EFI_EVENT               Event,
    475   IN VOID                    *Context
    476   )
    477 {
    478   QueueDpc (TPL_CALLBACK, PxeBcIcmp6ErrorDpcHandle, Context);
    479 }
    480 
    481 
    482 /**
    483   This function is to configure a UDPv4 instance for UdpWrite.
    484 
    485   @param[in]       Udp4                 The pointer to EFI_UDP4_PROTOCOL.
    486   @param[in]       StationIp            The pointer to the station address.
    487   @param[in]       SubnetMask           The pointer to the subnet mask.
    488   @param[in]       Gateway              The pointer to the gateway address.
    489   @param[in, out]  SrcPort              The pointer to the source port.
    490   @param[in]       DoNotFragment        If TRUE, fragment is not enabled.
    491                                         Otherwise, fragment is enabled.
    492 
    493   @retval          EFI_SUCCESS          Successfully configured this instance.
    494   @retval          Others               Failed to configure this instance.
    495 
    496 **/
    497 EFI_STATUS
    498 PxeBcConfigUdp4Write (
    499   IN     EFI_UDP4_PROTOCOL  *Udp4,
    500   IN     EFI_IPv4_ADDRESS   *StationIp,
    501   IN     EFI_IPv4_ADDRESS   *SubnetMask,
    502   IN     EFI_IPv4_ADDRESS   *Gateway,
    503   IN OUT UINT16             *SrcPort,
    504   IN     BOOLEAN            DoNotFragment
    505   )
    506 {
    507   EFI_UDP4_CONFIG_DATA  Udp4CfgData;
    508   EFI_STATUS            Status;
    509 
    510   ZeroMem (&Udp4CfgData, sizeof (Udp4CfgData));
    511 
    512   Udp4CfgData.TransmitTimeout    = PXEBC_DEFAULT_LIFETIME;
    513   Udp4CfgData.ReceiveTimeout     = PXEBC_DEFAULT_LIFETIME;
    514   Udp4CfgData.TypeOfService      = DEFAULT_ToS;
    515   Udp4CfgData.TimeToLive         = DEFAULT_TTL;
    516   Udp4CfgData.AllowDuplicatePort = TRUE;
    517   Udp4CfgData.DoNotFragment      = DoNotFragment;
    518 
    519   CopyMem (&Udp4CfgData.StationAddress, StationIp, sizeof (*StationIp));
    520   CopyMem (&Udp4CfgData.SubnetMask, SubnetMask, sizeof (*SubnetMask));
    521 
    522   Udp4CfgData.StationPort = *SrcPort;
    523 
    524   //
    525   // Reset the UDPv4 instance.
    526   //
    527   Udp4->Configure (Udp4, NULL);
    528 
    529   Status = Udp4->Configure (Udp4, &Udp4CfgData);
    530   if (!EFI_ERROR (Status) && !EFI_IP4_EQUAL (Gateway, &mZeroIp4Addr)) {
    531     //
    532     // The basic configuration is OK, need to add the default route entry
    533     //
    534     Status = Udp4->Routes (Udp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, Gateway);
    535     if (EFI_ERROR (Status)) {
    536       Udp4->Configure (Udp4, NULL);
    537     }
    538   }
    539 
    540   if (!EFI_ERROR (Status) && *SrcPort == 0) {
    541     Udp4->GetModeData (Udp4, &Udp4CfgData, NULL, NULL, NULL);
    542     *SrcPort = Udp4CfgData.StationPort;
    543   }
    544 
    545   return Status;
    546 }
    547 
    548 
    549 /**
    550   This function is to configure a UDPv6 instance for UdpWrite.
    551 
    552   @param[in]       Udp6                 The pointer to EFI_UDP6_PROTOCOL.
    553   @param[in]       StationIp            The pointer to the station address.
    554   @param[in, out]  SrcPort              The pointer to the source port.
    555 
    556   @retval          EFI_SUCCESS          Successfully configured this instance.
    557   @retval          Others               Failed to configure this instance.
    558 
    559 **/
    560 EFI_STATUS
    561 PxeBcConfigUdp6Write (
    562   IN     EFI_UDP6_PROTOCOL  *Udp6,
    563   IN     EFI_IPv6_ADDRESS   *StationIp,
    564   IN OUT UINT16             *SrcPort
    565   )
    566 {
    567   EFI_UDP6_CONFIG_DATA  CfgData;
    568   EFI_STATUS            Status;
    569 
    570   ZeroMem (&CfgData, sizeof (EFI_UDP6_CONFIG_DATA));
    571 
    572   CfgData.ReceiveTimeout     = PXEBC_DEFAULT_LIFETIME;
    573   CfgData.TransmitTimeout    = PXEBC_DEFAULT_LIFETIME;
    574   CfgData.HopLimit           = PXEBC_DEFAULT_HOPLIMIT;
    575   CfgData.AllowDuplicatePort = TRUE;
    576   CfgData.StationPort        = *SrcPort;
    577 
    578   CopyMem (&CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));
    579 
    580   //
    581   // Reset the UDPv6 instance.
    582   //
    583   Udp6->Configure (Udp6, NULL);
    584 
    585   Status = Udp6->Configure (Udp6, &CfgData);
    586   if (EFI_ERROR (Status)) {
    587     return Status;
    588   }
    589 
    590   if (!EFI_ERROR (Status) && *SrcPort == 0) {
    591     Udp6->GetModeData (Udp6, &CfgData, NULL, NULL, NULL);
    592     *SrcPort = CfgData.StationPort;
    593   }
    594 
    595   return Status;
    596 }
    597 
    598 
    599 /**
    600   This function is to configure a UDPv4 instance for UdpWrite.
    601 
    602   @param[in]       Udp4                 The pointer to EFI_UDP4_PROTOCOL.
    603   @param[in]       Session              The pointer to the UDP4 session data.
    604   @param[in]       TimeoutEvent         The event for timeout.
    605   @param[in]       Gateway              The pointer to the gateway address.
    606   @param[in]       HeaderSize           An optional field which may be set to the length of a header
    607                                         at HeaderPtr to be prefixed to the data at BufferPtr.
    608   @param[in]       HeaderPtr            If HeaderSize is not NULL, a pointer to a header to be
    609                                         prefixed to the data at BufferPtr.
    610   @param[in]       BufferSize           A pointer to the size of the data at BufferPtr.
    611   @param[in]       BufferPtr            A pointer to the data to be written.
    612 
    613   @retval          EFI_SUCCESS          Successfully send out data using Udp4Write.
    614   @retval          Others               Failed to send out data.
    615 
    616 **/
    617 EFI_STATUS
    618 PxeBcUdp4Write (
    619   IN EFI_UDP4_PROTOCOL       *Udp4,
    620   IN EFI_UDP4_SESSION_DATA   *Session,
    621   IN EFI_EVENT               TimeoutEvent,
    622   IN EFI_IPv4_ADDRESS        *Gateway      OPTIONAL,
    623   IN UINTN                   *HeaderSize   OPTIONAL,
    624   IN VOID                    *HeaderPtr    OPTIONAL,
    625   IN UINTN                   *BufferSize,
    626   IN VOID                    *BufferPtr
    627   )
    628 {
    629   EFI_UDP4_COMPLETION_TOKEN Token;
    630   EFI_UDP4_TRANSMIT_DATA    *TxData;
    631   UINT32                    TxLength;
    632   UINT32                    FragCount;
    633   UINT32                    DataLength;
    634   BOOLEAN                   IsDone;
    635   EFI_STATUS                Status;
    636 
    637   //
    638   // Arrange one fragment buffer for data, and another fragment buffer for header if has.
    639   //
    640   FragCount = (HeaderSize != NULL) ? 2 : 1;
    641   TxLength  = sizeof (EFI_UDP4_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA);
    642   TxData    = (EFI_UDP4_TRANSMIT_DATA *) AllocateZeroPool (TxLength);
    643   if (TxData == NULL) {
    644     return EFI_OUT_OF_RESOURCES;
    645   }
    646 
    647   TxData->FragmentCount                               = FragCount;
    648   TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32) *BufferSize;
    649   TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;
    650   DataLength                                          = (UINT32) *BufferSize;
    651 
    652   if (HeaderSize != NULL) {
    653     TxData->FragmentTable[0].FragmentLength = (UINT32) *HeaderSize;
    654     TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;
    655     DataLength                             += (UINT32) *HeaderSize;
    656   }
    657 
    658   if (Gateway != NULL) {
    659     TxData->GatewayAddress  = Gateway;
    660   }
    661 
    662   TxData->UdpSessionData  = Session;
    663   TxData->DataLength      = DataLength;
    664   Token.Packet.TxData     = TxData;
    665   Token.Status            = EFI_NOT_READY;
    666   IsDone                  = FALSE;
    667 
    668   Status = gBS->CreateEvent (
    669                   EVT_NOTIFY_SIGNAL,
    670                   TPL_NOTIFY,
    671                   PxeBcCommonNotify,
    672                   &IsDone,
    673                   &Token.Event
    674                   );
    675   if (EFI_ERROR (Status)) {
    676     goto ON_EXIT;
    677   }
    678 
    679   Status = Udp4->Transmit (Udp4, &Token);
    680   if (EFI_ERROR (Status)) {
    681     goto ON_EXIT;
    682   }
    683 
    684   //
    685   // Poll the UDPv6 read instance if no packet received and no timeout triggered.
    686   //
    687   while (!IsDone &&
    688          Token.Status == EFI_NOT_READY &&
    689          EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
    690     Udp4->Poll (Udp4);
    691   }
    692 
    693   Status = (Token.Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token.Status;
    694 
    695 ON_EXIT:
    696   if (Token.Event != NULL) {
    697     gBS->CloseEvent (Token.Event);
    698   }
    699   FreePool (TxData);
    700 
    701   return Status;
    702 }
    703 
    704 
    705 /**
    706   This function is to configure a UDPv4 instance for UdpWrite.
    707 
    708   @param[in]       Udp6                 The pointer to EFI_UDP6_PROTOCOL.
    709   @param[in]       Session              The pointer to the UDP6 session data.
    710   @param[in]       TimeoutEvent         The event for timeout.
    711   @param[in]       HeaderSize           An optional field which may be set to the length of a header
    712                                         at HeaderPtr to be prefixed to the data at BufferPtr.
    713   @param[in]       HeaderPtr            If HeaderSize is not NULL, a pointer to a header to be
    714                                         prefixed to the data at BufferPtr.
    715   @param[in]       BufferSize           A pointer to the size of the data at BufferPtr.
    716   @param[in]       BufferPtr            A pointer to the data to be written.
    717 
    718   @retval          EFI_SUCCESS          Successfully sent out data using Udp6Write.
    719   @retval          Others               Failed to send out data.
    720 
    721 **/
    722 EFI_STATUS
    723 PxeBcUdp6Write (
    724   IN EFI_UDP6_PROTOCOL       *Udp6,
    725   IN EFI_UDP6_SESSION_DATA   *Session,
    726   IN EFI_EVENT               TimeoutEvent,
    727   IN UINTN                   *HeaderSize   OPTIONAL,
    728   IN VOID                    *HeaderPtr    OPTIONAL,
    729   IN UINTN                   *BufferSize,
    730   IN VOID                    *BufferPtr
    731   )
    732 {
    733   EFI_UDP6_COMPLETION_TOKEN Token;
    734   EFI_UDP6_TRANSMIT_DATA    *TxData;
    735   UINT32                    TxLength;
    736   UINT32                    FragCount;
    737   UINT32                    DataLength;
    738   BOOLEAN                   IsDone;
    739   EFI_STATUS                Status;
    740 
    741   //
    742   // Arrange one fragment buffer for data, and another fragment buffer for header if has.
    743   //
    744   FragCount = (HeaderSize != NULL) ? 2 : 1;
    745   TxLength  = sizeof (EFI_UDP6_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP6_FRAGMENT_DATA);
    746   TxData    = (EFI_UDP6_TRANSMIT_DATA *) AllocateZeroPool (TxLength);
    747   if (TxData == NULL) {
    748     return EFI_OUT_OF_RESOURCES;
    749   }
    750 
    751   TxData->FragmentCount                               = FragCount;
    752   TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32) *BufferSize;
    753   TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;
    754   DataLength                                          = (UINT32) *BufferSize;
    755 
    756   if (HeaderSize != NULL) {
    757     TxData->FragmentTable[0].FragmentLength = (UINT32) *HeaderSize;
    758     TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;
    759     DataLength                             += (UINT32) *HeaderSize;
    760   }
    761 
    762   TxData->UdpSessionData  = Session;
    763   TxData->DataLength      = DataLength;
    764   Token.Packet.TxData     = TxData;
    765   Token.Status            = EFI_NOT_READY;
    766   IsDone                  = FALSE;
    767 
    768   Status = gBS->CreateEvent (
    769                   EVT_NOTIFY_SIGNAL,
    770                   TPL_NOTIFY,
    771                   PxeBcCommonNotify,
    772                   &IsDone,
    773                   &Token.Event
    774                   );
    775   if (EFI_ERROR (Status)) {
    776     goto ON_EXIT;
    777   }
    778 
    779   Status = Udp6->Transmit (Udp6, &Token);
    780   if (EFI_ERROR (Status)) {
    781     goto ON_EXIT;
    782   }
    783 
    784   //
    785   // Poll the UDPv6 read instance if no packet received and no timeout triggered.
    786   //
    787   while (!IsDone &&
    788          Token.Status == EFI_NOT_READY &&
    789          EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
    790     Udp6->Poll (Udp6);
    791   }
    792 
    793   Status = (Token.Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token.Status;
    794 
    795 ON_EXIT:
    796   if (Token.Event != NULL) {
    797     gBS->CloseEvent (Token.Event);
    798   }
    799   FreePool (TxData);
    800 
    801   return Status;
    802 }
    803 
    804 
    805 /**
    806   Check the received packet using the Ip filter.
    807 
    808   @param[in]  Mode                The pointer to the mode data of PxeBc.
    809   @param[in]  Session             The pointer to the current UDPv4 session.
    810   @param[in]  OpFlags             Operation flag for UdpRead/UdpWrite.
    811 
    812   @retval     TRUE                Passed the Ip filter successfully.
    813   @retval     FALSE               Failed to pass the Ip filter.
    814 
    815 **/
    816 BOOLEAN
    817 PxeBcCheckByIpFilter (
    818   IN EFI_PXE_BASE_CODE_MODE    *Mode,
    819   IN VOID                      *Session,
    820   IN UINT16                    OpFlags
    821   )
    822 {
    823   EFI_IP_ADDRESS               DestinationIp;
    824   UINTN                        Index;
    825 
    826   if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) == 0) {
    827     return TRUE;
    828   }
    829 
    830   if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != 0) {
    831     return TRUE;
    832   }
    833 
    834   //
    835   // Convert the destination address in session data to host order.
    836   //
    837   if (Mode->UsingIpv6) {
    838     CopyMem (
    839       &DestinationIp,
    840       &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress,
    841       sizeof (EFI_IPv6_ADDRESS)
    842       );
    843     NTOHLLL (&DestinationIp.v6);
    844   } else {
    845     ZeroMem (&DestinationIp, sizeof (EFI_IP_ADDRESS));
    846     CopyMem (
    847       &DestinationIp,
    848       &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress,
    849       sizeof (EFI_IPv4_ADDRESS)
    850       );
    851     EFI_NTOHL (DestinationIp);
    852   }
    853 
    854   if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) != 0 &&
    855       (IP4_IS_MULTICAST (DestinationIp.Addr[0]) ||
    856        IP6_IS_MULTICAST (&DestinationIp))) {
    857     return TRUE;
    858   }
    859 
    860   if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0 &&
    861       IP4_IS_LOCAL_BROADCAST (DestinationIp.Addr[0])) {
    862     ASSERT (!Mode->UsingIpv6);
    863     return TRUE;
    864   }
    865 
    866   if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0 &&
    867       (EFI_IP4_EQUAL (&Mode->StationIp.v4, &DestinationIp) ||
    868        EFI_IP6_EQUAL (&Mode->StationIp.v6, &DestinationIp))) {
    869     //
    870     // Matched if the dest address is equal to the station address.
    871     //
    872     return TRUE;
    873   }
    874 
    875   for (Index = 0; Index < Mode->IpFilter.IpCnt; Index++) {
    876     ASSERT (Index < EFI_PXE_BASE_CODE_MAX_IPCNT);
    877     if (EFI_IP4_EQUAL (&Mode->IpFilter.IpList[Index].v4, &DestinationIp) ||
    878         EFI_IP6_EQUAL (&Mode->IpFilter.IpList[Index].v6, &DestinationIp)) {
    879       //
    880       // Matched if the dest address is equal to any of address in the filter list.
    881       //
    882       return TRUE;
    883     }
    884   }
    885 
    886   return FALSE;
    887 }
    888 
    889 
    890 /**
    891   Filter the received packet using the destination Ip.
    892 
    893   @param[in]       Mode           The pointer to the mode data of PxeBc.
    894   @param[in]       Session        The pointer to the current UDPv4 session.
    895   @param[in, out]  DestIp         The pointer to the destination Ip address.
    896   @param[in]       OpFlags        Operation flag for UdpRead/UdpWrite.
    897 
    898   @retval     TRUE                Passed the IPv4 filter successfully.
    899   @retval     FALSE               Failed to pass the IPv4 filter.
    900 
    901 **/
    902 BOOLEAN
    903 PxeBcCheckByDestIp (
    904   IN     EFI_PXE_BASE_CODE_MODE    *Mode,
    905   IN     VOID                      *Session,
    906   IN OUT EFI_IP_ADDRESS            *DestIp,
    907   IN     UINT16                    OpFlags
    908   )
    909 {
    910   if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP) != 0) {
    911     //
    912     // Copy the destination address from the received packet if accept any.
    913     //
    914     if (DestIp != NULL) {
    915       if (Mode->UsingIpv6) {
    916         CopyMem (
    917           DestIp,
    918           &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress,
    919           sizeof (EFI_IPv6_ADDRESS)
    920           );
    921       } else {
    922         ZeroMem (DestIp, sizeof (EFI_IP_ADDRESS));
    923         CopyMem (
    924           DestIp,
    925           &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress,
    926           sizeof (EFI_IPv4_ADDRESS)
    927           );
    928       }
    929 
    930     }
    931     return TRUE;
    932   } else if (DestIp != NULL &&
    933              (EFI_IP4_EQUAL (DestIp, &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress) ||
    934               EFI_IP6_EQUAL (DestIp, &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress))) {
    935     //
    936     // The destination address in the received packet is matched if present.
    937     //
    938     return TRUE;
    939   } else if (EFI_IP4_EQUAL (&Mode->StationIp, &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress) ||
    940              EFI_IP6_EQUAL (&Mode->StationIp, &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress)) {
    941     //
    942     // The destination address in the received packet is equal to the host address.
    943     //
    944     return TRUE;
    945   }
    946 
    947   return FALSE;
    948 }
    949 
    950 
    951 /**
    952   Check the received packet using the destination port.
    953 
    954   @param[in]       Mode           The pointer to the mode data of PxeBc.
    955   @param[in]       Session        The pointer to the current UDPv4 session.
    956   @param[in, out]  DestPort       The pointer to the destination port.
    957   @param[in]       OpFlags        Operation flag for UdpRead/UdpWrite.
    958 
    959   @retval     TRUE                Passed the IPv4 filter successfully.
    960   @retval     FALSE               Failed to pass the IPv4 filter.
    961 
    962 **/
    963 BOOLEAN
    964 PxeBcCheckByDestPort (
    965   IN     EFI_PXE_BASE_CODE_MODE    *Mode,
    966   IN     VOID                      *Session,
    967   IN OUT UINT16                    *DestPort,
    968   IN     UINT16                    OpFlags
    969   )
    970 {
    971   UINT16       Port;
    972 
    973   if (Mode->UsingIpv6) {
    974     Port = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort;
    975   } else {
    976     Port = ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort;
    977   }
    978 
    979   if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) != 0) {
    980     //
    981     // Return the destination port in the received packet if accept any.
    982     //
    983     if (DestPort != NULL) {
    984       *DestPort = Port;
    985     }
    986     return TRUE;
    987   } else if (DestPort != NULL && *DestPort == Port) {
    988     //
    989     // The destination port in the received packet is matched if present.
    990     //
    991     return TRUE;
    992   }
    993 
    994   return FALSE;
    995 }
    996 
    997 
    998 /**
    999   Filter the received packet using the source Ip.
   1000 
   1001   @param[in]       Mode           The pointer to the mode data of PxeBc.
   1002   @param[in]       Session        The pointer to the current UDPv4 session.
   1003   @param[in, out]  SrcIp          The pointer to the source Ip address.
   1004   @param[in]       OpFlags        Operation flag for UdpRead/UdpWrite.
   1005 
   1006   @retval     TRUE                Passed the IPv4 filter successfully.
   1007   @retval     FALSE               Failed to pass the IPv4 filter.
   1008 
   1009 **/
   1010 BOOLEAN
   1011 PxeBcFilterBySrcIp (
   1012   IN     EFI_PXE_BASE_CODE_MODE    *Mode,
   1013   IN     VOID                      *Session,
   1014   IN OUT EFI_IP_ADDRESS            *SrcIp,
   1015   IN     UINT16                    OpFlags
   1016   )
   1017 {
   1018   if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) != 0) {
   1019     //
   1020     // Copy the source address from the received packet if accept any.
   1021     //
   1022     if (SrcIp != NULL) {
   1023       if (Mode->UsingIpv6) {
   1024         CopyMem (
   1025           SrcIp,
   1026           &((EFI_UDP6_SESSION_DATA *)Session)->SourceAddress,
   1027           sizeof (EFI_IPv6_ADDRESS)
   1028           );
   1029       } else {
   1030         ZeroMem (SrcIp, sizeof (EFI_IP_ADDRESS));
   1031         CopyMem (
   1032           SrcIp,
   1033           &((EFI_UDP4_SESSION_DATA *)Session)->SourceAddress,
   1034           sizeof (EFI_IPv4_ADDRESS)
   1035           );
   1036       }
   1037 
   1038     }
   1039     return TRUE;
   1040   } else if (SrcIp != NULL &&
   1041              (EFI_IP4_EQUAL (SrcIp, &((EFI_UDP4_SESSION_DATA *)Session)->SourceAddress) ||
   1042               EFI_IP6_EQUAL (SrcIp, &((EFI_UDP6_SESSION_DATA *)Session)->SourceAddress))) {
   1043     //
   1044     // The source address in the received packet is matched if present.
   1045     //
   1046     return TRUE;
   1047   }
   1048 
   1049   return FALSE;
   1050 }
   1051 
   1052 
   1053 /**
   1054   Filter the received packet using the source port.
   1055 
   1056   @param[in]       Mode           The pointer to the mode data of PxeBc.
   1057   @param[in]       Session        The pointer to the current UDPv4 session.
   1058   @param[in, out]  SrcPort        The pointer to the source port.
   1059   @param[in]       OpFlags        Operation flag for UdpRead/UdpWrite.
   1060 
   1061   @retval     TRUE                Passed the IPv4 filter successfully.
   1062   @retval     FALSE               Failed to pass the IPv4 filter.
   1063 
   1064 **/
   1065 BOOLEAN
   1066 PxeBcFilterBySrcPort (
   1067   IN     EFI_PXE_BASE_CODE_MODE    *Mode,
   1068   IN     VOID                      *Session,
   1069   IN OUT UINT16                    *SrcPort,
   1070   IN     UINT16                    OpFlags
   1071   )
   1072 {
   1073   UINT16       Port;
   1074 
   1075   if (Mode->UsingIpv6) {
   1076     Port = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort;
   1077   } else {
   1078     Port = ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort;
   1079   }
   1080 
   1081   if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) != 0) {
   1082     //
   1083     // Return the source port in the received packet if accept any.
   1084     //
   1085     if (SrcPort != NULL) {
   1086       *SrcPort = Port;
   1087     }
   1088     return TRUE;
   1089   } else if (SrcPort != NULL && *SrcPort == Port) {
   1090     //
   1091     // The source port in the received packet is matched if present.
   1092     //
   1093     return TRUE;
   1094   }
   1095 
   1096   return FALSE;
   1097 }
   1098 
   1099 
   1100 /**
   1101   This function is to receive packet using Udp4Read.
   1102 
   1103   @param[in]       Udp4                 The pointer to EFI_UDP4_PROTOCOL.
   1104   @param[in]       Token                The pointer to EFI_UDP4_COMPLETION_TOKEN.
   1105   @param[in]       Mode                 The pointer to EFI_PXE_BASE_CODE_MODE.
   1106   @param[in]       TimeoutEvent         The event for timeout.
   1107   @param[in]       OpFlags              The UDP operation flags.
   1108   @param[in]       IsDone               The pointer to the IsDone flag.
   1109   @param[out]      IsMatched            The pointer to the IsMatched flag.
   1110   @param[in, out]  DestIp               The pointer to the destination address.
   1111   @param[in, out]  DestPort             The pointer to the destination port.
   1112   @param[in, out]  SrcIp                The pointer to the source address.
   1113   @param[in, out]  SrcPort              The pointer to the source port.
   1114 
   1115   @retval          EFI_SUCCESS          Successfully read the data using Udp4.
   1116   @retval          Others               Failed to send out data.
   1117 
   1118 **/
   1119 EFI_STATUS
   1120 PxeBcUdp4Read (
   1121   IN     EFI_UDP4_PROTOCOL            *Udp4,
   1122   IN     EFI_UDP4_COMPLETION_TOKEN    *Token,
   1123   IN     EFI_PXE_BASE_CODE_MODE       *Mode,
   1124   IN     EFI_EVENT                    TimeoutEvent,
   1125   IN     UINT16                       OpFlags,
   1126   IN     BOOLEAN                      *IsDone,
   1127      OUT BOOLEAN                      *IsMatched,
   1128   IN OUT EFI_IP_ADDRESS               *DestIp      OPTIONAL,
   1129   IN OUT EFI_PXE_BASE_CODE_UDP_PORT   *DestPort    OPTIONAL,
   1130   IN OUT EFI_IP_ADDRESS               *SrcIp       OPTIONAL,
   1131   IN OUT EFI_PXE_BASE_CODE_UDP_PORT   *SrcPort     OPTIONAL
   1132   )
   1133 {
   1134   EFI_UDP4_RECEIVE_DATA     *RxData;
   1135   EFI_UDP4_SESSION_DATA     *Session;
   1136   EFI_STATUS                Status;
   1137 
   1138   Token->Status = EFI_NOT_READY;
   1139   *IsDone       = FALSE;
   1140 
   1141   Status = Udp4->Receive (Udp4, Token);
   1142   if (EFI_ERROR (Status)) {
   1143     return Status;
   1144   }
   1145 
   1146   //
   1147   // Poll the UDPv6 read instance if no packet received and no timeout triggered.
   1148   //
   1149   while (!(*IsDone) &&
   1150          Token->Status == EFI_NOT_READY &&
   1151          EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
   1152     //
   1153     // Poll the token utill reply/ICMPv6 error message received or timeout.
   1154     //
   1155     Udp4->Poll (Udp4);
   1156     if (Token->Status == EFI_ICMP_ERROR ||
   1157         Token->Status == EFI_NETWORK_UNREACHABLE ||
   1158         Token->Status == EFI_HOST_UNREACHABLE ||
   1159         Token->Status == EFI_PROTOCOL_UNREACHABLE ||
   1160         Token->Status == EFI_PORT_UNREACHABLE) {
   1161       break;
   1162     }
   1163   }
   1164 
   1165   Status = (Token->Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token->Status;
   1166 
   1167   if (!EFI_ERROR (Status)) {
   1168     //
   1169     // check whether this packet matches the filters
   1170     //
   1171     RxData    = Token->Packet.RxData;
   1172     Session   = &RxData->UdpSession;
   1173 
   1174     *IsMatched = PxeBcCheckByIpFilter (Mode, Session, OpFlags);
   1175 
   1176     if (*IsMatched) {
   1177       *IsMatched = PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags);
   1178     }
   1179 
   1180     if (*IsMatched) {
   1181       *IsMatched = PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlags);
   1182     }
   1183 
   1184     if (*IsMatched) {
   1185       *IsMatched = PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags);
   1186     }
   1187 
   1188     if (*IsMatched) {
   1189       *IsMatched = PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags);
   1190     }
   1191 
   1192     if (!(*IsMatched)) {
   1193       //
   1194       // Recycle the receiving buffer if not matched.
   1195       //
   1196       gBS->SignalEvent (RxData->RecycleSignal);
   1197     }
   1198   }
   1199 
   1200   return Status;
   1201 }
   1202 
   1203 
   1204 /**
   1205   This function is to receive packets using Udp6Read.
   1206 
   1207   @param[in]       Udp6                 The pointer to EFI_UDP6_PROTOCOL.
   1208   @param[in]       Token                The pointer to EFI_UDP6_COMPLETION_TOKEN.
   1209   @param[in]       Mode                 The pointer to EFI_PXE_BASE_CODE_MODE.
   1210   @param[in]       TimeoutEvent         The event for timeout.
   1211   @param[in]       OpFlags              The UDP operation flags.
   1212   @param[in]       IsDone               The pointer to the IsDone flag.
   1213   @param[out]      IsMatched            The pointer to the IsMatched flag.
   1214   @param[in, out]  DestIp               The pointer to the destination address.
   1215   @param[in, out]  DestPort             The pointer to the destination port.
   1216   @param[in, out]  SrcIp                The pointer to the source address.
   1217   @param[in, out]  SrcPort              The pointer to the source port.
   1218 
   1219   @retval          EFI_SUCCESS          Successfully read data using Udp6.
   1220   @retval          Others               Failed to send out data.
   1221 
   1222 **/
   1223 EFI_STATUS
   1224 PxeBcUdp6Read (
   1225   IN     EFI_UDP6_PROTOCOL            *Udp6,
   1226   IN     EFI_UDP6_COMPLETION_TOKEN    *Token,
   1227   IN     EFI_PXE_BASE_CODE_MODE       *Mode,
   1228   IN     EFI_EVENT                    TimeoutEvent,
   1229   IN     UINT16                       OpFlags,
   1230   IN     BOOLEAN                      *IsDone,
   1231      OUT BOOLEAN                      *IsMatched,
   1232   IN OUT EFI_IP_ADDRESS               *DestIp      OPTIONAL,
   1233   IN OUT EFI_PXE_BASE_CODE_UDP_PORT   *DestPort    OPTIONAL,
   1234   IN OUT EFI_IP_ADDRESS               *SrcIp       OPTIONAL,
   1235   IN OUT EFI_PXE_BASE_CODE_UDP_PORT   *SrcPort     OPTIONAL
   1236   )
   1237 {
   1238   EFI_UDP6_RECEIVE_DATA     *RxData;
   1239   EFI_UDP6_SESSION_DATA     *Session;
   1240   EFI_STATUS                Status;
   1241 
   1242   Token->Status = EFI_NOT_READY;
   1243   *IsDone       = FALSE;
   1244 
   1245   Status = Udp6->Receive (Udp6, Token);
   1246   if (EFI_ERROR (Status)) {
   1247     return Status;
   1248   }
   1249 
   1250   //
   1251   // Poll the UDPv6 read instance if no packet received and no timeout triggered.
   1252   //
   1253   while (!(*IsDone) &&
   1254          Token->Status == EFI_NOT_READY &&
   1255          EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
   1256     //
   1257     // Poll the token utill reply/ICMPv6 error message received or timeout.
   1258     //
   1259     Udp6->Poll (Udp6);
   1260     if (Token->Status == EFI_ICMP_ERROR ||
   1261         Token->Status == EFI_NETWORK_UNREACHABLE ||
   1262         Token->Status == EFI_HOST_UNREACHABLE ||
   1263         Token->Status == EFI_PROTOCOL_UNREACHABLE ||
   1264         Token->Status == EFI_PORT_UNREACHABLE) {
   1265       break;
   1266     }
   1267   }
   1268 
   1269   Status = (Token->Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token->Status;
   1270 
   1271   if (!EFI_ERROR (Status)) {
   1272     //
   1273     // check whether this packet matches the filters
   1274     //
   1275     RxData    = Token->Packet.RxData;
   1276     Session   = &RxData->UdpSession;
   1277 
   1278     *IsMatched = PxeBcCheckByIpFilter (Mode, Session, OpFlags);
   1279 
   1280     if (*IsMatched) {
   1281       *IsMatched = PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags);
   1282     }
   1283 
   1284     if (*IsMatched) {
   1285       *IsMatched = PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlags);
   1286     }
   1287 
   1288     if (*IsMatched) {
   1289       *IsMatched = PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags);
   1290     }
   1291 
   1292     if (*IsMatched) {
   1293       *IsMatched = PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags);
   1294     }
   1295 
   1296     if (!(*IsMatched)) {
   1297       //
   1298       // Recycle the receiving buffer if not matched.
   1299       //
   1300       gBS->SignalEvent (RxData->RecycleSignal);
   1301     }
   1302   }
   1303 
   1304   return Status;
   1305 }
   1306 
   1307 
   1308 /**
   1309   This function is to display the IPv4 address.
   1310 
   1311   @param[in]  Ip        The pointer to the IPv4 address.
   1312 
   1313 **/
   1314 VOID
   1315 PxeBcShowIp4Addr (
   1316   IN EFI_IPv4_ADDRESS   *Ip
   1317   )
   1318 {
   1319   UINTN                 Index;
   1320 
   1321   for (Index = 0; Index < 4; Index++) {
   1322     AsciiPrint ("%d", Ip->Addr[Index]);
   1323     if (Index < 3) {
   1324       AsciiPrint (".");
   1325     }
   1326   }
   1327 }
   1328 
   1329 
   1330 /**
   1331   This function is to display the IPv6 address.
   1332 
   1333   @param[in]  Ip        The pointer to the IPv6 address.
   1334 
   1335 **/
   1336 VOID
   1337 PxeBcShowIp6Addr (
   1338   IN EFI_IPv6_ADDRESS   *Ip
   1339   )
   1340 {
   1341   UINTN                 Index;
   1342 
   1343   for (Index = 0; Index < 16; Index++) {
   1344 
   1345     if (Ip->Addr[Index] != 0) {
   1346       AsciiPrint ("%x", Ip->Addr[Index]);
   1347     }
   1348     Index++;
   1349     if (Index > 15) {
   1350       return;
   1351     }
   1352     if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) {
   1353       AsciiPrint ("0");
   1354     }
   1355     AsciiPrint ("%x", Ip->Addr[Index]);
   1356     if (Index < 15) {
   1357       AsciiPrint (":");
   1358     }
   1359   }
   1360 }
   1361 
   1362 
   1363 /**
   1364   This function is to convert UINTN to ASCII string with the required formatting.
   1365 
   1366   @param[in]  Number         Numeric value to be converted.
   1367   @param[in]  Buffer         The pointer to the buffer for ASCII string.
   1368   @param[in]  Length         The length of the required format.
   1369 
   1370 **/
   1371 VOID
   1372 PxeBcUintnToAscDecWithFormat (
   1373   IN UINTN                       Number,
   1374   IN UINT8                       *Buffer,
   1375   IN INTN                        Length
   1376   )
   1377 {
   1378   UINTN                          Remainder;
   1379 
   1380   while (Length > 0) {
   1381     Length--;
   1382     Remainder      = Number % 10;
   1383     Number        /= 10;
   1384     Buffer[Length] = (UINT8) ('0' + Remainder);
   1385   }
   1386 }
   1387 
   1388 
   1389 /**
   1390   This function is to convert a UINTN to a ASCII string, and return the
   1391   actual length of the buffer.
   1392 
   1393   @param[in]  Number         Numeric value to be converted.
   1394   @param[in]  Buffer         The pointer to the buffer for ASCII string.
   1395   @param[in]  BufferSize     The maxsize of the buffer.
   1396 
   1397   @return     Length         The actual length of the ASCII string.
   1398 
   1399 **/
   1400 UINTN
   1401 PxeBcUintnToAscDec (
   1402   IN UINTN               Number,
   1403   IN UINT8               *Buffer,
   1404   IN UINTN               BufferSize
   1405   )
   1406 {
   1407   UINTN           Index;
   1408   UINTN           Length;
   1409   CHAR8           TempStr[64];
   1410 
   1411   Index           = 63;
   1412   TempStr[Index]  = 0;
   1413 
   1414   do {
   1415     Index--;
   1416     TempStr[Index] = (CHAR8) ('0' + (Number % 10));
   1417     Number         = (UINTN) (Number / 10);
   1418   } while (Number != 0);
   1419 
   1420   AsciiStrCpyS ((CHAR8 *) Buffer, BufferSize, &TempStr[Index]);
   1421 
   1422   Length = AsciiStrLen ((CHAR8 *) Buffer);
   1423 
   1424   return Length;
   1425 }
   1426 
   1427 
   1428 /**
   1429   This function is to convert unicode hex number to a UINT8.
   1430 
   1431   @param[out]  Digit                   The converted UINT8 for output.
   1432   @param[in]   Char                    The unicode hex number to be converted.
   1433 
   1434   @retval      EFI_SUCCESS             Successfully converted the unicode hex.
   1435   @retval      EFI_INVALID_PARAMETER   Failed to convert the unicode hex.
   1436 
   1437 **/
   1438 EFI_STATUS
   1439 PxeBcUniHexToUint8 (
   1440   OUT UINT8                *Digit,
   1441   IN  CHAR16               Char
   1442   )
   1443 {
   1444   if ((Char >= L'0') && (Char <= L'9')) {
   1445     *Digit = (UINT8) (Char - L'0');
   1446     return EFI_SUCCESS;
   1447   }
   1448 
   1449   if ((Char >= L'A') && (Char <= L'F')) {
   1450     *Digit = (UINT8) (Char - L'A' + 0x0A);
   1451     return EFI_SUCCESS;
   1452   }
   1453 
   1454   if ((Char >= L'a') && (Char <= L'f')) {
   1455     *Digit = (UINT8) (Char - L'a' + 0x0A);
   1456     return EFI_SUCCESS;
   1457   }
   1458 
   1459   return EFI_INVALID_PARAMETER;
   1460 }
   1461 
   1462 /**
   1463   Calculate the elapsed time.
   1464 
   1465   @param[in]      Private      The pointer to PXE private data
   1466 
   1467 **/
   1468 VOID
   1469 CalcElapsedTime (
   1470   IN     PXEBC_PRIVATE_DATA     *Private
   1471   )
   1472 {
   1473   EFI_TIME          Time;
   1474   UINT64            CurrentStamp;
   1475   UINT64            ElapsedTimeValue;
   1476 
   1477   //
   1478   // Generate a time stamp of the centiseconds from 1900/1/1, assume 30day/month.
   1479   //
   1480   ZeroMem (&Time, sizeof (EFI_TIME));
   1481   gRT->GetTime (&Time, NULL);
   1482   CurrentStamp = (UINT64)
   1483     (
   1484       ((((((Time.Year - 1900) * 360 +
   1485        (Time.Month - 1)) * 30 +
   1486        (Time.Day - 1)) * 24 + Time.Hour) * 60 +
   1487        Time.Minute) * 60 + Time.Second) * 100
   1488        + DivU64x32(Time.Nanosecond, 10000000)
   1489     );
   1490 
   1491   //
   1492   // Sentinel value of 0 means that this is the first DHCP packet that we are
   1493   // sending and that we need to initialize the value.  First DHCP Solicit
   1494   // gets 0 elapsed-time.  Otherwise, calculate based on StartTime.
   1495   //
   1496   if (Private->ElapsedTime == 0) {
   1497     Private->ElapsedTime = CurrentStamp;
   1498   } else {
   1499     ElapsedTimeValue = CurrentStamp - Private->ElapsedTime;
   1500 
   1501     //
   1502     // If elapsed time cannot fit in two bytes, set it to 0xffff.
   1503     //
   1504     if (ElapsedTimeValue > 0xffff) {
   1505       ElapsedTimeValue = 0xffff;
   1506     }
   1507     //
   1508     // Save the elapsed time
   1509     //
   1510     Private->ElapsedTime = ElapsedTimeValue;
   1511   }
   1512 }
   1513 
   1514