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