Home | History | Annotate | Download | only in DxeNetLib
      1 /** @file
      2   Network library.
      3 
      4 Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>
      5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 **/
     14 
     15 #include <Uefi.h>
     16 
     17 #include <IndustryStandard/SmBios.h>
     18 
     19 #include <Protocol/DriverBinding.h>
     20 #include <Protocol/ServiceBinding.h>
     21 #include <Protocol/SimpleNetwork.h>
     22 #include <Protocol/ManagedNetwork.h>
     23 #include <Protocol/Ip4Config2.h>
     24 #include <Protocol/ComponentName.h>
     25 #include <Protocol/ComponentName2.h>
     26 
     27 #include <Guid/SmBios.h>
     28 
     29 #include <Library/NetLib.h>
     30 #include <Library/BaseLib.h>
     31 #include <Library/DebugLib.h>
     32 #include <Library/BaseMemoryLib.h>
     33 #include <Library/UefiBootServicesTableLib.h>
     34 #include <Library/UefiRuntimeServicesTableLib.h>
     35 #include <Library/MemoryAllocationLib.h>
     36 #include <Library/DevicePathLib.h>
     37 #include <Library/PrintLib.h>
     38 #include <Library/UefiLib.h>
     39 
     40 #define NIC_ITEM_CONFIG_SIZE   sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE
     41 #define DEFAULT_ZERO_START     ((UINTN) ~0)
     42 
     43 //
     44 // All the supported IP4 maskes in host byte order.
     45 //
     46 GLOBAL_REMOVE_IF_UNREFERENCED IP4_ADDR  gIp4AllMasks[IP4_MASK_NUM] = {
     47   0x00000000,
     48   0x80000000,
     49   0xC0000000,
     50   0xE0000000,
     51   0xF0000000,
     52   0xF8000000,
     53   0xFC000000,
     54   0xFE000000,
     55 
     56   0xFF000000,
     57   0xFF800000,
     58   0xFFC00000,
     59   0xFFE00000,
     60   0xFFF00000,
     61   0xFFF80000,
     62   0xFFFC0000,
     63   0xFFFE0000,
     64 
     65   0xFFFF0000,
     66   0xFFFF8000,
     67   0xFFFFC000,
     68   0xFFFFE000,
     69   0xFFFFF000,
     70   0xFFFFF800,
     71   0xFFFFFC00,
     72   0xFFFFFE00,
     73 
     74   0xFFFFFF00,
     75   0xFFFFFF80,
     76   0xFFFFFFC0,
     77   0xFFFFFFE0,
     78   0xFFFFFFF0,
     79   0xFFFFFFF8,
     80   0xFFFFFFFC,
     81   0xFFFFFFFE,
     82   0xFFFFFFFF,
     83 };
     84 
     85 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IPv4_ADDRESS  mZeroIp4Addr = {{0, 0, 0, 0}};
     86 
     87 //
     88 // Any error level digitally larger than mNetDebugLevelMax
     89 // will be silently discarded.
     90 //
     91 GLOBAL_REMOVE_IF_UNREFERENCED UINTN  mNetDebugLevelMax = NETDEBUG_LEVEL_ERROR;
     92 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogPacketSeq  = 0xDEADBEEF;
     93 
     94 //
     95 // You can change mSyslogDstMac mSyslogDstIp and mSyslogSrcIp
     96 // here to direct the syslog packets to the syslog deamon. The
     97 // default is broadcast to both the ethernet and IP.
     98 //
     99 GLOBAL_REMOVE_IF_UNREFERENCED UINT8  mSyslogDstMac[NET_ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
    100 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogDstIp                      = 0xffffffff;
    101 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogSrcIp                      = 0;
    102 
    103 GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mMonthName[] = {
    104   "Jan",
    105   "Feb",
    106   "Mar",
    107   "Apr",
    108   "May",
    109   "Jun",
    110   "Jul",
    111   "Aug",
    112   "Sep",
    113   "Oct",
    114   "Nov",
    115   "Dec"
    116 };
    117 
    118 //
    119 // VLAN device path node template
    120 //
    121 GLOBAL_REMOVE_IF_UNREFERENCED VLAN_DEVICE_PATH mNetVlanDevicePathTemplate = {
    122   {
    123     MESSAGING_DEVICE_PATH,
    124     MSG_VLAN_DP,
    125     {
    126       (UINT8) (sizeof (VLAN_DEVICE_PATH)),
    127       (UINT8) ((sizeof (VLAN_DEVICE_PATH)) >> 8)
    128     }
    129   },
    130   0
    131 };
    132 
    133 /**
    134   Locate the handles that support SNP, then open one of them
    135   to send the syslog packets. The caller isn't required to close
    136   the SNP after use because the SNP is opened by HandleProtocol.
    137 
    138   @return The point to SNP if one is properly openned. Otherwise NULL
    139 
    140 **/
    141 EFI_SIMPLE_NETWORK_PROTOCOL *
    142 SyslogLocateSnp (
    143   VOID
    144   )
    145 {
    146   EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
    147   EFI_STATUS                  Status;
    148   EFI_HANDLE                  *Handles;
    149   UINTN                       HandleCount;
    150   UINTN                       Index;
    151 
    152   //
    153   // Locate the handles which has SNP installed.
    154   //
    155   Handles = NULL;
    156   Status  = gBS->LocateHandleBuffer (
    157                    ByProtocol,
    158                    &gEfiSimpleNetworkProtocolGuid,
    159                    NULL,
    160                    &HandleCount,
    161                    &Handles
    162                    );
    163 
    164   if (EFI_ERROR (Status) || (HandleCount == 0)) {
    165     return NULL;
    166   }
    167 
    168   //
    169   // Try to open one of the ethernet SNP protocol to send packet
    170   //
    171   Snp = NULL;
    172 
    173   for (Index = 0; Index < HandleCount; Index++) {
    174     Status = gBS->HandleProtocol (
    175                     Handles[Index],
    176                     &gEfiSimpleNetworkProtocolGuid,
    177                     (VOID **) &Snp
    178                     );
    179 
    180     if ((Status == EFI_SUCCESS) && (Snp != NULL) &&
    181         (Snp->Mode->IfType == NET_IFTYPE_ETHERNET) &&
    182         (Snp->Mode->MaxPacketSize >= NET_SYSLOG_PACKET_LEN)) {
    183 
    184       break;
    185     }
    186 
    187     Snp = NULL;
    188   }
    189 
    190   FreePool (Handles);
    191   return Snp;
    192 }
    193 
    194 /**
    195   Transmit a syslog packet synchronously through SNP. The Packet
    196   already has the ethernet header prepended. This function should
    197   fill in the source MAC because it will try to locate a SNP each
    198   time it is called to avoid the problem if SNP is unloaded.
    199   This code snip is copied from MNP.
    200 
    201   @param[in] Packet          The Syslog packet
    202   @param[in] Length          The length of the packet
    203 
    204   @retval EFI_DEVICE_ERROR   Failed to locate a usable SNP protocol
    205   @retval EFI_TIMEOUT        Timeout happened to send the packet.
    206   @retval EFI_SUCCESS        Packet is sent.
    207 
    208 **/
    209 EFI_STATUS
    210 SyslogSendPacket (
    211   IN CHAR8                    *Packet,
    212   IN UINT32                   Length
    213   )
    214 {
    215   EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
    216   ETHER_HEAD                  *Ether;
    217   EFI_STATUS                  Status;
    218   EFI_EVENT                   TimeoutEvent;
    219   UINT8                       *TxBuf;
    220 
    221   Snp = SyslogLocateSnp ();
    222 
    223   if (Snp == NULL) {
    224     return EFI_DEVICE_ERROR;
    225   }
    226 
    227   Ether = (ETHER_HEAD *) Packet;
    228   CopyMem (Ether->SrcMac, Snp->Mode->CurrentAddress.Addr, NET_ETHER_ADDR_LEN);
    229 
    230   //
    231   // Start the timeout event.
    232   //
    233   Status = gBS->CreateEvent (
    234                   EVT_TIMER,
    235                   TPL_NOTIFY,
    236                   NULL,
    237                   NULL,
    238                   &TimeoutEvent
    239                   );
    240 
    241   if (EFI_ERROR (Status)) {
    242     return Status;
    243   }
    244 
    245   Status = gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);
    246 
    247   if (EFI_ERROR (Status)) {
    248     goto ON_EXIT;
    249   }
    250 
    251   for (;;) {
    252     //
    253     // Transmit the packet through SNP.
    254     //
    255     Status = Snp->Transmit (Snp, 0, Length, Packet, NULL, NULL, NULL);
    256 
    257     if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {
    258       Status = EFI_DEVICE_ERROR;
    259       break;
    260     }
    261 
    262     //
    263     // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
    264     // if Status is EFI_NOT_READY, the transmit engine of the network
    265     // interface is busy. Both need to sync SNP.
    266     //
    267     TxBuf = NULL;
    268 
    269     do {
    270       //
    271       // Get the recycled transmit buffer status.
    272       //
    273       Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf);
    274 
    275       if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
    276         Status = EFI_TIMEOUT;
    277         break;
    278       }
    279 
    280     } while (TxBuf == NULL);
    281 
    282     if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {
    283       break;
    284     }
    285 
    286     //
    287     // Status is EFI_NOT_READY. Restart the timer event and
    288     // call Snp->Transmit again.
    289     //
    290     gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);
    291   }
    292 
    293   gBS->SetTimer (TimeoutEvent, TimerCancel, 0);
    294 
    295 ON_EXIT:
    296   gBS->CloseEvent (TimeoutEvent);
    297   return Status;
    298 }
    299 
    300 /**
    301   Build a syslog packet, including the Ethernet/Ip/Udp headers
    302   and user's message.
    303 
    304   @param[in]  Level     Syslog severity level
    305   @param[in]  Module    The module that generates the log
    306   @param[in]  File      The file that contains the current log
    307   @param[in]  Line      The line of code in the File that contains the current log
    308   @param[in]  Message   The log message
    309   @param[in]  BufLen    The lenght of the Buf
    310   @param[out] Buf       The buffer to put the packet data
    311 
    312   @return The length of the syslog packet built.
    313 
    314 **/
    315 UINT32
    316 SyslogBuildPacket (
    317   IN  UINT32                Level,
    318   IN  UINT8                 *Module,
    319   IN  UINT8                 *File,
    320   IN  UINT32                Line,
    321   IN  UINT8                 *Message,
    322   IN  UINT32                BufLen,
    323   OUT CHAR8                 *Buf
    324   )
    325 {
    326   ETHER_HEAD                *Ether;
    327   IP4_HEAD                  *Ip4;
    328   EFI_UDP_HEADER            *Udp4;
    329   EFI_TIME                  Time;
    330   UINT32                    Pri;
    331   UINT32                    Len;
    332 
    333   //
    334   // Fill in the Ethernet header. Leave alone the source MAC.
    335   // SyslogSendPacket will fill in the address for us.
    336   //
    337   Ether = (ETHER_HEAD *) Buf;
    338   CopyMem (Ether->DstMac, mSyslogDstMac, NET_ETHER_ADDR_LEN);
    339   ZeroMem (Ether->SrcMac, NET_ETHER_ADDR_LEN);
    340 
    341   Ether->EtherType = HTONS (0x0800);    // IPv4 protocol
    342 
    343   Buf             += sizeof (ETHER_HEAD);
    344   BufLen          -= sizeof (ETHER_HEAD);
    345 
    346   //
    347   // Fill in the IP header
    348   //
    349   Ip4              = (IP4_HEAD *) Buf;
    350   Ip4->HeadLen     = 5;
    351   Ip4->Ver         = 4;
    352   Ip4->Tos         = 0;
    353   Ip4->TotalLen    = 0;
    354   Ip4->Id          = (UINT16) mSyslogPacketSeq;
    355   Ip4->Fragment    = 0;
    356   Ip4->Ttl         = 16;
    357   Ip4->Protocol    = 0x11;
    358   Ip4->Checksum    = 0;
    359   Ip4->Src         = mSyslogSrcIp;
    360   Ip4->Dst         = mSyslogDstIp;
    361 
    362   Buf             += sizeof (IP4_HEAD);
    363   BufLen          -= sizeof (IP4_HEAD);
    364 
    365   //
    366   // Fill in the UDP header, Udp checksum is optional. Leave it zero.
    367   //
    368   Udp4             = (EFI_UDP_HEADER *) Buf;
    369   Udp4->SrcPort    = HTONS (514);
    370   Udp4->DstPort    = HTONS (514);
    371   Udp4->Length     = 0;
    372   Udp4->Checksum   = 0;
    373 
    374   Buf             += sizeof (EFI_UDP_HEADER);
    375   BufLen          -= sizeof (EFI_UDP_HEADER);
    376 
    377   //
    378   // Build the syslog message body with <PRI> Timestamp  machine module Message
    379   //
    380   Pri = ((NET_SYSLOG_FACILITY & 31) << 3) | (Level & 7);
    381   gRT->GetTime (&Time, NULL);
    382   ASSERT ((Time.Month <= 12) && (Time.Month >= 1));
    383 
    384   //
    385   // Use %a to format the ASCII strings, %s to format UNICODE strings
    386   //
    387   Len  = 0;
    388   Len += (UINT32) AsciiSPrint (
    389                     Buf,
    390                     BufLen,
    391                     "<%d> %a %d %d:%d:%d ",
    392                     Pri,
    393                     mMonthName [Time.Month-1],
    394                     Time.Day,
    395                     Time.Hour,
    396                     Time.Minute,
    397                     Time.Second
    398                     );
    399   Len--;
    400 
    401   Len += (UINT32) AsciiSPrint (
    402                     Buf + Len,
    403                     BufLen - Len,
    404                     "Tiano %a: %a (Line: %d File: %a)",
    405                     Module,
    406                     Message,
    407                     Line,
    408                     File
    409                     );
    410   Len--;
    411 
    412   //
    413   // OK, patch the IP length/checksum and UDP length fields.
    414   //
    415   Len           += sizeof (EFI_UDP_HEADER);
    416   Udp4->Length   = HTONS ((UINT16) Len);
    417 
    418   Len           += sizeof (IP4_HEAD);
    419   Ip4->TotalLen  = HTONS ((UINT16) Len);
    420   Ip4->Checksum  = (UINT16) (~NetblockChecksum ((UINT8 *) Ip4, sizeof (IP4_HEAD)));
    421 
    422   return Len + sizeof (ETHER_HEAD);
    423 }
    424 
    425 /**
    426   Allocate a buffer, then format the message to it. This is a
    427   help function for the NET_DEBUG_XXX macros. The PrintArg of
    428   these macros treats the variable length print parameters as a
    429   single parameter, and pass it to the NetDebugASPrint. For
    430   example, NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name))
    431   if extracted to:
    432 
    433          NetDebugOutput (
    434            NETDEBUG_LEVEL_TRACE,
    435            "Tcp",
    436            __FILE__,
    437            __LINE__,
    438            NetDebugASPrint ("State transit to %a\n", Name)
    439          )
    440 
    441   @param Format  The ASCII format string.
    442   @param ...     The variable length parameter whose format is determined
    443                  by the Format string.
    444 
    445   @return        The buffer containing the formatted message,
    446                  or NULL if failed to allocate memory.
    447 
    448 **/
    449 CHAR8 *
    450 EFIAPI
    451 NetDebugASPrint (
    452   IN CHAR8                  *Format,
    453   ...
    454   )
    455 {
    456   VA_LIST                   Marker;
    457   CHAR8                     *Buf;
    458 
    459   Buf = (CHAR8 *) AllocatePool (NET_DEBUG_MSG_LEN);
    460 
    461   if (Buf == NULL) {
    462     return NULL;
    463   }
    464 
    465   VA_START (Marker, Format);
    466   AsciiVSPrint (Buf, NET_DEBUG_MSG_LEN, Format, Marker);
    467   VA_END (Marker);
    468 
    469   return Buf;
    470 }
    471 
    472 /**
    473   Builds an UDP4 syslog packet and send it using SNP.
    474 
    475   This function will locate a instance of SNP then send the message through it.
    476   Because it isn't open the SNP BY_DRIVER, apply caution when using it.
    477 
    478   @param Level    The severity level of the message.
    479   @param Module   The Moudle that generates the log.
    480   @param File     The file that contains the log.
    481   @param Line     The exact line that contains the log.
    482   @param Message  The user message to log.
    483 
    484   @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
    485   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory for the packet
    486   @retval EFI_SUCCESS           The log is discard because that it is more verbose
    487                                 than the mNetDebugLevelMax. Or, it has been sent out.
    488 **/
    489 EFI_STATUS
    490 EFIAPI
    491 NetDebugOutput (
    492   IN UINT32                    Level,
    493   IN UINT8                     *Module,
    494   IN UINT8                     *File,
    495   IN UINT32                    Line,
    496   IN UINT8                     *Message
    497   )
    498 {
    499   CHAR8                        *Packet;
    500   UINT32                       Len;
    501   EFI_STATUS                   Status;
    502 
    503   //
    504   // Check whether the message should be sent out
    505   //
    506   if (Message == NULL) {
    507     return EFI_INVALID_PARAMETER;
    508   }
    509 
    510   if (Level > mNetDebugLevelMax) {
    511     Status = EFI_SUCCESS;
    512     goto ON_EXIT;
    513   }
    514 
    515   //
    516   // Allocate a maxium of 1024 bytes, the caller should ensure
    517   // that the message plus the ethernet/ip/udp header is shorter
    518   // than this
    519   //
    520   Packet = (CHAR8 *) AllocatePool (NET_SYSLOG_PACKET_LEN);
    521 
    522   if (Packet == NULL) {
    523     Status = EFI_OUT_OF_RESOURCES;
    524     goto ON_EXIT;
    525   }
    526 
    527   //
    528   // Build the message: Ethernet header + IP header + Udp Header + user data
    529   //
    530   Len = SyslogBuildPacket (
    531           Level,
    532           Module,
    533           File,
    534           Line,
    535           Message,
    536           NET_SYSLOG_PACKET_LEN,
    537           Packet
    538           );
    539 
    540   mSyslogPacketSeq++;
    541   Status = SyslogSendPacket (Packet, Len);
    542   FreePool (Packet);
    543 
    544 ON_EXIT:
    545   FreePool (Message);
    546   return Status;
    547 }
    548 /**
    549   Return the length of the mask.
    550 
    551   Return the length of the mask, the correct value is from 0 to 32.
    552   If the mask is invalid, return the invalid length 33, which is IP4_MASK_NUM.
    553   NetMask is in the host byte order.
    554 
    555   @param[in]  NetMask              The netmask to get the length from.
    556 
    557   @return The length of the netmask, IP4_MASK_NUM if the mask is invalid.
    558 
    559 **/
    560 INTN
    561 EFIAPI
    562 NetGetMaskLength (
    563   IN IP4_ADDR               NetMask
    564   )
    565 {
    566   INTN                      Index;
    567 
    568   for (Index = 0; Index <= IP4_MASK_MAX; Index++) {
    569     if (NetMask == gIp4AllMasks[Index]) {
    570       break;
    571     }
    572   }
    573 
    574   return Index;
    575 }
    576 
    577 
    578 
    579 /**
    580   Return the class of the IP address, such as class A, B, C.
    581   Addr is in host byte order.
    582 
    583   [ATTENTION]
    584   Classful addressing (IP class A/B/C) has been deprecated according to RFC4632.
    585   Caller of this function could only check the returned value against
    586   IP4_ADDR_CLASSD (multicast) or IP4_ADDR_CLASSE (reserved) now.
    587 
    588   The address of class A  starts with 0.
    589   If the address belong to class A, return IP4_ADDR_CLASSA.
    590   The address of class B  starts with 10.
    591   If the address belong to class B, return IP4_ADDR_CLASSB.
    592   The address of class C  starts with 110.
    593   If the address belong to class C, return IP4_ADDR_CLASSC.
    594   The address of class D  starts with 1110.
    595   If the address belong to class D, return IP4_ADDR_CLASSD.
    596   The address of class E  starts with 1111.
    597   If the address belong to class E, return IP4_ADDR_CLASSE.
    598 
    599 
    600   @param[in]   Addr                  The address to get the class from.
    601 
    602   @return IP address class, such as IP4_ADDR_CLASSA.
    603 
    604 **/
    605 INTN
    606 EFIAPI
    607 NetGetIpClass (
    608   IN IP4_ADDR               Addr
    609   )
    610 {
    611   UINT8                     ByteOne;
    612 
    613   ByteOne = (UINT8) (Addr >> 24);
    614 
    615   if ((ByteOne & 0x80) == 0) {
    616     return IP4_ADDR_CLASSA;
    617 
    618   } else if ((ByteOne & 0xC0) == 0x80) {
    619     return IP4_ADDR_CLASSB;
    620 
    621   } else if ((ByteOne & 0xE0) == 0xC0) {
    622     return IP4_ADDR_CLASSC;
    623 
    624   } else if ((ByteOne & 0xF0) == 0xE0) {
    625     return IP4_ADDR_CLASSD;
    626 
    627   } else {
    628     return IP4_ADDR_CLASSE;
    629 
    630   }
    631 }
    632 
    633 
    634 /**
    635   Check whether the IP is a valid unicast address according to
    636   the netmask.
    637 
    638   ASSERT if NetMask is zero.
    639 
    640   If all bits of the host address of IP are 0 or 1, IP is also not a valid unicast address.
    641 
    642   @param[in]  Ip                    The IP to check against.
    643   @param[in]  NetMask               The mask of the IP.
    644 
    645   @return TRUE if IP is a valid unicast address on the network, otherwise FALSE.
    646 
    647 **/
    648 BOOLEAN
    649 EFIAPI
    650 NetIp4IsUnicast (
    651   IN IP4_ADDR               Ip,
    652   IN IP4_ADDR               NetMask
    653   )
    654 {
    655   ASSERT (NetMask != 0);
    656 
    657   if (Ip == 0 || IP4_IS_LOCAL_BROADCAST (Ip)) {
    658     return FALSE;
    659   }
    660 
    661   if (((Ip &~NetMask) == ~NetMask) || ((Ip &~NetMask) == 0)) {
    662     return FALSE;
    663   }
    664 
    665   return TRUE;
    666 }
    667 
    668 /**
    669   Check whether the incoming IPv6 address is a valid unicast address.
    670 
    671   If the address is a multicast address has binary 0xFF at the start, it is not
    672   a valid unicast address. If the address is unspecified ::, it is not a valid
    673   unicast address to be assigned to any node. If the address is loopback address
    674   ::1, it is also not a valid unicast address to be assigned to any physical
    675   interface.
    676 
    677   @param[in]  Ip6                   The IPv6 address to check against.
    678 
    679   @return TRUE if Ip6 is a valid unicast address on the network, otherwise FALSE.
    680 
    681 **/
    682 BOOLEAN
    683 EFIAPI
    684 NetIp6IsValidUnicast (
    685   IN EFI_IPv6_ADDRESS       *Ip6
    686   )
    687 {
    688   UINT8 Byte;
    689   UINT8 Index;
    690 
    691   if (Ip6->Addr[0] == 0xFF) {
    692     return FALSE;
    693   }
    694 
    695   for (Index = 0; Index < 15; Index++) {
    696     if (Ip6->Addr[Index] != 0) {
    697       return TRUE;
    698     }
    699   }
    700 
    701   Byte = Ip6->Addr[Index];
    702 
    703   if (Byte == 0x0 || Byte == 0x1) {
    704     return FALSE;
    705   }
    706 
    707   return TRUE;
    708 }
    709 
    710 /**
    711   Check whether the incoming Ipv6 address is the unspecified address or not.
    712 
    713   @param[in] Ip6   - Ip6 address, in network order.
    714 
    715   @retval TRUE     - Yes, unspecified
    716   @retval FALSE    - No
    717 
    718 **/
    719 BOOLEAN
    720 EFIAPI
    721 NetIp6IsUnspecifiedAddr (
    722   IN EFI_IPv6_ADDRESS       *Ip6
    723   )
    724 {
    725   UINT8 Index;
    726 
    727   for (Index = 0; Index < 16; Index++) {
    728     if (Ip6->Addr[Index] != 0) {
    729       return FALSE;
    730     }
    731   }
    732 
    733   return TRUE;
    734 }
    735 
    736 /**
    737   Check whether the incoming Ipv6 address is a link-local address.
    738 
    739   @param[in] Ip6   - Ip6 address, in network order.
    740 
    741   @retval TRUE  - Yes, link-local address
    742   @retval FALSE - No
    743 
    744 **/
    745 BOOLEAN
    746 EFIAPI
    747 NetIp6IsLinkLocalAddr (
    748   IN EFI_IPv6_ADDRESS *Ip6
    749   )
    750 {
    751   UINT8 Index;
    752 
    753   ASSERT (Ip6 != NULL);
    754 
    755   if (Ip6->Addr[0] != 0xFE) {
    756     return FALSE;
    757   }
    758 
    759   if (Ip6->Addr[1] != 0x80) {
    760     return FALSE;
    761   }
    762 
    763   for (Index = 2; Index < 8; Index++) {
    764     if (Ip6->Addr[Index] != 0) {
    765       return FALSE;
    766     }
    767   }
    768 
    769   return TRUE;
    770 }
    771 
    772 /**
    773   Check whether the Ipv6 address1 and address2 are on the connected network.
    774 
    775   @param[in] Ip1          - Ip6 address1, in network order.
    776   @param[in] Ip2          - Ip6 address2, in network order.
    777   @param[in] PrefixLength - The prefix length of the checking net.
    778 
    779   @retval TRUE            - Yes, connected.
    780   @retval FALSE           - No.
    781 
    782 **/
    783 BOOLEAN
    784 EFIAPI
    785 NetIp6IsNetEqual (
    786   EFI_IPv6_ADDRESS *Ip1,
    787   EFI_IPv6_ADDRESS *Ip2,
    788   UINT8            PrefixLength
    789   )
    790 {
    791   UINT8 Byte;
    792   UINT8 Bit;
    793   UINT8 Mask;
    794 
    795   ASSERT ((Ip1 != NULL) && (Ip2 != NULL) && (PrefixLength <= IP6_PREFIX_MAX));
    796 
    797   if (PrefixLength == 0) {
    798     return TRUE;
    799   }
    800 
    801   Byte = (UINT8) (PrefixLength / 8);
    802   Bit  = (UINT8) (PrefixLength % 8);
    803 
    804   if (CompareMem (Ip1, Ip2, Byte) != 0) {
    805     return FALSE;
    806   }
    807 
    808   if (Bit > 0) {
    809     Mask = (UINT8) (0xFF << (8 - Bit));
    810 
    811     ASSERT (Byte < 16);
    812     if ((Ip1->Addr[Byte] & Mask) != (Ip2->Addr[Byte] & Mask)) {
    813       return FALSE;
    814     }
    815   }
    816 
    817   return TRUE;
    818 }
    819 
    820 
    821 /**
    822   Switches the endianess of an IPv6 address
    823 
    824   This function swaps the bytes in a 128-bit IPv6 address to switch the value
    825   from little endian to big endian or vice versa. The byte swapped value is
    826   returned.
    827 
    828   @param  Ip6 Points to an IPv6 address
    829 
    830   @return The byte swapped IPv6 address.
    831 
    832 **/
    833 EFI_IPv6_ADDRESS *
    834 EFIAPI
    835 Ip6Swap128 (
    836   EFI_IPv6_ADDRESS *Ip6
    837   )
    838 {
    839   UINT64 High;
    840   UINT64 Low;
    841 
    842   CopyMem (&High, Ip6, sizeof (UINT64));
    843   CopyMem (&Low, &Ip6->Addr[8], sizeof (UINT64));
    844 
    845   High = SwapBytes64 (High);
    846   Low  = SwapBytes64 (Low);
    847 
    848   CopyMem (Ip6, &Low, sizeof (UINT64));
    849   CopyMem (&Ip6->Addr[8], &High, sizeof (UINT64));
    850 
    851   return Ip6;
    852 }
    853 
    854 /**
    855   Initialize a random seed using current time and monotonic count.
    856 
    857   Get current time and monotonic count first. Then initialize a random seed
    858   based on some basic mathematics operation on the hour, day, minute, second,
    859   nanosecond and year of the current time and the monotonic count value.
    860 
    861   @return The random seed initialized with current time.
    862 
    863 **/
    864 UINT32
    865 EFIAPI
    866 NetRandomInitSeed (
    867   VOID
    868   )
    869 {
    870   EFI_TIME                  Time;
    871   UINT32                    Seed;
    872   UINT64                    MonotonicCount;
    873 
    874   gRT->GetTime (&Time, NULL);
    875   Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second);
    876   Seed ^= Time.Nanosecond;
    877   Seed ^= Time.Year << 7;
    878 
    879   gBS->GetNextMonotonicCount (&MonotonicCount);
    880   Seed += (UINT32) MonotonicCount;
    881 
    882   return Seed;
    883 }
    884 
    885 
    886 /**
    887   Extract a UINT32 from a byte stream.
    888 
    889   Copy a UINT32 from a byte stream, then converts it from Network
    890   byte order to host byte order. Use this function to avoid alignment error.
    891 
    892   @param[in]  Buf                 The buffer to extract the UINT32.
    893 
    894   @return The UINT32 extracted.
    895 
    896 **/
    897 UINT32
    898 EFIAPI
    899 NetGetUint32 (
    900   IN UINT8                  *Buf
    901   )
    902 {
    903   UINT32                    Value;
    904 
    905   CopyMem (&Value, Buf, sizeof (UINT32));
    906   return NTOHL (Value);
    907 }
    908 
    909 
    910 /**
    911   Put a UINT32 to the byte stream in network byte order.
    912 
    913   Converts a UINT32 from host byte order to network byte order. Then copy it to the
    914   byte stream.
    915 
    916   @param[in, out]  Buf          The buffer to put the UINT32.
    917   @param[in]       Data         The data to be converted and put into the byte stream.
    918 
    919 **/
    920 VOID
    921 EFIAPI
    922 NetPutUint32 (
    923   IN OUT UINT8                 *Buf,
    924   IN     UINT32                Data
    925   )
    926 {
    927   Data = HTONL (Data);
    928   CopyMem (Buf, &Data, sizeof (UINT32));
    929 }
    930 
    931 
    932 /**
    933   Remove the first node entry on the list, and return the removed node entry.
    934 
    935   Removes the first node Entry from a doubly linked list. It is up to the caller of
    936   this function to release the memory used by the first node if that is required. On
    937   exit, the removed node is returned.
    938 
    939   If Head is NULL, then ASSERT().
    940   If Head was not initialized, then ASSERT().
    941   If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
    942   linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
    943   then ASSERT().
    944 
    945   @param[in, out]  Head                  The list header.
    946 
    947   @return The first node entry that is removed from the list, NULL if the list is empty.
    948 
    949 **/
    950 LIST_ENTRY *
    951 EFIAPI
    952 NetListRemoveHead (
    953   IN OUT LIST_ENTRY            *Head
    954   )
    955 {
    956   LIST_ENTRY            *First;
    957 
    958   ASSERT (Head != NULL);
    959 
    960   if (IsListEmpty (Head)) {
    961     return NULL;
    962   }
    963 
    964   First                         = Head->ForwardLink;
    965   Head->ForwardLink             = First->ForwardLink;
    966   First->ForwardLink->BackLink  = Head;
    967 
    968   DEBUG_CODE (
    969     First->ForwardLink  = (LIST_ENTRY *) NULL;
    970     First->BackLink     = (LIST_ENTRY *) NULL;
    971   );
    972 
    973   return First;
    974 }
    975 
    976 
    977 /**
    978   Remove the last node entry on the list and and return the removed node entry.
    979 
    980   Removes the last node entry from a doubly linked list. It is up to the caller of
    981   this function to release the memory used by the first node if that is required. On
    982   exit, the removed node is returned.
    983 
    984   If Head is NULL, then ASSERT().
    985   If Head was not initialized, then ASSERT().
    986   If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
    987   linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
    988   then ASSERT().
    989 
    990   @param[in, out]  Head                  The list head.
    991 
    992   @return The last node entry that is removed from the list, NULL if the list is empty.
    993 
    994 **/
    995 LIST_ENTRY *
    996 EFIAPI
    997 NetListRemoveTail (
    998   IN OUT LIST_ENTRY            *Head
    999   )
   1000 {
   1001   LIST_ENTRY            *Last;
   1002 
   1003   ASSERT (Head != NULL);
   1004 
   1005   if (IsListEmpty (Head)) {
   1006     return NULL;
   1007   }
   1008 
   1009   Last                        = Head->BackLink;
   1010   Head->BackLink              = Last->BackLink;
   1011   Last->BackLink->ForwardLink = Head;
   1012 
   1013   DEBUG_CODE (
   1014     Last->ForwardLink = (LIST_ENTRY *) NULL;
   1015     Last->BackLink    = (LIST_ENTRY *) NULL;
   1016   );
   1017 
   1018   return Last;
   1019 }
   1020 
   1021 
   1022 /**
   1023   Insert a new node entry after a designated node entry of a doubly linked list.
   1024 
   1025   Inserts a new node entry donated by NewEntry after the node entry donated by PrevEntry
   1026   of the doubly linked list.
   1027 
   1028   @param[in, out]  PrevEntry             The previous entry to insert after.
   1029   @param[in, out]  NewEntry              The new entry to insert.
   1030 
   1031 **/
   1032 VOID
   1033 EFIAPI
   1034 NetListInsertAfter (
   1035   IN OUT LIST_ENTRY         *PrevEntry,
   1036   IN OUT LIST_ENTRY         *NewEntry
   1037   )
   1038 {
   1039   NewEntry->BackLink                = PrevEntry;
   1040   NewEntry->ForwardLink             = PrevEntry->ForwardLink;
   1041   PrevEntry->ForwardLink->BackLink  = NewEntry;
   1042   PrevEntry->ForwardLink            = NewEntry;
   1043 }
   1044 
   1045 
   1046 /**
   1047   Insert a new node entry before a designated node entry of a doubly linked list.
   1048 
   1049   Inserts a new node entry donated by NewEntry after the node entry donated by PostEntry
   1050   of the doubly linked list.
   1051 
   1052   @param[in, out]  PostEntry             The entry to insert before.
   1053   @param[in, out]  NewEntry              The new entry to insert.
   1054 
   1055 **/
   1056 VOID
   1057 EFIAPI
   1058 NetListInsertBefore (
   1059   IN OUT LIST_ENTRY     *PostEntry,
   1060   IN OUT LIST_ENTRY     *NewEntry
   1061   )
   1062 {
   1063   NewEntry->ForwardLink             = PostEntry;
   1064   NewEntry->BackLink                = PostEntry->BackLink;
   1065   PostEntry->BackLink->ForwardLink  = NewEntry;
   1066   PostEntry->BackLink               = NewEntry;
   1067 }
   1068 
   1069 /**
   1070   Safe destroy nodes in a linked list, and return the length of the list after all possible operations finished.
   1071 
   1072   Destroy network child instance list by list traversals is not safe due to graph dependencies between nodes.
   1073   This function performs a safe traversal to destroy these nodes by checking to see if the node being destroyed
   1074   has been removed from the list or not.
   1075   If it has been removed, then restart the traversal from the head.
   1076   If it hasn't been removed, then continue with the next node directly.
   1077   This function will end the iterate and return the CallBack's last return value if error happens,
   1078   or retrun EFI_SUCCESS if 2 complete passes are made with no changes in the number of children in the list.
   1079 
   1080   @param[in]    List             The head of the list.
   1081   @param[in]    CallBack         Pointer to the callback function to destroy one node in the list.
   1082   @param[in]    Context          Pointer to the callback function's context: corresponds to the
   1083                                  parameter Context in NET_DESTROY_LINK_LIST_CALLBACK.
   1084   @param[out]   ListLength       The length of the link list if the function returns successfully.
   1085 
   1086   @retval EFI_SUCCESS            Two complete passes are made with no changes in the number of children.
   1087   @retval EFI_INVALID_PARAMETER  The input parameter is invalid.
   1088   @retval Others                 Return the CallBack's last return value.
   1089 
   1090 **/
   1091 EFI_STATUS
   1092 EFIAPI
   1093 NetDestroyLinkList (
   1094   IN   LIST_ENTRY                       *List,
   1095   IN   NET_DESTROY_LINK_LIST_CALLBACK   CallBack,
   1096   IN   VOID                             *Context,    OPTIONAL
   1097   OUT  UINTN                            *ListLength  OPTIONAL
   1098   )
   1099 {
   1100   UINTN                         PreviousLength;
   1101   LIST_ENTRY                    *Entry;
   1102   LIST_ENTRY                    *Ptr;
   1103   UINTN                         Length;
   1104   EFI_STATUS                    Status;
   1105 
   1106   if (List == NULL || CallBack == NULL) {
   1107     return EFI_INVALID_PARAMETER;
   1108   }
   1109 
   1110   Length = 0;
   1111   do {
   1112     PreviousLength = Length;
   1113     Entry = GetFirstNode (List);
   1114     while (!IsNull (List, Entry)) {
   1115       Status = CallBack (Entry, Context);
   1116       if (EFI_ERROR (Status)) {
   1117         return Status;
   1118       }
   1119       //
   1120       // Walk through the list to see whether the Entry has been removed or not.
   1121       // If the Entry still exists, just try to destroy the next one.
   1122       // If not, go back to the start point to iterate the list again.
   1123       //
   1124       for (Ptr = List->ForwardLink; Ptr != List; Ptr = Ptr->ForwardLink) {
   1125         if (Ptr == Entry) {
   1126           break;
   1127         }
   1128       }
   1129       if (Ptr == Entry) {
   1130         Entry = GetNextNode (List, Entry);
   1131       } else {
   1132         Entry = GetFirstNode (List);
   1133       }
   1134     }
   1135     for (Length = 0, Ptr = List->ForwardLink; Ptr != List; Length++, Ptr = Ptr->ForwardLink);
   1136   } while (Length != PreviousLength);
   1137 
   1138   if (ListLength != NULL) {
   1139     *ListLength = Length;
   1140   }
   1141   return EFI_SUCCESS;
   1142 }
   1143 
   1144 /**
   1145   This function checks the input Handle to see if it's one of these handles in ChildHandleBuffer.
   1146 
   1147   @param[in]  Handle             Handle to be checked.
   1148   @param[in]  NumberOfChildren   Number of Handles in ChildHandleBuffer.
   1149   @param[in]  ChildHandleBuffer  An array of child handles to be freed. May be NULL
   1150                                  if NumberOfChildren is 0.
   1151 
   1152   @retval TRUE                   Found the input Handle in ChildHandleBuffer.
   1153   @retval FALSE                  Can't find the input Handle in ChildHandleBuffer.
   1154 
   1155 **/
   1156 BOOLEAN
   1157 EFIAPI
   1158 NetIsInHandleBuffer (
   1159   IN  EFI_HANDLE          Handle,
   1160   IN  UINTN               NumberOfChildren,
   1161   IN  EFI_HANDLE          *ChildHandleBuffer OPTIONAL
   1162   )
   1163 {
   1164   UINTN     Index;
   1165 
   1166   if (NumberOfChildren == 0 || ChildHandleBuffer == NULL) {
   1167     return FALSE;
   1168   }
   1169 
   1170   for (Index = 0; Index < NumberOfChildren; Index++) {
   1171     if (Handle == ChildHandleBuffer[Index]) {
   1172       return TRUE;
   1173     }
   1174   }
   1175 
   1176   return FALSE;
   1177 }
   1178 
   1179 
   1180 /**
   1181   Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.
   1182 
   1183   Initialize the forward and backward links of two head nodes donated by Map->Used
   1184   and Map->Recycled of two doubly linked lists.
   1185   Initializes the count of the <Key, Value> pairs in the netmap to zero.
   1186 
   1187   If Map is NULL, then ASSERT().
   1188   If the address of Map->Used is NULL, then ASSERT().
   1189   If the address of Map->Recycled is NULl, then ASSERT().
   1190 
   1191   @param[in, out]  Map                   The netmap to initialize.
   1192 
   1193 **/
   1194 VOID
   1195 EFIAPI
   1196 NetMapInit (
   1197   IN OUT NET_MAP                *Map
   1198   )
   1199 {
   1200   ASSERT (Map != NULL);
   1201 
   1202   InitializeListHead (&Map->Used);
   1203   InitializeListHead (&Map->Recycled);
   1204   Map->Count = 0;
   1205 }
   1206 
   1207 
   1208 /**
   1209   To clean up the netmap, that is, release allocated memories.
   1210 
   1211   Removes all nodes of the Used doubly linked list and free memory of all related netmap items.
   1212   Removes all nodes of the Recycled doubly linked list and free memory of all related netmap items.
   1213   The number of the <Key, Value> pairs in the netmap is set to be zero.
   1214 
   1215   If Map is NULL, then ASSERT().
   1216 
   1217   @param[in, out]  Map                   The netmap to clean up.
   1218 
   1219 **/
   1220 VOID
   1221 EFIAPI
   1222 NetMapClean (
   1223   IN OUT NET_MAP            *Map
   1224   )
   1225 {
   1226   NET_MAP_ITEM              *Item;
   1227   LIST_ENTRY                *Entry;
   1228   LIST_ENTRY                *Next;
   1229 
   1230   ASSERT (Map != NULL);
   1231 
   1232   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Used) {
   1233     Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
   1234 
   1235     RemoveEntryList (&Item->Link);
   1236     Map->Count--;
   1237 
   1238     gBS->FreePool (Item);
   1239   }
   1240 
   1241   ASSERT ((Map->Count == 0) && IsListEmpty (&Map->Used));
   1242 
   1243   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Recycled) {
   1244     Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
   1245 
   1246     RemoveEntryList (&Item->Link);
   1247     gBS->FreePool (Item);
   1248   }
   1249 
   1250   ASSERT (IsListEmpty (&Map->Recycled));
   1251 }
   1252 
   1253 
   1254 /**
   1255   Test whether the netmap is empty and return true if it is.
   1256 
   1257   If the number of the <Key, Value> pairs in the netmap is zero, return TRUE.
   1258 
   1259   If Map is NULL, then ASSERT().
   1260 
   1261 
   1262   @param[in]  Map                   The net map to test.
   1263 
   1264   @return TRUE if the netmap is empty, otherwise FALSE.
   1265 
   1266 **/
   1267 BOOLEAN
   1268 EFIAPI
   1269 NetMapIsEmpty (
   1270   IN NET_MAP                *Map
   1271   )
   1272 {
   1273   ASSERT (Map != NULL);
   1274   return (BOOLEAN) (Map->Count == 0);
   1275 }
   1276 
   1277 
   1278 /**
   1279   Return the number of the <Key, Value> pairs in the netmap.
   1280 
   1281   @param[in]  Map                   The netmap to get the entry number.
   1282 
   1283   @return The entry number in the netmap.
   1284 
   1285 **/
   1286 UINTN
   1287 EFIAPI
   1288 NetMapGetCount (
   1289   IN NET_MAP                *Map
   1290   )
   1291 {
   1292   return Map->Count;
   1293 }
   1294 
   1295 
   1296 /**
   1297   Return one allocated item.
   1298 
   1299   If the Recycled doubly linked list of the netmap is empty, it will try to allocate
   1300   a batch of items if there are enough resources and add corresponding nodes to the begining
   1301   of the Recycled doubly linked list of the netmap. Otherwise, it will directly remove
   1302   the fist node entry of the Recycled doubly linked list and return the corresponding item.
   1303 
   1304   If Map is NULL, then ASSERT().
   1305 
   1306   @param[in, out]  Map          The netmap to allocate item for.
   1307 
   1308   @return                       The allocated item. If NULL, the
   1309                                 allocation failed due to resource limit.
   1310 
   1311 **/
   1312 NET_MAP_ITEM *
   1313 NetMapAllocItem (
   1314   IN OUT NET_MAP            *Map
   1315   )
   1316 {
   1317   NET_MAP_ITEM              *Item;
   1318   LIST_ENTRY                *Head;
   1319   UINTN                     Index;
   1320 
   1321   ASSERT (Map != NULL);
   1322 
   1323   Head = &Map->Recycled;
   1324 
   1325   if (IsListEmpty (Head)) {
   1326     for (Index = 0; Index < NET_MAP_INCREAMENT; Index++) {
   1327       Item = AllocatePool (sizeof (NET_MAP_ITEM));
   1328 
   1329       if (Item == NULL) {
   1330         if (Index == 0) {
   1331           return NULL;
   1332         }
   1333 
   1334         break;
   1335       }
   1336 
   1337       InsertHeadList (Head, &Item->Link);
   1338     }
   1339   }
   1340 
   1341   Item = NET_LIST_HEAD (Head, NET_MAP_ITEM, Link);
   1342   NetListRemoveHead (Head);
   1343 
   1344   return Item;
   1345 }
   1346 
   1347 
   1348 /**
   1349   Allocate an item to save the <Key, Value> pair to the head of the netmap.
   1350 
   1351   Allocate an item to save the <Key, Value> pair and add corresponding node entry
   1352   to the beginning of the Used doubly linked list. The number of the <Key, Value>
   1353   pairs in the netmap increase by 1.
   1354 
   1355   If Map is NULL, then ASSERT().
   1356 
   1357   @param[in, out]  Map                   The netmap to insert into.
   1358   @param[in]       Key                   The user's key.
   1359   @param[in]       Value                 The user's value for the key.
   1360 
   1361   @retval EFI_OUT_OF_RESOURCES  Failed to allocate the memory for the item.
   1362   @retval EFI_SUCCESS           The item is inserted to the head.
   1363 
   1364 **/
   1365 EFI_STATUS
   1366 EFIAPI
   1367 NetMapInsertHead (
   1368   IN OUT NET_MAP            *Map,
   1369   IN VOID                   *Key,
   1370   IN VOID                   *Value    OPTIONAL
   1371   )
   1372 {
   1373   NET_MAP_ITEM              *Item;
   1374 
   1375   ASSERT (Map != NULL);
   1376 
   1377   Item = NetMapAllocItem (Map);
   1378 
   1379   if (Item == NULL) {
   1380     return EFI_OUT_OF_RESOURCES;
   1381   }
   1382 
   1383   Item->Key   = Key;
   1384   Item->Value = Value;
   1385   InsertHeadList (&Map->Used, &Item->Link);
   1386 
   1387   Map->Count++;
   1388   return EFI_SUCCESS;
   1389 }
   1390 
   1391 
   1392 /**
   1393   Allocate an item to save the <Key, Value> pair to the tail of the netmap.
   1394 
   1395   Allocate an item to save the <Key, Value> pair and add corresponding node entry
   1396   to the tail of the Used doubly linked list. The number of the <Key, Value>
   1397   pairs in the netmap increase by 1.
   1398 
   1399   If Map is NULL, then ASSERT().
   1400 
   1401   @param[in, out]  Map                   The netmap to insert into.
   1402   @param[in]       Key                   The user's key.
   1403   @param[in]       Value                 The user's value for the key.
   1404 
   1405   @retval EFI_OUT_OF_RESOURCES  Failed to allocate the memory for the item.
   1406   @retval EFI_SUCCESS           The item is inserted to the tail.
   1407 
   1408 **/
   1409 EFI_STATUS
   1410 EFIAPI
   1411 NetMapInsertTail (
   1412   IN OUT NET_MAP            *Map,
   1413   IN VOID                   *Key,
   1414   IN VOID                   *Value    OPTIONAL
   1415   )
   1416 {
   1417   NET_MAP_ITEM              *Item;
   1418 
   1419   ASSERT (Map != NULL);
   1420 
   1421   Item = NetMapAllocItem (Map);
   1422 
   1423   if (Item == NULL) {
   1424     return EFI_OUT_OF_RESOURCES;
   1425   }
   1426 
   1427   Item->Key   = Key;
   1428   Item->Value = Value;
   1429   InsertTailList (&Map->Used, &Item->Link);
   1430 
   1431   Map->Count++;
   1432 
   1433   return EFI_SUCCESS;
   1434 }
   1435 
   1436 
   1437 /**
   1438   Check whether the item is in the Map and return TRUE if it is.
   1439 
   1440   @param[in]  Map                   The netmap to search within.
   1441   @param[in]  Item                  The item to search.
   1442 
   1443   @return TRUE if the item is in the netmap, otherwise FALSE.
   1444 
   1445 **/
   1446 BOOLEAN
   1447 NetItemInMap (
   1448   IN NET_MAP                *Map,
   1449   IN NET_MAP_ITEM           *Item
   1450   )
   1451 {
   1452   LIST_ENTRY            *ListEntry;
   1453 
   1454   NET_LIST_FOR_EACH (ListEntry, &Map->Used) {
   1455     if (ListEntry == &Item->Link) {
   1456       return TRUE;
   1457     }
   1458   }
   1459 
   1460   return FALSE;
   1461 }
   1462 
   1463 
   1464 /**
   1465   Find the key in the netmap and returns the point to the item contains the Key.
   1466 
   1467   Iterate the Used doubly linked list of the netmap to get every item. Compare the key of every
   1468   item with the key to search. It returns the point to the item contains the Key if found.
   1469 
   1470   If Map is NULL, then ASSERT().
   1471 
   1472   @param[in]  Map                   The netmap to search within.
   1473   @param[in]  Key                   The key to search.
   1474 
   1475   @return The point to the item contains the Key, or NULL if Key isn't in the map.
   1476 
   1477 **/
   1478 NET_MAP_ITEM *
   1479 EFIAPI
   1480 NetMapFindKey (
   1481   IN  NET_MAP               *Map,
   1482   IN  VOID                  *Key
   1483   )
   1484 {
   1485   LIST_ENTRY              *Entry;
   1486   NET_MAP_ITEM            *Item;
   1487 
   1488   ASSERT (Map != NULL);
   1489 
   1490   NET_LIST_FOR_EACH (Entry, &Map->Used) {
   1491     Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
   1492 
   1493     if (Item->Key == Key) {
   1494       return Item;
   1495     }
   1496   }
   1497 
   1498   return NULL;
   1499 }
   1500 
   1501 
   1502 /**
   1503   Remove the node entry of the item from the netmap and return the key of the removed item.
   1504 
   1505   Remove the node entry of the item from the Used doubly linked list of the netmap.
   1506   The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
   1507   entry of the item to the Recycled doubly linked list of the netmap. If Value is not NULL,
   1508   Value will point to the value of the item. It returns the key of the removed item.
   1509 
   1510   If Map is NULL, then ASSERT().
   1511   If Item is NULL, then ASSERT().
   1512   if item in not in the netmap, then ASSERT().
   1513 
   1514   @param[in, out]  Map                   The netmap to remove the item from.
   1515   @param[in, out]  Item                  The item to remove.
   1516   @param[out]      Value                 The variable to receive the value if not NULL.
   1517 
   1518   @return                                The key of the removed item.
   1519 
   1520 **/
   1521 VOID *
   1522 EFIAPI
   1523 NetMapRemoveItem (
   1524   IN  OUT NET_MAP             *Map,
   1525   IN  OUT NET_MAP_ITEM        *Item,
   1526   OUT VOID                    **Value           OPTIONAL
   1527   )
   1528 {
   1529   ASSERT ((Map != NULL) && (Item != NULL));
   1530   ASSERT (NetItemInMap (Map, Item));
   1531 
   1532   RemoveEntryList (&Item->Link);
   1533   Map->Count--;
   1534   InsertHeadList (&Map->Recycled, &Item->Link);
   1535 
   1536   if (Value != NULL) {
   1537     *Value = Item->Value;
   1538   }
   1539 
   1540   return Item->Key;
   1541 }
   1542 
   1543 
   1544 /**
   1545   Remove the first node entry on the netmap and return the key of the removed item.
   1546 
   1547   Remove the first node entry from the Used doubly linked list of the netmap.
   1548   The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
   1549   entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
   1550   parameter Value will point to the value of the item. It returns the key of the removed item.
   1551 
   1552   If Map is NULL, then ASSERT().
   1553   If the Used doubly linked list is empty, then ASSERT().
   1554 
   1555   @param[in, out]  Map                   The netmap to remove the head from.
   1556   @param[out]      Value                 The variable to receive the value if not NULL.
   1557 
   1558   @return                                The key of the item removed.
   1559 
   1560 **/
   1561 VOID *
   1562 EFIAPI
   1563 NetMapRemoveHead (
   1564   IN OUT NET_MAP            *Map,
   1565   OUT VOID                  **Value         OPTIONAL
   1566   )
   1567 {
   1568   NET_MAP_ITEM  *Item;
   1569 
   1570   //
   1571   // Often, it indicates a programming error to remove
   1572   // the first entry in an empty list
   1573   //
   1574   ASSERT (Map && !IsListEmpty (&Map->Used));
   1575 
   1576   Item = NET_LIST_HEAD (&Map->Used, NET_MAP_ITEM, Link);
   1577   RemoveEntryList (&Item->Link);
   1578   Map->Count--;
   1579   InsertHeadList (&Map->Recycled, &Item->Link);
   1580 
   1581   if (Value != NULL) {
   1582     *Value = Item->Value;
   1583   }
   1584 
   1585   return Item->Key;
   1586 }
   1587 
   1588 
   1589 /**
   1590   Remove the last node entry on the netmap and return the key of the removed item.
   1591 
   1592   Remove the last node entry from the Used doubly linked list of the netmap.
   1593   The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
   1594   entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
   1595   parameter Value will point to the value of the item. It returns the key of the removed item.
   1596 
   1597   If Map is NULL, then ASSERT().
   1598   If the Used doubly linked list is empty, then ASSERT().
   1599 
   1600   @param[in, out]  Map                   The netmap to remove the tail from.
   1601   @param[out]      Value                 The variable to receive the value if not NULL.
   1602 
   1603   @return                                The key of the item removed.
   1604 
   1605 **/
   1606 VOID *
   1607 EFIAPI
   1608 NetMapRemoveTail (
   1609   IN OUT NET_MAP            *Map,
   1610   OUT VOID                  **Value       OPTIONAL
   1611   )
   1612 {
   1613   NET_MAP_ITEM              *Item;
   1614 
   1615   //
   1616   // Often, it indicates a programming error to remove
   1617   // the last entry in an empty list
   1618   //
   1619   ASSERT (Map && !IsListEmpty (&Map->Used));
   1620 
   1621   Item = NET_LIST_TAIL (&Map->Used, NET_MAP_ITEM, Link);
   1622   RemoveEntryList (&Item->Link);
   1623   Map->Count--;
   1624   InsertHeadList (&Map->Recycled, &Item->Link);
   1625 
   1626   if (Value != NULL) {
   1627     *Value = Item->Value;
   1628   }
   1629 
   1630   return Item->Key;
   1631 }
   1632 
   1633 
   1634 /**
   1635   Iterate through the netmap and call CallBack for each item.
   1636 
   1637   It will continue the traverse if CallBack returns EFI_SUCCESS, otherwise, break
   1638   from the loop. It returns the CallBack's last return value. This function is
   1639   delete safe for the current item.
   1640 
   1641   If Map is NULL, then ASSERT().
   1642   If CallBack is NULL, then ASSERT().
   1643 
   1644   @param[in]  Map                   The Map to iterate through.
   1645   @param[in]  CallBack              The callback function to call for each item.
   1646   @param[in]  Arg                   The opaque parameter to the callback.
   1647 
   1648   @retval EFI_SUCCESS            There is no item in the netmap or CallBack for each item
   1649                                  return EFI_SUCCESS.
   1650   @retval Others                 It returns the CallBack's last return value.
   1651 
   1652 **/
   1653 EFI_STATUS
   1654 EFIAPI
   1655 NetMapIterate (
   1656   IN NET_MAP                *Map,
   1657   IN NET_MAP_CALLBACK       CallBack,
   1658   IN VOID                   *Arg      OPTIONAL
   1659   )
   1660 {
   1661 
   1662   LIST_ENTRY            *Entry;
   1663   LIST_ENTRY            *Next;
   1664   LIST_ENTRY            *Head;
   1665   NET_MAP_ITEM          *Item;
   1666   EFI_STATUS            Result;
   1667 
   1668   ASSERT ((Map != NULL) && (CallBack != NULL));
   1669 
   1670   Head = &Map->Used;
   1671 
   1672   if (IsListEmpty (Head)) {
   1673     return EFI_SUCCESS;
   1674   }
   1675 
   1676   NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
   1677     Item   = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
   1678     Result = CallBack (Map, Item, Arg);
   1679 
   1680     if (EFI_ERROR (Result)) {
   1681       return Result;
   1682     }
   1683   }
   1684 
   1685   return EFI_SUCCESS;
   1686 }
   1687 
   1688 
   1689 /**
   1690   This is the default unload handle for all the network drivers.
   1691 
   1692   Disconnect the driver specified by ImageHandle from all the devices in the handle database.
   1693   Uninstall all the protocols installed in the driver entry point.
   1694 
   1695   @param[in]  ImageHandle       The drivers' driver image.
   1696 
   1697   @retval EFI_SUCCESS           The image is unloaded.
   1698   @retval Others                Failed to unload the image.
   1699 
   1700 **/
   1701 EFI_STATUS
   1702 EFIAPI
   1703 NetLibDefaultUnload (
   1704   IN EFI_HANDLE             ImageHandle
   1705   )
   1706 {
   1707   EFI_STATUS                        Status;
   1708   EFI_HANDLE                        *DeviceHandleBuffer;
   1709   UINTN                             DeviceHandleCount;
   1710   UINTN                             Index;
   1711   UINTN                             Index2;
   1712   EFI_DRIVER_BINDING_PROTOCOL       *DriverBinding;
   1713   EFI_COMPONENT_NAME_PROTOCOL       *ComponentName;
   1714   EFI_COMPONENT_NAME2_PROTOCOL      *ComponentName2;
   1715 
   1716   //
   1717   // Get the list of all the handles in the handle database.
   1718   // If there is an error getting the list, then the unload
   1719   // operation fails.
   1720   //
   1721   Status = gBS->LocateHandleBuffer (
   1722                   AllHandles,
   1723                   NULL,
   1724                   NULL,
   1725                   &DeviceHandleCount,
   1726                   &DeviceHandleBuffer
   1727                   );
   1728 
   1729   if (EFI_ERROR (Status)) {
   1730     return Status;
   1731   }
   1732 
   1733   for (Index = 0; Index < DeviceHandleCount; Index++) {
   1734     Status = gBS->HandleProtocol (
   1735                     DeviceHandleBuffer[Index],
   1736                     &gEfiDriverBindingProtocolGuid,
   1737                     (VOID **) &DriverBinding
   1738                     );
   1739     if (EFI_ERROR (Status)) {
   1740       continue;
   1741     }
   1742 
   1743     if (DriverBinding->ImageHandle != ImageHandle) {
   1744       continue;
   1745     }
   1746 
   1747     //
   1748     // Disconnect the driver specified by ImageHandle from all
   1749     // the devices in the handle database.
   1750     //
   1751     for (Index2 = 0; Index2 < DeviceHandleCount; Index2++) {
   1752       Status = gBS->DisconnectController (
   1753                       DeviceHandleBuffer[Index2],
   1754                       DriverBinding->DriverBindingHandle,
   1755                       NULL
   1756                       );
   1757     }
   1758 
   1759     //
   1760     // Uninstall all the protocols installed in the driver entry point
   1761     //
   1762     gBS->UninstallProtocolInterface (
   1763           DriverBinding->DriverBindingHandle,
   1764           &gEfiDriverBindingProtocolGuid,
   1765           DriverBinding
   1766           );
   1767 
   1768     Status = gBS->HandleProtocol (
   1769                     DeviceHandleBuffer[Index],
   1770                     &gEfiComponentNameProtocolGuid,
   1771                     (VOID **) &ComponentName
   1772                     );
   1773     if (!EFI_ERROR (Status)) {
   1774       gBS->UninstallProtocolInterface (
   1775              DriverBinding->DriverBindingHandle,
   1776              &gEfiComponentNameProtocolGuid,
   1777              ComponentName
   1778              );
   1779     }
   1780 
   1781     Status = gBS->HandleProtocol (
   1782                     DeviceHandleBuffer[Index],
   1783                     &gEfiComponentName2ProtocolGuid,
   1784                     (VOID **) &ComponentName2
   1785                     );
   1786     if (!EFI_ERROR (Status)) {
   1787       gBS->UninstallProtocolInterface (
   1788              DriverBinding->DriverBindingHandle,
   1789              &gEfiComponentName2ProtocolGuid,
   1790              ComponentName2
   1791              );
   1792     }
   1793   }
   1794 
   1795   //
   1796   // Free the buffer containing the list of handles from the handle database
   1797   //
   1798   if (DeviceHandleBuffer != NULL) {
   1799     gBS->FreePool (DeviceHandleBuffer);
   1800   }
   1801 
   1802   return EFI_SUCCESS;
   1803 }
   1804 
   1805 
   1806 
   1807 /**
   1808   Create a child of the service that is identified by ServiceBindingGuid.
   1809 
   1810   Get the ServiceBinding Protocol first, then use it to create a child.
   1811 
   1812   If ServiceBindingGuid is NULL, then ASSERT().
   1813   If ChildHandle is NULL, then ASSERT().
   1814 
   1815   @param[in]       Controller            The controller which has the service installed.
   1816   @param[in]       Image                 The image handle used to open service.
   1817   @param[in]       ServiceBindingGuid    The service's Guid.
   1818   @param[in, out]  ChildHandle           The handle to receive the create child.
   1819 
   1820   @retval EFI_SUCCESS           The child is successfully created.
   1821   @retval Others                Failed to create the child.
   1822 
   1823 **/
   1824 EFI_STATUS
   1825 EFIAPI
   1826 NetLibCreateServiceChild (
   1827   IN  EFI_HANDLE            Controller,
   1828   IN  EFI_HANDLE            Image,
   1829   IN  EFI_GUID              *ServiceBindingGuid,
   1830   IN  OUT EFI_HANDLE        *ChildHandle
   1831   )
   1832 {
   1833   EFI_STATUS                    Status;
   1834   EFI_SERVICE_BINDING_PROTOCOL  *Service;
   1835 
   1836 
   1837   ASSERT ((ServiceBindingGuid != NULL) && (ChildHandle != NULL));
   1838 
   1839   //
   1840   // Get the ServiceBinding Protocol
   1841   //
   1842   Status = gBS->OpenProtocol (
   1843                   Controller,
   1844                   ServiceBindingGuid,
   1845                   (VOID **) &Service,
   1846                   Image,
   1847                   Controller,
   1848                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1849                   );
   1850 
   1851   if (EFI_ERROR (Status)) {
   1852     return Status;
   1853   }
   1854 
   1855   //
   1856   // Create a child
   1857   //
   1858   Status = Service->CreateChild (Service, ChildHandle);
   1859   return Status;
   1860 }
   1861 
   1862 
   1863 /**
   1864   Destroy a child of the service that is identified by ServiceBindingGuid.
   1865 
   1866   Get the ServiceBinding Protocol first, then use it to destroy a child.
   1867 
   1868   If ServiceBindingGuid is NULL, then ASSERT().
   1869 
   1870   @param[in]   Controller            The controller which has the service installed.
   1871   @param[in]   Image                 The image handle used to open service.
   1872   @param[in]   ServiceBindingGuid    The service's Guid.
   1873   @param[in]   ChildHandle           The child to destroy.
   1874 
   1875   @retval EFI_SUCCESS           The child is successfully destroyed.
   1876   @retval Others                Failed to destroy the child.
   1877 
   1878 **/
   1879 EFI_STATUS
   1880 EFIAPI
   1881 NetLibDestroyServiceChild (
   1882   IN  EFI_HANDLE            Controller,
   1883   IN  EFI_HANDLE            Image,
   1884   IN  EFI_GUID              *ServiceBindingGuid,
   1885   IN  EFI_HANDLE            ChildHandle
   1886   )
   1887 {
   1888   EFI_STATUS                    Status;
   1889   EFI_SERVICE_BINDING_PROTOCOL  *Service;
   1890 
   1891   ASSERT (ServiceBindingGuid != NULL);
   1892 
   1893   //
   1894   // Get the ServiceBinding Protocol
   1895   //
   1896   Status = gBS->OpenProtocol (
   1897                   Controller,
   1898                   ServiceBindingGuid,
   1899                   (VOID **) &Service,
   1900                   Image,
   1901                   Controller,
   1902                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1903                   );
   1904 
   1905   if (EFI_ERROR (Status)) {
   1906     return Status;
   1907   }
   1908 
   1909   //
   1910   // destroy the child
   1911   //
   1912   Status = Service->DestroyChild (Service, ChildHandle);
   1913   return Status;
   1914 }
   1915 
   1916 /**
   1917   Get handle with Simple Network Protocol installed on it.
   1918 
   1919   There should be MNP Service Binding Protocol installed on the input ServiceHandle.
   1920   If Simple Network Protocol is already installed on the ServiceHandle, the
   1921   ServiceHandle will be returned. If SNP is not installed on the ServiceHandle,
   1922   try to find its parent handle with SNP installed.
   1923 
   1924   @param[in]   ServiceHandle    The handle where network service binding protocols are
   1925                                 installed on.
   1926   @param[out]  Snp              The pointer to store the address of the SNP instance.
   1927                                 This is an optional parameter that may be NULL.
   1928 
   1929   @return The SNP handle, or NULL if not found.
   1930 
   1931 **/
   1932 EFI_HANDLE
   1933 EFIAPI
   1934 NetLibGetSnpHandle (
   1935   IN   EFI_HANDLE                  ServiceHandle,
   1936   OUT  EFI_SIMPLE_NETWORK_PROTOCOL **Snp  OPTIONAL
   1937   )
   1938 {
   1939   EFI_STATUS                   Status;
   1940   EFI_SIMPLE_NETWORK_PROTOCOL  *SnpInstance;
   1941   EFI_DEVICE_PATH_PROTOCOL     *DevicePath;
   1942   EFI_HANDLE                   SnpHandle;
   1943 
   1944   //
   1945   // Try to open SNP from ServiceHandle
   1946   //
   1947   SnpInstance = NULL;
   1948   Status = gBS->HandleProtocol (ServiceHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);
   1949   if (!EFI_ERROR (Status)) {
   1950     if (Snp != NULL) {
   1951       *Snp = SnpInstance;
   1952     }
   1953     return ServiceHandle;
   1954   }
   1955 
   1956   //
   1957   // Failed to open SNP, try to get SNP handle by LocateDevicePath()
   1958   //
   1959   DevicePath = DevicePathFromHandle (ServiceHandle);
   1960   if (DevicePath == NULL) {
   1961     return NULL;
   1962   }
   1963 
   1964   SnpHandle = NULL;
   1965   Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &DevicePath, &SnpHandle);
   1966   if (EFI_ERROR (Status)) {
   1967     //
   1968     // Failed to find SNP handle
   1969     //
   1970     return NULL;
   1971   }
   1972 
   1973   Status = gBS->HandleProtocol (SnpHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);
   1974   if (!EFI_ERROR (Status)) {
   1975     if (Snp != NULL) {
   1976       *Snp = SnpInstance;
   1977     }
   1978     return SnpHandle;
   1979   }
   1980 
   1981   return NULL;
   1982 }
   1983 
   1984 /**
   1985   Retrieve VLAN ID of a VLAN device handle.
   1986 
   1987   Search VLAN device path node in Device Path of specified ServiceHandle and
   1988   return its VLAN ID. If no VLAN device path node found, then this ServiceHandle
   1989   is not a VLAN device handle, and 0 will be returned.
   1990 
   1991   @param[in]   ServiceHandle    The handle where network service binding protocols are
   1992                                 installed on.
   1993 
   1994   @return VLAN ID of the device handle, or 0 if not a VLAN device.
   1995 
   1996 **/
   1997 UINT16
   1998 EFIAPI
   1999 NetLibGetVlanId (
   2000   IN EFI_HANDLE             ServiceHandle
   2001   )
   2002 {
   2003   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
   2004   EFI_DEVICE_PATH_PROTOCOL  *Node;
   2005 
   2006   DevicePath = DevicePathFromHandle (ServiceHandle);
   2007   if (DevicePath == NULL) {
   2008     return 0;
   2009   }
   2010 
   2011   Node = DevicePath;
   2012   while (!IsDevicePathEnd (Node)) {
   2013     if (Node->Type == MESSAGING_DEVICE_PATH && Node->SubType == MSG_VLAN_DP) {
   2014       return ((VLAN_DEVICE_PATH *) Node)->VlanId;
   2015     }
   2016     Node = NextDevicePathNode (Node);
   2017   }
   2018 
   2019   return 0;
   2020 }
   2021 
   2022 /**
   2023   Find VLAN device handle with specified VLAN ID.
   2024 
   2025   The VLAN child device handle is created by VLAN Config Protocol on ControllerHandle.
   2026   This function will append VLAN device path node to the parent device path,
   2027   and then use LocateDevicePath() to find the correct VLAN device handle.
   2028 
   2029   @param[in]   ControllerHandle The handle where network service binding protocols are
   2030                                 installed on.
   2031   @param[in]   VlanId           The configured VLAN ID for the VLAN device.
   2032 
   2033   @return The VLAN device handle, or NULL if not found.
   2034 
   2035 **/
   2036 EFI_HANDLE
   2037 EFIAPI
   2038 NetLibGetVlanHandle (
   2039   IN EFI_HANDLE             ControllerHandle,
   2040   IN UINT16                 VlanId
   2041   )
   2042 {
   2043   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
   2044   EFI_DEVICE_PATH_PROTOCOL  *VlanDevicePath;
   2045   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
   2046   VLAN_DEVICE_PATH          VlanNode;
   2047   EFI_HANDLE                Handle;
   2048 
   2049   ParentDevicePath = DevicePathFromHandle (ControllerHandle);
   2050   if (ParentDevicePath == NULL) {
   2051     return NULL;
   2052   }
   2053 
   2054   //
   2055   // Construct VLAN device path
   2056   //
   2057   CopyMem (&VlanNode, &mNetVlanDevicePathTemplate, sizeof (VLAN_DEVICE_PATH));
   2058   VlanNode.VlanId = VlanId;
   2059   VlanDevicePath = AppendDevicePathNode (
   2060                      ParentDevicePath,
   2061                      (EFI_DEVICE_PATH_PROTOCOL *) &VlanNode
   2062                      );
   2063   if (VlanDevicePath == NULL) {
   2064     return NULL;
   2065   }
   2066 
   2067   //
   2068   // Find VLAN device handle
   2069   //
   2070   Handle = NULL;
   2071   DevicePath = VlanDevicePath;
   2072   gBS->LocateDevicePath (
   2073          &gEfiDevicePathProtocolGuid,
   2074          &DevicePath,
   2075          &Handle
   2076          );
   2077   if (!IsDevicePathEnd (DevicePath)) {
   2078     //
   2079     // Device path is not exactly match
   2080     //
   2081     Handle = NULL;
   2082   }
   2083 
   2084   FreePool (VlanDevicePath);
   2085   return Handle;
   2086 }
   2087 
   2088 /**
   2089   Get MAC address associated with the network service handle.
   2090 
   2091   There should be MNP Service Binding Protocol installed on the input ServiceHandle.
   2092   If SNP is installed on the ServiceHandle or its parent handle, MAC address will
   2093   be retrieved from SNP. If no SNP found, try to get SNP mode data use MNP.
   2094 
   2095   @param[in]   ServiceHandle    The handle where network service binding protocols are
   2096                                 installed on.
   2097   @param[out]  MacAddress       The pointer to store the returned MAC address.
   2098   @param[out]  AddressSize      The length of returned MAC address.
   2099 
   2100   @retval EFI_SUCCESS           MAC address is returned successfully.
   2101   @retval Others                Failed to get SNP mode data.
   2102 
   2103 **/
   2104 EFI_STATUS
   2105 EFIAPI
   2106 NetLibGetMacAddress (
   2107   IN  EFI_HANDLE            ServiceHandle,
   2108   OUT EFI_MAC_ADDRESS       *MacAddress,
   2109   OUT UINTN                 *AddressSize
   2110   )
   2111 {
   2112   EFI_STATUS                   Status;
   2113   EFI_SIMPLE_NETWORK_PROTOCOL  *Snp;
   2114   EFI_SIMPLE_NETWORK_MODE      *SnpMode;
   2115   EFI_SIMPLE_NETWORK_MODE      SnpModeData;
   2116   EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
   2117   EFI_SERVICE_BINDING_PROTOCOL *MnpSb;
   2118   EFI_HANDLE                   *SnpHandle;
   2119   EFI_HANDLE                   MnpChildHandle;
   2120 
   2121   ASSERT (MacAddress != NULL);
   2122   ASSERT (AddressSize != NULL);
   2123 
   2124   //
   2125   // Try to get SNP handle
   2126   //
   2127   Snp = NULL;
   2128   SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);
   2129   if (SnpHandle != NULL) {
   2130     //
   2131     // SNP found, use it directly
   2132     //
   2133     SnpMode = Snp->Mode;
   2134   } else {
   2135     //
   2136     // Failed to get SNP handle, try to get MAC address from MNP
   2137     //
   2138     MnpChildHandle = NULL;
   2139     Status = gBS->HandleProtocol (
   2140                     ServiceHandle,
   2141                     &gEfiManagedNetworkServiceBindingProtocolGuid,
   2142                     (VOID **) &MnpSb
   2143                     );
   2144     if (EFI_ERROR (Status)) {
   2145       return Status;
   2146     }
   2147 
   2148     //
   2149     // Create a MNP child
   2150     //
   2151     Status = MnpSb->CreateChild (MnpSb, &MnpChildHandle);
   2152     if (EFI_ERROR (Status)) {
   2153       return Status;
   2154     }
   2155 
   2156     //
   2157     // Open MNP protocol
   2158     //
   2159     Status = gBS->HandleProtocol (
   2160                     MnpChildHandle,
   2161                     &gEfiManagedNetworkProtocolGuid,
   2162                     (VOID **) &Mnp
   2163                     );
   2164     if (EFI_ERROR (Status)) {
   2165       MnpSb->DestroyChild (MnpSb, MnpChildHandle);
   2166       return Status;
   2167     }
   2168 
   2169     //
   2170     // Try to get SNP mode from MNP
   2171     //
   2172     Status = Mnp->GetModeData (Mnp, NULL, &SnpModeData);
   2173     if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {
   2174       MnpSb->DestroyChild (MnpSb, MnpChildHandle);
   2175       return Status;
   2176     }
   2177     SnpMode = &SnpModeData;
   2178 
   2179     //
   2180     // Destroy the MNP child
   2181     //
   2182     MnpSb->DestroyChild (MnpSb, MnpChildHandle);
   2183   }
   2184 
   2185   *AddressSize = SnpMode->HwAddressSize;
   2186   CopyMem (MacAddress->Addr, SnpMode->CurrentAddress.Addr, SnpMode->HwAddressSize);
   2187 
   2188   return EFI_SUCCESS;
   2189 }
   2190 
   2191 /**
   2192   Convert MAC address of the NIC associated with specified Service Binding Handle
   2193   to a unicode string. Callers are responsible for freeing the string storage.
   2194 
   2195   Locate simple network protocol associated with the Service Binding Handle and
   2196   get the mac address from SNP. Then convert the mac address into a unicode
   2197   string. It takes 2 unicode characters to represent a 1 byte binary buffer.
   2198   Plus one unicode character for the null-terminator.
   2199 
   2200   @param[in]   ServiceHandle         The handle where network service binding protocol is
   2201                                      installed on.
   2202   @param[in]   ImageHandle           The image handle used to act as the agent handle to
   2203                                      get the simple network protocol. This parameter is
   2204                                      optional and may be NULL.
   2205   @param[out]  MacString             The pointer to store the address of the string
   2206                                      representation of  the mac address.
   2207 
   2208   @retval EFI_SUCCESS           Convert the mac address a unicode string successfully.
   2209   @retval EFI_OUT_OF_RESOURCES  There are not enough memory resource.
   2210   @retval Others                Failed to open the simple network protocol.
   2211 
   2212 **/
   2213 EFI_STATUS
   2214 EFIAPI
   2215 NetLibGetMacString (
   2216   IN  EFI_HANDLE            ServiceHandle,
   2217   IN  EFI_HANDLE            ImageHandle, OPTIONAL
   2218   OUT CHAR16                **MacString
   2219   )
   2220 {
   2221   EFI_STATUS                   Status;
   2222   EFI_MAC_ADDRESS              MacAddress;
   2223   UINT8                        *HwAddress;
   2224   UINTN                        HwAddressSize;
   2225   UINT16                       VlanId;
   2226   CHAR16                       *String;
   2227   UINTN                        Index;
   2228 
   2229   ASSERT (MacString != NULL);
   2230 
   2231   //
   2232   // Get MAC address of the network device
   2233   //
   2234   Status = NetLibGetMacAddress (ServiceHandle, &MacAddress, &HwAddressSize);
   2235   if (EFI_ERROR (Status)) {
   2236     return Status;
   2237   }
   2238 
   2239   //
   2240   // It takes 2 unicode characters to represent a 1 byte binary buffer.
   2241   // If VLAN is configured, it will need extra 5 characters like "\0005".
   2242   // Plus one unicode character for the null-terminator.
   2243   //
   2244   String = AllocateZeroPool ((2 * HwAddressSize + 5 + 1) * sizeof (CHAR16));
   2245   if (String == NULL) {
   2246     return EFI_OUT_OF_RESOURCES;
   2247   }
   2248   *MacString = String;
   2249 
   2250   //
   2251   // Convert the MAC address into a unicode string.
   2252   //
   2253   HwAddress = &MacAddress.Addr[0];
   2254   for (Index = 0; Index < HwAddressSize; Index++) {
   2255     String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(HwAddress++), 2);
   2256   }
   2257 
   2258   //
   2259   // Append VLAN ID if any
   2260   //
   2261   VlanId = NetLibGetVlanId (ServiceHandle);
   2262   if (VlanId != 0) {
   2263     *String++ = L'\\';
   2264     String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, VlanId, 4);
   2265   }
   2266 
   2267   //
   2268   // Null terminate the Unicode string
   2269   //
   2270   *String = L'\0';
   2271 
   2272   return EFI_SUCCESS;
   2273 }
   2274 
   2275 /**
   2276   Detect media status for specified network device.
   2277 
   2278   The underlying UNDI driver may or may not support reporting media status from
   2279   GET_STATUS command (PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED). This routine
   2280   will try to invoke Snp->GetStatus() to get the media status: if media already
   2281   present, it return directly; if media not present, it will stop SNP and then
   2282   restart SNP to get the latest media status, this give chance to get the correct
   2283   media status for old UNDI driver which doesn't support reporting media status
   2284   from GET_STATUS command.
   2285   Note: there will be two limitations for current algorithm:
   2286   1) for UNDI with this capability, in case of cable is not attached, there will
   2287      be an redundant Stop/Start() process;
   2288   2) for UNDI without this capability, in case that network cable is attached when
   2289      Snp->Initialize() is invoked while network cable is unattached later,
   2290      NetLibDetectMedia() will report MediaPresent as TRUE, causing upper layer
   2291      apps to wait for timeout time.
   2292 
   2293   @param[in]   ServiceHandle    The handle where network service binding protocols are
   2294                                 installed on.
   2295   @param[out]  MediaPresent     The pointer to store the media status.
   2296 
   2297   @retval EFI_SUCCESS           Media detection success.
   2298   @retval EFI_INVALID_PARAMETER ServiceHandle is not valid network device handle.
   2299   @retval EFI_UNSUPPORTED       Network device does not support media detection.
   2300   @retval EFI_DEVICE_ERROR      SNP is in unknown state.
   2301 
   2302 **/
   2303 EFI_STATUS
   2304 EFIAPI
   2305 NetLibDetectMedia (
   2306   IN  EFI_HANDLE            ServiceHandle,
   2307   OUT BOOLEAN               *MediaPresent
   2308   )
   2309 {
   2310   EFI_STATUS                   Status;
   2311   EFI_HANDLE                   SnpHandle;
   2312   EFI_SIMPLE_NETWORK_PROTOCOL  *Snp;
   2313   UINT32                       InterruptStatus;
   2314   UINT32                       OldState;
   2315   EFI_MAC_ADDRESS              *MCastFilter;
   2316   UINT32                       MCastFilterCount;
   2317   UINT32                       EnableFilterBits;
   2318   UINT32                       DisableFilterBits;
   2319   BOOLEAN                      ResetMCastFilters;
   2320 
   2321   ASSERT (MediaPresent != NULL);
   2322 
   2323   //
   2324   // Get SNP handle
   2325   //
   2326   Snp = NULL;
   2327   SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);
   2328   if (SnpHandle == NULL) {
   2329     return EFI_INVALID_PARAMETER;
   2330   }
   2331 
   2332   //
   2333   // Check whether SNP support media detection
   2334   //
   2335   if (!Snp->Mode->MediaPresentSupported) {
   2336     return EFI_UNSUPPORTED;
   2337   }
   2338 
   2339   //
   2340   // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
   2341   //
   2342   Status = Snp->GetStatus (Snp, &InterruptStatus, NULL);
   2343   if (EFI_ERROR (Status)) {
   2344     return Status;
   2345   }
   2346 
   2347   if (Snp->Mode->MediaPresent) {
   2348     //
   2349     // Media is present, return directly
   2350     //
   2351     *MediaPresent = TRUE;
   2352     return EFI_SUCCESS;
   2353   }
   2354 
   2355   //
   2356   // Till now, GetStatus() report no media; while, in case UNDI not support
   2357   // reporting media status from GetStatus(), this media status may be incorrect.
   2358   // So, we will stop SNP and then restart it to get the correct media status.
   2359   //
   2360   OldState = Snp->Mode->State;
   2361   if (OldState >= EfiSimpleNetworkMaxState) {
   2362     return EFI_DEVICE_ERROR;
   2363   }
   2364 
   2365   MCastFilter = NULL;
   2366 
   2367   if (OldState == EfiSimpleNetworkInitialized) {
   2368     //
   2369     // SNP is already in use, need Shutdown/Stop and then Start/Initialize
   2370     //
   2371 
   2372     //
   2373     // Backup current SNP receive filter settings
   2374     //
   2375     EnableFilterBits  = Snp->Mode->ReceiveFilterSetting;
   2376     DisableFilterBits = Snp->Mode->ReceiveFilterMask ^ EnableFilterBits;
   2377 
   2378     ResetMCastFilters = TRUE;
   2379     MCastFilterCount  = Snp->Mode->MCastFilterCount;
   2380     if (MCastFilterCount != 0) {
   2381       MCastFilter = AllocateCopyPool (
   2382                       MCastFilterCount * sizeof (EFI_MAC_ADDRESS),
   2383                       Snp->Mode->MCastFilter
   2384                       );
   2385       ASSERT (MCastFilter != NULL);
   2386 
   2387       ResetMCastFilters = FALSE;
   2388     }
   2389 
   2390     //
   2391     // Shutdown/Stop the simple network
   2392     //
   2393     Status = Snp->Shutdown (Snp);
   2394     if (!EFI_ERROR (Status)) {
   2395       Status = Snp->Stop (Snp);
   2396     }
   2397     if (EFI_ERROR (Status)) {
   2398       goto Exit;
   2399     }
   2400 
   2401     //
   2402     // Start/Initialize the simple network
   2403     //
   2404     Status = Snp->Start (Snp);
   2405     if (!EFI_ERROR (Status)) {
   2406       Status = Snp->Initialize (Snp, 0, 0);
   2407     }
   2408     if (EFI_ERROR (Status)) {
   2409       goto Exit;
   2410     }
   2411 
   2412     //
   2413     // Here we get the correct media status
   2414     //
   2415     *MediaPresent = Snp->Mode->MediaPresent;
   2416 
   2417     //
   2418     // Restore SNP receive filter settings
   2419     //
   2420     Status = Snp->ReceiveFilters (
   2421                     Snp,
   2422                     EnableFilterBits,
   2423                     DisableFilterBits,
   2424                     ResetMCastFilters,
   2425                     MCastFilterCount,
   2426                     MCastFilter
   2427                     );
   2428 
   2429     if (MCastFilter != NULL) {
   2430       FreePool (MCastFilter);
   2431     }
   2432 
   2433     return Status;
   2434   }
   2435 
   2436   //
   2437   // SNP is not in use, it's in state of EfiSimpleNetworkStopped or EfiSimpleNetworkStarted
   2438   //
   2439   if (OldState == EfiSimpleNetworkStopped) {
   2440     //
   2441     // SNP not start yet, start it
   2442     //
   2443     Status = Snp->Start (Snp);
   2444     if (EFI_ERROR (Status)) {
   2445       goto Exit;
   2446     }
   2447   }
   2448 
   2449   //
   2450   // Initialize the simple network
   2451   //
   2452   Status = Snp->Initialize (Snp, 0, 0);
   2453   if (EFI_ERROR (Status)) {
   2454     Status = EFI_DEVICE_ERROR;
   2455     goto Exit;
   2456   }
   2457 
   2458   //
   2459   // Here we get the correct media status
   2460   //
   2461   *MediaPresent = Snp->Mode->MediaPresent;
   2462 
   2463   //
   2464   // Shut down the simple network
   2465   //
   2466   Snp->Shutdown (Snp);
   2467 
   2468 Exit:
   2469   if (OldState == EfiSimpleNetworkStopped) {
   2470     //
   2471     // Original SNP sate is Stopped, restore to original state
   2472     //
   2473     Snp->Stop (Snp);
   2474   }
   2475 
   2476   if (MCastFilter != NULL) {
   2477     FreePool (MCastFilter);
   2478   }
   2479 
   2480   return Status;
   2481 }
   2482 
   2483 /**
   2484   Check the default address used by the IPv4 driver is static or dynamic (acquired
   2485   from DHCP).
   2486 
   2487   If the controller handle does not have the EFI_IP4_CONFIG2_PROTOCOL installed, the
   2488   default address is static. If failed to get the policy from Ip4 Config2 Protocol,
   2489   the default address is static. Otherwise, get the result from Ip4 Config2 Protocol.
   2490 
   2491   @param[in]   Controller     The controller handle which has the EFI_IP4_CONFIG2_PROTOCOL
   2492                               relative with the default address to judge.
   2493 
   2494   @retval TRUE           If the default address is static.
   2495   @retval FALSE          If the default address is acquired from DHCP.
   2496 
   2497 **/
   2498 BOOLEAN
   2499 NetLibDefaultAddressIsStatic (
   2500   IN EFI_HANDLE  Controller
   2501   )
   2502 {
   2503   EFI_STATUS                       Status;
   2504   EFI_IP4_CONFIG2_PROTOCOL         *Ip4Config2;
   2505   UINTN                            DataSize;
   2506   EFI_IP4_CONFIG2_POLICY           Policy;
   2507   BOOLEAN                          IsStatic;
   2508 
   2509   Ip4Config2 = NULL;
   2510 
   2511   DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
   2512 
   2513   IsStatic   = TRUE;
   2514 
   2515   //
   2516   // Get Ip4Config2 policy.
   2517   //
   2518   Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);
   2519   if (EFI_ERROR (Status)) {
   2520     goto ON_EXIT;
   2521   }
   2522 
   2523   Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypePolicy, &DataSize, &Policy);
   2524   if (EFI_ERROR (Status)) {
   2525     goto ON_EXIT;
   2526   }
   2527 
   2528   IsStatic = (BOOLEAN) (Policy == Ip4Config2PolicyStatic);
   2529 
   2530 ON_EXIT:
   2531 
   2532   return IsStatic;
   2533 }
   2534 
   2535 /**
   2536   Create an IPv4 device path node.
   2537 
   2538   The header type of IPv4 device path node is MESSAGING_DEVICE_PATH.
   2539   The header subtype of IPv4 device path node is MSG_IPv4_DP.
   2540   Get other info from parameters to make up the whole IPv4 device path node.
   2541 
   2542   @param[in, out]  Node                  Pointer to the IPv4 device path node.
   2543   @param[in]       Controller            The controller handle.
   2544   @param[in]       LocalIp               The local IPv4 address.
   2545   @param[in]       LocalPort             The local port.
   2546   @param[in]       RemoteIp              The remote IPv4 address.
   2547   @param[in]       RemotePort            The remote port.
   2548   @param[in]       Protocol              The protocol type in the IP header.
   2549   @param[in]       UseDefaultAddress     Whether this instance is using default address or not.
   2550 
   2551 **/
   2552 VOID
   2553 EFIAPI
   2554 NetLibCreateIPv4DPathNode (
   2555   IN OUT IPv4_DEVICE_PATH  *Node,
   2556   IN EFI_HANDLE            Controller,
   2557   IN IP4_ADDR              LocalIp,
   2558   IN UINT16                LocalPort,
   2559   IN IP4_ADDR              RemoteIp,
   2560   IN UINT16                RemotePort,
   2561   IN UINT16                Protocol,
   2562   IN BOOLEAN               UseDefaultAddress
   2563   )
   2564 {
   2565   Node->Header.Type    = MESSAGING_DEVICE_PATH;
   2566   Node->Header.SubType = MSG_IPv4_DP;
   2567   SetDevicePathNodeLength (&Node->Header, sizeof (IPv4_DEVICE_PATH));
   2568 
   2569   CopyMem (&Node->LocalIpAddress, &LocalIp, sizeof (EFI_IPv4_ADDRESS));
   2570   CopyMem (&Node->RemoteIpAddress, &RemoteIp, sizeof (EFI_IPv4_ADDRESS));
   2571 
   2572   Node->LocalPort  = LocalPort;
   2573   Node->RemotePort = RemotePort;
   2574 
   2575   Node->Protocol = Protocol;
   2576 
   2577   if (!UseDefaultAddress) {
   2578     Node->StaticIpAddress = TRUE;
   2579   } else {
   2580     Node->StaticIpAddress = NetLibDefaultAddressIsStatic (Controller);
   2581   }
   2582 
   2583   //
   2584   // Set the Gateway IP address to default value 0:0:0:0.
   2585   // Set the Subnet mask to default value 255:255:255:0.
   2586   //
   2587   ZeroMem (&Node->GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS));
   2588   SetMem (&Node->SubnetMask, sizeof (EFI_IPv4_ADDRESS), 0xff);
   2589   Node->SubnetMask.Addr[3] = 0;
   2590 }
   2591 
   2592 /**
   2593   Create an IPv6 device path node.
   2594 
   2595   The header type of IPv6 device path node is MESSAGING_DEVICE_PATH.
   2596   The header subtype of IPv6 device path node is MSG_IPv6_DP.
   2597   Get other info from parameters to make up the whole IPv6 device path node.
   2598 
   2599   @param[in, out]  Node                  Pointer to the IPv6 device path node.
   2600   @param[in]       Controller            The controller handle.
   2601   @param[in]       LocalIp               The local IPv6 address.
   2602   @param[in]       LocalPort             The local port.
   2603   @param[in]       RemoteIp              The remote IPv6 address.
   2604   @param[in]       RemotePort            The remote port.
   2605   @param[in]       Protocol              The protocol type in the IP header.
   2606 
   2607 **/
   2608 VOID
   2609 EFIAPI
   2610 NetLibCreateIPv6DPathNode (
   2611   IN OUT IPv6_DEVICE_PATH  *Node,
   2612   IN EFI_HANDLE            Controller,
   2613   IN EFI_IPv6_ADDRESS      *LocalIp,
   2614   IN UINT16                LocalPort,
   2615   IN EFI_IPv6_ADDRESS      *RemoteIp,
   2616   IN UINT16                RemotePort,
   2617   IN UINT16                Protocol
   2618   )
   2619 {
   2620   Node->Header.Type    = MESSAGING_DEVICE_PATH;
   2621   Node->Header.SubType = MSG_IPv6_DP;
   2622   SetDevicePathNodeLength (&Node->Header, sizeof (IPv6_DEVICE_PATH));
   2623 
   2624   CopyMem (&Node->LocalIpAddress, LocalIp, sizeof (EFI_IPv6_ADDRESS));
   2625   CopyMem (&Node->RemoteIpAddress, RemoteIp, sizeof (EFI_IPv6_ADDRESS));
   2626 
   2627   Node->LocalPort  = LocalPort;
   2628   Node->RemotePort = RemotePort;
   2629 
   2630   Node->Protocol        = Protocol;
   2631 
   2632   //
   2633   // Set default value to IPAddressOrigin, PrefixLength.
   2634   // Set the Gateway IP address to unspecified address.
   2635   //
   2636   Node->IpAddressOrigin = 0;
   2637   Node->PrefixLength    = IP6_PREFIX_LENGTH;
   2638   ZeroMem (&Node->GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS));
   2639 }
   2640 
   2641 /**
   2642   Find the UNDI/SNP handle from controller and protocol GUID.
   2643 
   2644   For example, IP will open a MNP child to transmit/receive
   2645   packets, when MNP is stopped, IP should also be stopped. IP
   2646   needs to find its own private data which is related the IP's
   2647   service binding instance that is install on UNDI/SNP handle.
   2648   Now, the controller is either a MNP or ARP child handle. But
   2649   IP opens these handle BY_DRIVER, use that info, we can get the
   2650   UNDI/SNP handle.
   2651 
   2652   @param[in]  Controller            Then protocol handle to check.
   2653   @param[in]  ProtocolGuid          The protocol that is related with the handle.
   2654 
   2655   @return The UNDI/SNP handle or NULL for errors.
   2656 
   2657 **/
   2658 EFI_HANDLE
   2659 EFIAPI
   2660 NetLibGetNicHandle (
   2661   IN EFI_HANDLE             Controller,
   2662   IN EFI_GUID               *ProtocolGuid
   2663   )
   2664 {
   2665   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenBuffer;
   2666   EFI_HANDLE                          Handle;
   2667   EFI_STATUS                          Status;
   2668   UINTN                               OpenCount;
   2669   UINTN                               Index;
   2670 
   2671   Status = gBS->OpenProtocolInformation (
   2672                   Controller,
   2673                   ProtocolGuid,
   2674                   &OpenBuffer,
   2675                   &OpenCount
   2676                   );
   2677 
   2678   if (EFI_ERROR (Status)) {
   2679     return NULL;
   2680   }
   2681 
   2682   Handle = NULL;
   2683 
   2684   for (Index = 0; Index < OpenCount; Index++) {
   2685     if ((OpenBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
   2686       Handle = OpenBuffer[Index].ControllerHandle;
   2687       break;
   2688     }
   2689   }
   2690 
   2691   gBS->FreePool (OpenBuffer);
   2692   return Handle;
   2693 }
   2694 
   2695 /**
   2696   Convert one Null-terminated ASCII string (decimal dotted) to EFI_IPv4_ADDRESS.
   2697 
   2698   @param[in]      String         The pointer to the Ascii string.
   2699   @param[out]     Ip4Address     The pointer to the converted IPv4 address.
   2700 
   2701   @retval EFI_SUCCESS            Convert to IPv4 address successfully.
   2702   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip4Address is NULL.
   2703 
   2704 **/
   2705 EFI_STATUS
   2706 EFIAPI
   2707 NetLibAsciiStrToIp4 (
   2708   IN CONST CHAR8                 *String,
   2709   OUT      EFI_IPv4_ADDRESS      *Ip4Address
   2710   )
   2711 {
   2712   UINT8                          Index;
   2713   CHAR8                          *Ip4Str;
   2714   CHAR8                          *TempStr;
   2715   UINTN                          NodeVal;
   2716 
   2717   if ((String == NULL) || (Ip4Address == NULL)) {
   2718     return EFI_INVALID_PARAMETER;
   2719   }
   2720 
   2721   Ip4Str = (CHAR8 *) String;
   2722 
   2723   for (Index = 0; Index < 4; Index++) {
   2724     TempStr = Ip4Str;
   2725 
   2726     while ((*Ip4Str != '\0') && (*Ip4Str != '.')) {
   2727       if (Index != 3 && !NET_IS_DIGIT (*Ip4Str)) {
   2728         return EFI_INVALID_PARAMETER;
   2729       }
   2730 
   2731       //
   2732       // Allow the IPv4 with prefix case, e.g. 192.168.10.10/24
   2733       //
   2734       if (Index == 3 && !NET_IS_DIGIT (*Ip4Str) && *Ip4Str != '/') {
   2735         return EFI_INVALID_PARAMETER;
   2736       }
   2737 
   2738       Ip4Str++;
   2739     }
   2740 
   2741     //
   2742     // The IPv4 address is X.X.X.X
   2743     //
   2744     if (*Ip4Str == '.') {
   2745       if (Index == 3) {
   2746         return EFI_INVALID_PARAMETER;
   2747       }
   2748     } else {
   2749       if (Index != 3) {
   2750         return EFI_INVALID_PARAMETER;
   2751       }
   2752     }
   2753 
   2754     //
   2755     // Convert the string to IPv4 address. AsciiStrDecimalToUintn stops at the
   2756     // first character that is not a valid decimal character, '.' or '\0' here.
   2757     //
   2758     NodeVal = AsciiStrDecimalToUintn (TempStr);
   2759     if (NodeVal > 0xFF) {
   2760       return EFI_INVALID_PARAMETER;
   2761     }
   2762 
   2763     Ip4Address->Addr[Index] = (UINT8) NodeVal;
   2764 
   2765     Ip4Str++;
   2766   }
   2767 
   2768   return EFI_SUCCESS;
   2769 }
   2770 
   2771 
   2772 /**
   2773   Convert one Null-terminated ASCII string to EFI_IPv6_ADDRESS. The format of the
   2774   string is defined in RFC 4291 - Text Representation of Addresses.
   2775 
   2776   @param[in]      String         The pointer to the Ascii string.
   2777   @param[out]     Ip6Address     The pointer to the converted IPv6 address.
   2778 
   2779   @retval EFI_SUCCESS            Convert to IPv6 address successfully.
   2780   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip6Address is NULL.
   2781 
   2782 **/
   2783 EFI_STATUS
   2784 EFIAPI
   2785 NetLibAsciiStrToIp6 (
   2786   IN CONST CHAR8                 *String,
   2787   OUT      EFI_IPv6_ADDRESS      *Ip6Address
   2788   )
   2789 {
   2790   UINT8                          Index;
   2791   CHAR8                          *Ip6Str;
   2792   CHAR8                          *TempStr;
   2793   CHAR8                          *TempStr2;
   2794   UINT8                          NodeCnt;
   2795   UINT8                          TailNodeCnt;
   2796   UINT8                          AllowedCnt;
   2797   UINTN                          NodeVal;
   2798   BOOLEAN                        Short;
   2799   BOOLEAN                        Update;
   2800   BOOLEAN                        LeadZero;
   2801   UINT8                          LeadZeroCnt;
   2802   UINT8                          Cnt;
   2803 
   2804   if ((String == NULL) || (Ip6Address == NULL)) {
   2805     return EFI_INVALID_PARAMETER;
   2806   }
   2807 
   2808   Ip6Str      = (CHAR8 *) String;
   2809   AllowedCnt  = 6;
   2810   LeadZeroCnt = 0;
   2811 
   2812   //
   2813   // An IPv6 address leading with : looks strange.
   2814   //
   2815   if (*Ip6Str == ':') {
   2816     if (*(Ip6Str + 1) != ':') {
   2817       return EFI_INVALID_PARAMETER;
   2818     } else {
   2819       AllowedCnt = 7;
   2820     }
   2821   }
   2822 
   2823   ZeroMem (Ip6Address, sizeof (EFI_IPv6_ADDRESS));
   2824 
   2825   NodeCnt     = 0;
   2826   TailNodeCnt = 0;
   2827   Short       = FALSE;
   2828   Update      = FALSE;
   2829   LeadZero    = FALSE;
   2830 
   2831   for (Index = 0; Index < 15; Index = (UINT8) (Index + 2)) {
   2832     TempStr = Ip6Str;
   2833 
   2834     while ((*Ip6Str != '\0') && (*Ip6Str != ':')) {
   2835       if (Index != 14 && !NET_IS_HEX (*Ip6Str)) {
   2836         return EFI_INVALID_PARAMETER;
   2837       }
   2838 
   2839       //
   2840       // Allow the IPv6 with prefix case, e.g. 2000:aaaa::10/24
   2841       //
   2842       if (Index == 14 && !NET_IS_HEX (*Ip6Str) && *Ip6Str != '/') {
   2843         return EFI_INVALID_PARAMETER;
   2844       }
   2845 
   2846       Ip6Str++;
   2847     }
   2848 
   2849     if ((*Ip6Str == '\0') && (Index != 14)) {
   2850       return EFI_INVALID_PARAMETER;
   2851     }
   2852 
   2853     if (*Ip6Str == ':') {
   2854       if (*(Ip6Str + 1) == ':') {
   2855         if ((NodeCnt > 6) ||
   2856             ((*(Ip6Str + 2) != '\0') && (AsciiStrHexToUintn (Ip6Str + 2) == 0))) {
   2857           //
   2858           // ::0 looks strange. report error to user.
   2859           //
   2860           return EFI_INVALID_PARAMETER;
   2861         }
   2862         if ((NodeCnt == 6) && (*(Ip6Str + 2) != '\0') &&
   2863             (AsciiStrHexToUintn (Ip6Str + 2) != 0)) {
   2864           return EFI_INVALID_PARAMETER;
   2865         }
   2866 
   2867         //
   2868         // Skip the abbreviation part of IPv6 address.
   2869         //
   2870         TempStr2 = Ip6Str + 2;
   2871         while ((*TempStr2 != '\0')) {
   2872           if (*TempStr2 == ':') {
   2873             if (*(TempStr2 + 1) == ':') {
   2874               //
   2875               // :: can only appear once in IPv6 address.
   2876               //
   2877               return EFI_INVALID_PARAMETER;
   2878             }
   2879 
   2880             TailNodeCnt++;
   2881             if (TailNodeCnt >= (AllowedCnt - NodeCnt)) {
   2882               //
   2883               // :: indicates one or more groups of 16 bits of zeros.
   2884               //
   2885               return EFI_INVALID_PARAMETER;
   2886             }
   2887           }
   2888 
   2889           TempStr2++;
   2890         }
   2891 
   2892         Short  = TRUE;
   2893         Update = TRUE;
   2894 
   2895         Ip6Str = Ip6Str + 2;
   2896       } else {
   2897         if (*(Ip6Str + 1) == '\0') {
   2898           return EFI_INVALID_PARAMETER;
   2899         }
   2900         Ip6Str++;
   2901         NodeCnt++;
   2902         if ((Short && (NodeCnt > 6)) || (!Short && (NodeCnt > 7))) {
   2903           //
   2904           // There are more than 8 groups of 16 bits of zeros.
   2905           //
   2906           return EFI_INVALID_PARAMETER;
   2907         }
   2908       }
   2909     }
   2910 
   2911     //
   2912     // Convert the string to IPv6 address. AsciiStrHexToUintn stops at the first
   2913     // character that is not a valid hexadecimal character, ':' or '\0' here.
   2914     //
   2915     NodeVal = AsciiStrHexToUintn (TempStr);
   2916     if ((NodeVal > 0xFFFF) || (Index > 14)) {
   2917       return EFI_INVALID_PARAMETER;
   2918     }
   2919     if (NodeVal != 0) {
   2920       if ((*TempStr  == '0') &&
   2921           ((*(TempStr + 2) == ':') || (*(TempStr + 3) == ':') ||
   2922           (*(TempStr + 2) == '\0') || (*(TempStr + 3) == '\0'))) {
   2923         return EFI_INVALID_PARAMETER;
   2924       }
   2925       if ((*TempStr  == '0') && (*(TempStr + 4) != '\0') &&
   2926           (*(TempStr + 4) != ':')) {
   2927         return EFI_INVALID_PARAMETER;
   2928       }
   2929     } else {
   2930       if (((*TempStr  == '0') && (*(TempStr + 1) == '0') &&
   2931           ((*(TempStr + 2) == ':') || (*(TempStr + 2) == '\0'))) ||
   2932           ((*TempStr  == '0') && (*(TempStr + 1) == '0') && (*(TempStr + 2) == '0') &&
   2933           ((*(TempStr + 3) == ':') || (*(TempStr + 3) == '\0')))) {
   2934         return EFI_INVALID_PARAMETER;
   2935       }
   2936     }
   2937 
   2938     Cnt = 0;
   2939     while ((TempStr[Cnt] != ':') && (TempStr[Cnt] != '\0')) {
   2940       Cnt++;
   2941     }
   2942     if (LeadZeroCnt == 0) {
   2943       if ((Cnt == 4) && (*TempStr  == '0')) {
   2944         LeadZero = TRUE;
   2945         LeadZeroCnt++;
   2946       }
   2947       if ((Cnt != 0) && (Cnt < 4)) {
   2948         LeadZero = FALSE;
   2949         LeadZeroCnt++;
   2950       }
   2951     } else {
   2952       if ((Cnt == 4) && (*TempStr  == '0') && !LeadZero) {
   2953         return EFI_INVALID_PARAMETER;
   2954       }
   2955       if ((Cnt != 0) && (Cnt < 4) && LeadZero) {
   2956         return EFI_INVALID_PARAMETER;
   2957       }
   2958     }
   2959 
   2960     Ip6Address->Addr[Index] = (UINT8) (NodeVal >> 8);
   2961     Ip6Address->Addr[Index + 1] = (UINT8) (NodeVal & 0xFF);
   2962 
   2963     //
   2964     // Skip the groups of zeros by ::
   2965     //
   2966     if (Short && Update) {
   2967       Index  = (UINT8) (16 - (TailNodeCnt + 2) * 2);
   2968       Update = FALSE;
   2969     }
   2970   }
   2971 
   2972   if ((!Short && Index != 16) || (*Ip6Str != '\0')) {
   2973     return EFI_INVALID_PARAMETER;
   2974   }
   2975 
   2976   return EFI_SUCCESS;
   2977 }
   2978 
   2979 
   2980 /**
   2981   Convert one Null-terminated Unicode string (decimal dotted) to EFI_IPv4_ADDRESS.
   2982 
   2983   @param[in]      String         The pointer to the Ascii string.
   2984   @param[out]     Ip4Address     The pointer to the converted IPv4 address.
   2985 
   2986   @retval EFI_SUCCESS            Convert to IPv4 address successfully.
   2987   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip4Address is NULL.
   2988   @retval EFI_OUT_OF_RESOURCES   Fail to perform the operation due to lack of resource.
   2989 
   2990 **/
   2991 EFI_STATUS
   2992 EFIAPI
   2993 NetLibStrToIp4 (
   2994   IN CONST CHAR16                *String,
   2995   OUT      EFI_IPv4_ADDRESS      *Ip4Address
   2996   )
   2997 {
   2998   CHAR8                          *Ip4Str;
   2999   UINTN                          StringSize;
   3000   EFI_STATUS                     Status;
   3001 
   3002   if ((String == NULL) || (Ip4Address == NULL)) {
   3003     return EFI_INVALID_PARAMETER;
   3004   }
   3005 
   3006   StringSize = StrLen (String) + 1;
   3007   Ip4Str = (CHAR8 *) AllocatePool (StringSize * sizeof (CHAR8));
   3008   if (Ip4Str == NULL) {
   3009     return EFI_OUT_OF_RESOURCES;
   3010   }
   3011 
   3012   UnicodeStrToAsciiStrS (String, Ip4Str, StringSize);
   3013 
   3014   Status = NetLibAsciiStrToIp4 (Ip4Str, Ip4Address);
   3015 
   3016   FreePool (Ip4Str);
   3017 
   3018   return Status;
   3019 }
   3020 
   3021 
   3022 /**
   3023   Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS.  The format of
   3024   the string is defined in RFC 4291 - Text Representation of Addresses.
   3025 
   3026   @param[in]      String         The pointer to the Ascii string.
   3027   @param[out]     Ip6Address     The pointer to the converted IPv6 address.
   3028 
   3029   @retval EFI_SUCCESS            Convert to IPv6 address successfully.
   3030   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip6Address is NULL.
   3031   @retval EFI_OUT_OF_RESOURCES   Fail to perform the operation due to lack of resource.
   3032 
   3033 **/
   3034 EFI_STATUS
   3035 EFIAPI
   3036 NetLibStrToIp6 (
   3037   IN CONST CHAR16                *String,
   3038   OUT      EFI_IPv6_ADDRESS      *Ip6Address
   3039   )
   3040 {
   3041   CHAR8                          *Ip6Str;
   3042   UINTN                          StringSize;
   3043   EFI_STATUS                     Status;
   3044 
   3045   if ((String == NULL) || (Ip6Address == NULL)) {
   3046     return EFI_INVALID_PARAMETER;
   3047   }
   3048 
   3049   StringSize = StrLen (String) + 1;
   3050   Ip6Str = (CHAR8 *) AllocatePool (StringSize * sizeof (CHAR8));
   3051   if (Ip6Str == NULL) {
   3052     return EFI_OUT_OF_RESOURCES;
   3053   }
   3054 
   3055   UnicodeStrToAsciiStrS (String, Ip6Str, StringSize);
   3056 
   3057   Status = NetLibAsciiStrToIp6 (Ip6Str, Ip6Address);
   3058 
   3059   FreePool (Ip6Str);
   3060 
   3061   return Status;
   3062 }
   3063 
   3064 /**
   3065   Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS and prefix length.
   3066   The format of the string is defined in RFC 4291 - Text Representation of Addresses
   3067   Prefixes: ipv6-address/prefix-length.
   3068 
   3069   @param[in]      String         The pointer to the Ascii string.
   3070   @param[out]     Ip6Address     The pointer to the converted IPv6 address.
   3071   @param[out]     PrefixLength   The pointer to the converted prefix length.
   3072 
   3073   @retval EFI_SUCCESS            Convert to IPv6 address successfully.
   3074   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip6Address is NULL.
   3075   @retval EFI_OUT_OF_RESOURCES   Fail to perform the operation due to lack of resource.
   3076 
   3077 **/
   3078 EFI_STATUS
   3079 EFIAPI
   3080 NetLibStrToIp6andPrefix (
   3081   IN CONST CHAR16                *String,
   3082   OUT      EFI_IPv6_ADDRESS      *Ip6Address,
   3083   OUT      UINT8                 *PrefixLength
   3084   )
   3085 {
   3086   CHAR8                          *Ip6Str;
   3087   UINTN                          StringSize;
   3088   CHAR8                          *PrefixStr;
   3089   CHAR8                          *TempStr;
   3090   EFI_STATUS                     Status;
   3091   UINT8                          Length;
   3092 
   3093   if ((String == NULL) || (Ip6Address == NULL) || (PrefixLength == NULL)) {
   3094     return EFI_INVALID_PARAMETER;
   3095   }
   3096 
   3097   StringSize = StrLen (String) + 1;
   3098   Ip6Str = (CHAR8 *) AllocatePool (StringSize * sizeof (CHAR8));
   3099   if (Ip6Str == NULL) {
   3100     return EFI_OUT_OF_RESOURCES;
   3101   }
   3102 
   3103   UnicodeStrToAsciiStrS (String, Ip6Str, StringSize);
   3104 
   3105   //
   3106   // Get the sub string describing prefix length.
   3107   //
   3108   TempStr = Ip6Str;
   3109   while (*TempStr != '\0' && (*TempStr != '/')) {
   3110     TempStr++;
   3111   }
   3112 
   3113   if (*TempStr == '/') {
   3114     PrefixStr = TempStr + 1;
   3115   } else {
   3116     PrefixStr = NULL;
   3117   }
   3118 
   3119   //
   3120   // Get the sub string describing IPv6 address and convert it.
   3121   //
   3122   *TempStr = '\0';
   3123 
   3124   Status = NetLibAsciiStrToIp6 (Ip6Str, Ip6Address);
   3125   if (EFI_ERROR (Status)) {
   3126     goto Exit;
   3127   }
   3128 
   3129   //
   3130   // If input string doesn't indicate the prefix length, return 0xff.
   3131   //
   3132   Length = 0xFF;
   3133 
   3134   //
   3135   // Convert the string to prefix length
   3136   //
   3137   if (PrefixStr != NULL) {
   3138 
   3139     Status = EFI_INVALID_PARAMETER;
   3140     Length = 0;
   3141     while (*PrefixStr != '\0') {
   3142       if (NET_IS_DIGIT (*PrefixStr)) {
   3143         Length = (UINT8) (Length * 10 + (*PrefixStr - '0'));
   3144         if (Length > IP6_PREFIX_MAX) {
   3145           goto Exit;
   3146         }
   3147       } else {
   3148         goto Exit;
   3149       }
   3150 
   3151       PrefixStr++;
   3152     }
   3153   }
   3154 
   3155   *PrefixLength = Length;
   3156   Status        = EFI_SUCCESS;
   3157 
   3158 Exit:
   3159 
   3160   FreePool (Ip6Str);
   3161   return Status;
   3162 }
   3163 
   3164 /**
   3165 
   3166   Convert one EFI_IPv6_ADDRESS to Null-terminated Unicode string.
   3167   The text representation of address is defined in RFC 4291.
   3168 
   3169   @param[in]       Ip6Address     The pointer to the IPv6 address.
   3170   @param[out]      String         The buffer to return the converted string.
   3171   @param[in]       StringSize     The length in bytes of the input String.
   3172 
   3173   @retval EFI_SUCCESS             Convert to string successfully.
   3174   @retval EFI_INVALID_PARAMETER   The input parameter is invalid.
   3175   @retval EFI_BUFFER_TOO_SMALL    The BufferSize is too small for the result. BufferSize has been
   3176                                   updated with the size needed to complete the request.
   3177 **/
   3178 EFI_STATUS
   3179 EFIAPI
   3180 NetLibIp6ToStr (
   3181   IN         EFI_IPv6_ADDRESS      *Ip6Address,
   3182   OUT        CHAR16                *String,
   3183   IN         UINTN                 StringSize
   3184   )
   3185 {
   3186   UINT16     Ip6Addr[8];
   3187   UINTN      Index;
   3188   UINTN      LongestZerosStart;
   3189   UINTN      LongestZerosLength;
   3190   UINTN      CurrentZerosStart;
   3191   UINTN      CurrentZerosLength;
   3192   CHAR16     Buffer[sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
   3193   CHAR16     *Ptr;
   3194 
   3195   if (Ip6Address == NULL || String == NULL || StringSize == 0) {
   3196     return EFI_INVALID_PARAMETER;
   3197   }
   3198 
   3199   //
   3200   // Convert the UINT8 array to an UINT16 array for easy handling.
   3201   //
   3202   ZeroMem (Ip6Addr, sizeof (Ip6Addr));
   3203   for (Index = 0; Index < 16; Index++) {
   3204     Ip6Addr[Index / 2] |= (Ip6Address->Addr[Index] << ((1 - (Index % 2)) << 3));
   3205   }
   3206 
   3207   //
   3208   // Find the longest zeros and mark it.
   3209   //
   3210   CurrentZerosStart  = DEFAULT_ZERO_START;
   3211   CurrentZerosLength = 0;
   3212   LongestZerosStart  = DEFAULT_ZERO_START;
   3213   LongestZerosLength = 0;
   3214   for (Index = 0; Index < 8; Index++) {
   3215     if (Ip6Addr[Index] == 0) {
   3216       if (CurrentZerosStart == DEFAULT_ZERO_START) {
   3217         CurrentZerosStart = Index;
   3218         CurrentZerosLength = 1;
   3219       } else {
   3220         CurrentZerosLength++;
   3221       }
   3222     } else {
   3223       if (CurrentZerosStart != DEFAULT_ZERO_START) {
   3224         if (CurrentZerosLength > 2 && (LongestZerosStart == (DEFAULT_ZERO_START) || CurrentZerosLength > LongestZerosLength)) {
   3225           LongestZerosStart  = CurrentZerosStart;
   3226           LongestZerosLength = CurrentZerosLength;
   3227         }
   3228         CurrentZerosStart  = DEFAULT_ZERO_START;
   3229         CurrentZerosLength = 0;
   3230       }
   3231     }
   3232   }
   3233 
   3234   if (CurrentZerosStart != DEFAULT_ZERO_START && CurrentZerosLength > 2) {
   3235     if (LongestZerosStart == DEFAULT_ZERO_START || LongestZerosLength < CurrentZerosLength) {
   3236       LongestZerosStart  = CurrentZerosStart;
   3237       LongestZerosLength = CurrentZerosLength;
   3238     }
   3239   }
   3240 
   3241   Ptr = Buffer;
   3242   for (Index = 0; Index < 8; Index++) {
   3243     if (LongestZerosStart != DEFAULT_ZERO_START && Index >= LongestZerosStart && Index < LongestZerosStart + LongestZerosLength) {
   3244       if (Index == LongestZerosStart) {
   3245         *Ptr++ = L':';
   3246       }
   3247       continue;
   3248     }
   3249     if (Index != 0) {
   3250       *Ptr++ = L':';
   3251     }
   3252     Ptr += UnicodeSPrint(Ptr, 10, L"%x", Ip6Addr[Index]);
   3253   }
   3254 
   3255   if (LongestZerosStart != DEFAULT_ZERO_START && LongestZerosStart + LongestZerosLength == 8) {
   3256     *Ptr++ = L':';
   3257   }
   3258   *Ptr = L'\0';
   3259 
   3260   if ((UINTN)Ptr - (UINTN)Buffer > StringSize) {
   3261     return EFI_BUFFER_TOO_SMALL;
   3262   }
   3263 
   3264   StrCpyS (String, StringSize / sizeof (CHAR16), Buffer);
   3265 
   3266   return EFI_SUCCESS;
   3267 }
   3268 
   3269 /**
   3270   This function obtains the system guid from the smbios table.
   3271 
   3272   @param[out]  SystemGuid     The pointer of the returned system guid.
   3273 
   3274   @retval EFI_SUCCESS         Successfully obtained the system guid.
   3275   @retval EFI_NOT_FOUND       Did not find the SMBIOS table.
   3276 
   3277 **/
   3278 EFI_STATUS
   3279 EFIAPI
   3280 NetLibGetSystemGuid (
   3281   OUT EFI_GUID              *SystemGuid
   3282   )
   3283 {
   3284   EFI_STATUS                    Status;
   3285   SMBIOS_TABLE_ENTRY_POINT      *SmbiosTable;
   3286   SMBIOS_TABLE_3_0_ENTRY_POINT  *Smbios30Table;
   3287   SMBIOS_STRUCTURE_POINTER      Smbios;
   3288   SMBIOS_STRUCTURE_POINTER      SmbiosEnd;
   3289   CHAR8                         *String;
   3290 
   3291   SmbiosTable = NULL;
   3292   Status = EfiGetSystemConfigurationTable (&gEfiSmbios3TableGuid, (VOID **) &Smbios30Table);
   3293   if (!(EFI_ERROR (Status) || Smbios30Table == NULL)) {
   3294     Smbios.Hdr = (SMBIOS_STRUCTURE *) (UINTN) Smbios30Table->TableAddress;
   3295     SmbiosEnd.Raw = (UINT8 *) (UINTN) (Smbios30Table->TableAddress + Smbios30Table->TableMaximumSize);
   3296   } else {
   3297     Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SmbiosTable);
   3298     if (EFI_ERROR (Status) || SmbiosTable == NULL) {
   3299       return EFI_NOT_FOUND;
   3300     }
   3301     Smbios.Hdr    = (SMBIOS_STRUCTURE *) (UINTN) SmbiosTable->TableAddress;
   3302     SmbiosEnd.Raw = (UINT8 *) (UINTN) (SmbiosTable->TableAddress + SmbiosTable->TableLength);
   3303   }
   3304 
   3305   do {
   3306     if (Smbios.Hdr->Type == 1) {
   3307       if (Smbios.Hdr->Length < 0x19) {
   3308         //
   3309         // Older version did not support UUID.
   3310         //
   3311         return EFI_NOT_FOUND;
   3312       }
   3313 
   3314       //
   3315       // SMBIOS tables are byte packed so we need to do a byte copy to
   3316       // prevend alignment faults on Itanium-based platform.
   3317       //
   3318       CopyMem (SystemGuid, &Smbios.Type1->Uuid, sizeof (EFI_GUID));
   3319       return EFI_SUCCESS;
   3320     }
   3321 
   3322     //
   3323     // Go to the next SMBIOS structure. Each SMBIOS structure may include 2 parts:
   3324     // 1. Formatted section; 2. Unformatted string section. So, 2 steps are needed
   3325     // to skip one SMBIOS structure.
   3326     //
   3327 
   3328     //
   3329     // Step 1: Skip over formatted section.
   3330     //
   3331     String = (CHAR8 *) (Smbios.Raw + Smbios.Hdr->Length);
   3332 
   3333     //
   3334     // Step 2: Skip over unformated string section.
   3335     //
   3336     do {
   3337       //
   3338       // Each string is terminated with a NULL(00h) BYTE and the sets of strings
   3339       // is terminated with an additional NULL(00h) BYTE.
   3340       //
   3341       for ( ; *String != 0; String++) {
   3342       }
   3343 
   3344       if (*(UINT8*)++String == 0) {
   3345         //
   3346         // Pointer to the next SMBIOS structure.
   3347         //
   3348         Smbios.Raw = (UINT8 *)++String;
   3349         break;
   3350       }
   3351     } while (TRUE);
   3352   } while (Smbios.Raw < SmbiosEnd.Raw);
   3353   return EFI_NOT_FOUND;
   3354 }
   3355 
   3356 /**
   3357   Create Dns QName according the queried domain name.
   3358   QName is a domain name represented as a sequence of labels,
   3359   where each label consists of a length octet followed by that
   3360   number of octets. The QName terminates with the zero
   3361   length octet for the null label of the root. Caller should
   3362   take responsibility to free the buffer in returned pointer.
   3363 
   3364   @param  DomainName    The pointer to the queried domain name string.
   3365 
   3366   @retval NULL          Failed to fill QName.
   3367   @return               QName filled successfully.
   3368 
   3369 **/
   3370 CHAR8 *
   3371 EFIAPI
   3372 NetLibCreateDnsQName (
   3373   IN  CHAR16              *DomainName
   3374   )
   3375 {
   3376   CHAR8                 *QueryName;
   3377   UINTN                 QueryNameSize;
   3378   CHAR8                 *Header;
   3379   CHAR8                 *Tail;
   3380   UINTN                 Len;
   3381   UINTN                 Index;
   3382 
   3383   QueryName     = NULL;
   3384   QueryNameSize = 0;
   3385   Header        = NULL;
   3386   Tail          = NULL;
   3387 
   3388   //
   3389   // One byte for first label length, one byte for terminated length zero.
   3390   //
   3391   QueryNameSize = StrLen (DomainName) + 2;
   3392 
   3393   if (QueryNameSize > DNS_MAX_NAME_SIZE) {
   3394     return NULL;
   3395   }
   3396 
   3397   QueryName = AllocateZeroPool (QueryNameSize);
   3398   if (QueryName == NULL) {
   3399     return NULL;
   3400   }
   3401 
   3402   Header = QueryName;
   3403   Tail = Header + 1;
   3404   Len = 0;
   3405   for (Index = 0; DomainName[Index] != 0; Index++) {
   3406     *Tail = (CHAR8) DomainName[Index];
   3407     if (*Tail == '.') {
   3408       *Header = (CHAR8) Len;
   3409       Header = Tail;
   3410       Tail ++;
   3411       Len = 0;
   3412     } else {
   3413       Tail++;
   3414       Len++;
   3415     }
   3416   }
   3417   *Header = (CHAR8) Len;
   3418   *Tail = 0;
   3419 
   3420   return QueryName;
   3421 }
   3422