Home | History | Annotate | Download | only in DxeNetLib
      1 /** @file
      2   Network library.
      3 
      4 Copyright (c) 2005 - 2015, 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 servity 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 servity 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_NUM; 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   The address of class A  starts with 0.
    584   If the address belong to class A, return IP4_ADDR_CLASSA.
    585   The address of class B  starts with 10.
    586   If the address belong to class B, return IP4_ADDR_CLASSB.
    587   The address of class C  starts with 110.
    588   If the address belong to class C, return IP4_ADDR_CLASSC.
    589   The address of class D  starts with 1110.
    590   If the address belong to class D, return IP4_ADDR_CLASSD.
    591   The address of class E  starts with 1111.
    592   If the address belong to class E, return IP4_ADDR_CLASSE.
    593 
    594 
    595   @param[in]   Addr                  The address to get the class from.
    596 
    597   @return IP address class, such as IP4_ADDR_CLASSA.
    598 
    599 **/
    600 INTN
    601 EFIAPI
    602 NetGetIpClass (
    603   IN IP4_ADDR               Addr
    604   )
    605 {
    606   UINT8                     ByteOne;
    607 
    608   ByteOne = (UINT8) (Addr >> 24);
    609 
    610   if ((ByteOne & 0x80) == 0) {
    611     return IP4_ADDR_CLASSA;
    612 
    613   } else if ((ByteOne & 0xC0) == 0x80) {
    614     return IP4_ADDR_CLASSB;
    615 
    616   } else if ((ByteOne & 0xE0) == 0xC0) {
    617     return IP4_ADDR_CLASSC;
    618 
    619   } else if ((ByteOne & 0xF0) == 0xE0) {
    620     return IP4_ADDR_CLASSD;
    621 
    622   } else {
    623     return IP4_ADDR_CLASSE;
    624 
    625   }
    626 }
    627 
    628 
    629 /**
    630   Check whether the IP is a valid unicast address according to
    631   the netmask. If NetMask is zero, use the IP address's class to get the default mask.
    632 
    633   If Ip is 0, IP is not a valid unicast address.
    634   Class D address is used for multicasting and class E address is reserved for future. If Ip
    635   belongs to class D or class E, IP is not a valid unicast address.
    636   If all bits of the host address of IP are 0 or 1, IP is also not a valid unicast address.
    637 
    638   @param[in]  Ip                    The IP to check against.
    639   @param[in]  NetMask               The mask of the IP.
    640 
    641   @return TRUE if IP is a valid unicast address on the network, otherwise FALSE.
    642 
    643 **/
    644 BOOLEAN
    645 EFIAPI
    646 NetIp4IsUnicast (
    647   IN IP4_ADDR               Ip,
    648   IN IP4_ADDR               NetMask
    649   )
    650 {
    651   INTN                      Class;
    652 
    653   Class = NetGetIpClass (Ip);
    654 
    655   if ((Ip == 0) || (Class >= IP4_ADDR_CLASSD)) {
    656     return FALSE;
    657   }
    658 
    659   if (NetMask == 0) {
    660     NetMask = gIp4AllMasks[Class << 3];
    661   }
    662 
    663   if (((Ip &~NetMask) == ~NetMask) || ((Ip &~NetMask) == 0)) {
    664     return FALSE;
    665   }
    666 
    667   return TRUE;
    668 }
    669 
    670 /**
    671   Check whether the incoming IPv6 address is a valid unicast address.
    672 
    673   If the address is a multicast address has binary 0xFF at the start, it is not
    674   a valid unicast address. If the address is unspecified ::, it is not a valid
    675   unicast address to be assigned to any node. If the address is loopback address
    676   ::1, it is also not a valid unicast address to be assigned to any physical
    677   interface.
    678 
    679   @param[in]  Ip6                   The IPv6 address to check against.
    680 
    681   @return TRUE if Ip6 is a valid unicast address on the network, otherwise FALSE.
    682 
    683 **/
    684 BOOLEAN
    685 EFIAPI
    686 NetIp6IsValidUnicast (
    687   IN EFI_IPv6_ADDRESS       *Ip6
    688   )
    689 {
    690   UINT8 Byte;
    691   UINT8 Index;
    692 
    693   if (Ip6->Addr[0] == 0xFF) {
    694     return FALSE;
    695   }
    696 
    697   for (Index = 0; Index < 15; Index++) {
    698     if (Ip6->Addr[Index] != 0) {
    699       return TRUE;
    700     }
    701   }
    702 
    703   Byte = Ip6->Addr[Index];
    704 
    705   if (Byte == 0x0 || Byte == 0x1) {
    706     return FALSE;
    707   }
    708 
    709   return TRUE;
    710 }
    711 
    712 /**
    713   Check whether the incoming Ipv6 address is the unspecified address or not.
    714 
    715   @param[in] Ip6   - Ip6 address, in network order.
    716 
    717   @retval TRUE     - Yes, unspecified
    718   @retval FALSE    - No
    719 
    720 **/
    721 BOOLEAN
    722 EFIAPI
    723 NetIp6IsUnspecifiedAddr (
    724   IN EFI_IPv6_ADDRESS       *Ip6
    725   )
    726 {
    727   UINT8 Index;
    728 
    729   for (Index = 0; Index < 16; Index++) {
    730     if (Ip6->Addr[Index] != 0) {
    731       return FALSE;
    732     }
    733   }
    734 
    735   return TRUE;
    736 }
    737 
    738 /**
    739   Check whether the incoming Ipv6 address is a link-local address.
    740 
    741   @param[in] Ip6   - Ip6 address, in network order.
    742 
    743   @retval TRUE  - Yes, link-local address
    744   @retval FALSE - No
    745 
    746 **/
    747 BOOLEAN
    748 EFIAPI
    749 NetIp6IsLinkLocalAddr (
    750   IN EFI_IPv6_ADDRESS *Ip6
    751   )
    752 {
    753   UINT8 Index;
    754 
    755   ASSERT (Ip6 != NULL);
    756 
    757   if (Ip6->Addr[0] != 0xFE) {
    758     return FALSE;
    759   }
    760 
    761   if (Ip6->Addr[1] != 0x80) {
    762     return FALSE;
    763   }
    764 
    765   for (Index = 2; Index < 8; Index++) {
    766     if (Ip6->Addr[Index] != 0) {
    767       return FALSE;
    768     }
    769   }
    770 
    771   return TRUE;
    772 }
    773 
    774 /**
    775   Check whether the Ipv6 address1 and address2 are on the connected network.
    776 
    777   @param[in] Ip1          - Ip6 address1, in network order.
    778   @param[in] Ip2          - Ip6 address2, in network order.
    779   @param[in] PrefixLength - The prefix length of the checking net.
    780 
    781   @retval TRUE            - Yes, connected.
    782   @retval FALSE           - No.
    783 
    784 **/
    785 BOOLEAN
    786 EFIAPI
    787 NetIp6IsNetEqual (
    788   EFI_IPv6_ADDRESS *Ip1,
    789   EFI_IPv6_ADDRESS *Ip2,
    790   UINT8            PrefixLength
    791   )
    792 {
    793   UINT8 Byte;
    794   UINT8 Bit;
    795   UINT8 Mask;
    796 
    797   ASSERT ((Ip1 != NULL) && (Ip2 != NULL) && (PrefixLength < IP6_PREFIX_NUM));
    798 
    799   if (PrefixLength == 0) {
    800     return TRUE;
    801   }
    802 
    803   Byte = (UINT8) (PrefixLength / 8);
    804   Bit  = (UINT8) (PrefixLength % 8);
    805 
    806   if (CompareMem (Ip1, Ip2, Byte) != 0) {
    807     return FALSE;
    808   }
    809 
    810   if (Bit > 0) {
    811     Mask = (UINT8) (0xFF << (8 - Bit));
    812 
    813     ASSERT (Byte < 16);
    814     if ((Ip1->Addr[Byte] & Mask) != (Ip2->Addr[Byte] & Mask)) {
    815       return FALSE;
    816     }
    817   }
    818 
    819   return TRUE;
    820 }
    821 
    822 
    823 /**
    824   Switches the endianess of an IPv6 address
    825 
    826   This function swaps the bytes in a 128-bit IPv6 address to switch the value
    827   from little endian to big endian or vice versa. The byte swapped value is
    828   returned.
    829 
    830   @param  Ip6 Points to an IPv6 address
    831 
    832   @return The byte swapped IPv6 address.
    833 
    834 **/
    835 EFI_IPv6_ADDRESS *
    836 EFIAPI
    837 Ip6Swap128 (
    838   EFI_IPv6_ADDRESS *Ip6
    839   )
    840 {
    841   UINT64 High;
    842   UINT64 Low;
    843 
    844   CopyMem (&High, Ip6, sizeof (UINT64));
    845   CopyMem (&Low, &Ip6->Addr[8], sizeof (UINT64));
    846 
    847   High = SwapBytes64 (High);
    848   Low  = SwapBytes64 (Low);
    849 
    850   CopyMem (Ip6, &Low, sizeof (UINT64));
    851   CopyMem (&Ip6->Addr[8], &High, sizeof (UINT64));
    852 
    853   return Ip6;
    854 }
    855 
    856 /**
    857   Initialize a random seed using current time and monotonic count.
    858 
    859   Get current time and monotonic count first. Then initialize a random seed
    860   based on some basic mathematics operation on the hour, day, minute, second,
    861   nanosecond and year of the current time and the monotonic count value.
    862 
    863   @return The random seed initialized with current time.
    864 
    865 **/
    866 UINT32
    867 EFIAPI
    868 NetRandomInitSeed (
    869   VOID
    870   )
    871 {
    872   EFI_TIME                  Time;
    873   UINT32                    Seed;
    874   UINT64                    MonotonicCount;
    875 
    876   gRT->GetTime (&Time, NULL);
    877   Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second);
    878   Seed ^= Time.Nanosecond;
    879   Seed ^= Time.Year << 7;
    880 
    881   gBS->GetNextMonotonicCount (&MonotonicCount);
    882   Seed += (UINT32) MonotonicCount;
    883 
    884   return Seed;
    885 }
    886 
    887 
    888 /**
    889   Extract a UINT32 from a byte stream.
    890 
    891   Copy a UINT32 from a byte stream, then converts it from Network
    892   byte order to host byte order. Use this function to avoid alignment error.
    893 
    894   @param[in]  Buf                 The buffer to extract the UINT32.
    895 
    896   @return The UINT32 extracted.
    897 
    898 **/
    899 UINT32
    900 EFIAPI
    901 NetGetUint32 (
    902   IN UINT8                  *Buf
    903   )
    904 {
    905   UINT32                    Value;
    906 
    907   CopyMem (&Value, Buf, sizeof (UINT32));
    908   return NTOHL (Value);
    909 }
    910 
    911 
    912 /**
    913   Put a UINT32 to the byte stream in network byte order.
    914 
    915   Converts a UINT32 from host byte order to network byte order. Then copy it to the
    916   byte stream.
    917 
    918   @param[in, out]  Buf          The buffer to put the UINT32.
    919   @param[in]       Data         The data to be converted and put into the byte stream.
    920 
    921 **/
    922 VOID
    923 EFIAPI
    924 NetPutUint32 (
    925   IN OUT UINT8                 *Buf,
    926   IN     UINT32                Data
    927   )
    928 {
    929   Data = HTONL (Data);
    930   CopyMem (Buf, &Data, sizeof (UINT32));
    931 }
    932 
    933 
    934 /**
    935   Remove the first node entry on the list, and return the removed node entry.
    936 
    937   Removes the first node Entry from a doubly linked list. It is up to the caller of
    938   this function to release the memory used by the first node if that is required. On
    939   exit, the removed node is returned.
    940 
    941   If Head is NULL, then ASSERT().
    942   If Head was not initialized, then ASSERT().
    943   If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
    944   linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
    945   then ASSERT().
    946 
    947   @param[in, out]  Head                  The list header.
    948 
    949   @return The first node entry that is removed from the list, NULL if the list is empty.
    950 
    951 **/
    952 LIST_ENTRY *
    953 EFIAPI
    954 NetListRemoveHead (
    955   IN OUT LIST_ENTRY            *Head
    956   )
    957 {
    958   LIST_ENTRY            *First;
    959 
    960   ASSERT (Head != NULL);
    961 
    962   if (IsListEmpty (Head)) {
    963     return NULL;
    964   }
    965 
    966   First                         = Head->ForwardLink;
    967   Head->ForwardLink             = First->ForwardLink;
    968   First->ForwardLink->BackLink  = Head;
    969 
    970   DEBUG_CODE (
    971     First->ForwardLink  = (LIST_ENTRY *) NULL;
    972     First->BackLink     = (LIST_ENTRY *) NULL;
    973   );
    974 
    975   return First;
    976 }
    977 
    978 
    979 /**
    980   Remove the last node entry on the list and and return the removed node entry.
    981 
    982   Removes the last node entry from a doubly linked list. It is up to the caller of
    983   this function to release the memory used by the first node if that is required. On
    984   exit, the removed node is returned.
    985 
    986   If Head is NULL, then ASSERT().
    987   If Head was not initialized, then ASSERT().
    988   If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
    989   linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
    990   then ASSERT().
    991 
    992   @param[in, out]  Head                  The list head.
    993 
    994   @return The last node entry that is removed from the list, NULL if the list is empty.
    995 
    996 **/
    997 LIST_ENTRY *
    998 EFIAPI
    999 NetListRemoveTail (
   1000   IN OUT LIST_ENTRY            *Head
   1001   )
   1002 {
   1003   LIST_ENTRY            *Last;
   1004 
   1005   ASSERT (Head != NULL);
   1006 
   1007   if (IsListEmpty (Head)) {
   1008     return NULL;
   1009   }
   1010 
   1011   Last                        = Head->BackLink;
   1012   Head->BackLink              = Last->BackLink;
   1013   Last->BackLink->ForwardLink = Head;
   1014 
   1015   DEBUG_CODE (
   1016     Last->ForwardLink = (LIST_ENTRY *) NULL;
   1017     Last->BackLink    = (LIST_ENTRY *) NULL;
   1018   );
   1019 
   1020   return Last;
   1021 }
   1022 
   1023 
   1024 /**
   1025   Insert a new node entry after a designated node entry of a doubly linked list.
   1026 
   1027   Inserts a new node entry donated by NewEntry after the node entry donated by PrevEntry
   1028   of the doubly linked list.
   1029 
   1030   @param[in, out]  PrevEntry             The previous entry to insert after.
   1031   @param[in, out]  NewEntry              The new entry to insert.
   1032 
   1033 **/
   1034 VOID
   1035 EFIAPI
   1036 NetListInsertAfter (
   1037   IN OUT LIST_ENTRY         *PrevEntry,
   1038   IN OUT LIST_ENTRY         *NewEntry
   1039   )
   1040 {
   1041   NewEntry->BackLink                = PrevEntry;
   1042   NewEntry->ForwardLink             = PrevEntry->ForwardLink;
   1043   PrevEntry->ForwardLink->BackLink  = NewEntry;
   1044   PrevEntry->ForwardLink            = NewEntry;
   1045 }
   1046 
   1047 
   1048 /**
   1049   Insert a new node entry before a designated node entry of a doubly linked list.
   1050 
   1051   Inserts a new node entry donated by NewEntry after the node entry donated by PostEntry
   1052   of the doubly linked list.
   1053 
   1054   @param[in, out]  PostEntry             The entry to insert before.
   1055   @param[in, out]  NewEntry              The new entry to insert.
   1056 
   1057 **/
   1058 VOID
   1059 EFIAPI
   1060 NetListInsertBefore (
   1061   IN OUT LIST_ENTRY     *PostEntry,
   1062   IN OUT LIST_ENTRY     *NewEntry
   1063   )
   1064 {
   1065   NewEntry->ForwardLink             = PostEntry;
   1066   NewEntry->BackLink                = PostEntry->BackLink;
   1067   PostEntry->BackLink->ForwardLink  = NewEntry;
   1068   PostEntry->BackLink               = NewEntry;
   1069 }
   1070 
   1071 /**
   1072   Safe destroy nodes in a linked list, and return the length of the list after all possible operations finished.
   1073 
   1074   Destroy network child instance list by list traversals is not safe due to graph dependencies between nodes.
   1075   This function performs a safe traversal to destroy these nodes by checking to see if the node being destroyed
   1076   has been removed from the list or not.
   1077   If it has been removed, then restart the traversal from the head.
   1078   If it hasn't been removed, then continue with the next node directly.
   1079   This function will end the iterate and return the CallBack's last return value if error happens,
   1080   or retrun EFI_SUCCESS if 2 complete passes are made with no changes in the number of children in the list.
   1081 
   1082   @param[in]    List             The head of the list.
   1083   @param[in]    CallBack         Pointer to the callback function to destroy one node in the list.
   1084   @param[in]    Context          Pointer to the callback function's context: corresponds to the
   1085                                  parameter Context in NET_DESTROY_LINK_LIST_CALLBACK.
   1086   @param[out]   ListLength       The length of the link list if the function returns successfully.
   1087 
   1088   @retval EFI_SUCCESS            Two complete passes are made with no changes in the number of children.
   1089   @retval EFI_INVALID_PARAMETER  The input parameter is invalid.
   1090   @retval Others                 Return the CallBack's last return value.
   1091 
   1092 **/
   1093 EFI_STATUS
   1094 EFIAPI
   1095 NetDestroyLinkList (
   1096   IN   LIST_ENTRY                       *List,
   1097   IN   NET_DESTROY_LINK_LIST_CALLBACK   CallBack,
   1098   IN   VOID                             *Context,    OPTIONAL
   1099   OUT  UINTN                            *ListLength  OPTIONAL
   1100   )
   1101 {
   1102   UINTN                         PreviousLength;
   1103   LIST_ENTRY                    *Entry;
   1104   LIST_ENTRY                    *Ptr;
   1105   UINTN                         Length;
   1106   EFI_STATUS                    Status;
   1107 
   1108   if (List == NULL || CallBack == NULL) {
   1109     return EFI_INVALID_PARAMETER;
   1110   }
   1111 
   1112   Length = 0;
   1113   do {
   1114     PreviousLength = Length;
   1115     Entry = GetFirstNode (List);
   1116     while (!IsNull (List, Entry)) {
   1117       Status = CallBack (Entry, Context);
   1118       if (EFI_ERROR (Status)) {
   1119         return Status;
   1120       }
   1121       //
   1122       // Walk through the list to see whether the Entry has been removed or not.
   1123       // If the Entry still exists, just try to destroy the next one.
   1124       // If not, go back to the start point to iterate the list again.
   1125       //
   1126       for (Ptr = List->ForwardLink; Ptr != List; Ptr = Ptr->ForwardLink) {
   1127         if (Ptr == Entry) {
   1128           break;
   1129         }
   1130       }
   1131       if (Ptr == Entry) {
   1132         Entry = GetNextNode (List, Entry);
   1133       } else {
   1134         Entry = GetFirstNode (List);
   1135       }
   1136     }
   1137     for (Length = 0, Ptr = List->ForwardLink; Ptr != List; Length++, Ptr = Ptr->ForwardLink);
   1138   } while (Length != PreviousLength);
   1139 
   1140   if (ListLength != NULL) {
   1141     *ListLength = Length;
   1142   }
   1143   return EFI_SUCCESS;
   1144 }
   1145 
   1146 /**
   1147   This function checks the input Handle to see if it's one of these handles in ChildHandleBuffer.
   1148 
   1149   @param[in]  Handle             Handle to be checked.
   1150   @param[in]  NumberOfChildren   Number of Handles in ChildHandleBuffer.
   1151   @param[in]  ChildHandleBuffer  An array of child handles to be freed. May be NULL
   1152                                  if NumberOfChildren is 0.
   1153 
   1154   @retval TURE                   Found the input Handle in ChildHandleBuffer.
   1155   @retval FALSE                  Can't find the input Handle in ChildHandleBuffer.
   1156 
   1157 **/
   1158 BOOLEAN
   1159 EFIAPI
   1160 NetIsInHandleBuffer (
   1161   IN  EFI_HANDLE          Handle,
   1162   IN  UINTN               NumberOfChildren,
   1163   IN  EFI_HANDLE          *ChildHandleBuffer OPTIONAL
   1164   )
   1165 {
   1166   UINTN     Index;
   1167 
   1168   if (NumberOfChildren == 0 || ChildHandleBuffer == NULL) {
   1169     return FALSE;
   1170   }
   1171 
   1172   for (Index = 0; Index < NumberOfChildren; Index++) {
   1173     if (Handle == ChildHandleBuffer[Index]) {
   1174       return TRUE;
   1175     }
   1176   }
   1177 
   1178   return FALSE;
   1179 }
   1180 
   1181 
   1182 /**
   1183   Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.
   1184 
   1185   Initialize the forward and backward links of two head nodes donated by Map->Used
   1186   and Map->Recycled of two doubly linked lists.
   1187   Initializes the count of the <Key, Value> pairs in the netmap to zero.
   1188 
   1189   If Map is NULL, then ASSERT().
   1190   If the address of Map->Used is NULL, then ASSERT().
   1191   If the address of Map->Recycled is NULl, then ASSERT().
   1192 
   1193   @param[in, out]  Map                   The netmap to initialize.
   1194 
   1195 **/
   1196 VOID
   1197 EFIAPI
   1198 NetMapInit (
   1199   IN OUT NET_MAP                *Map
   1200   )
   1201 {
   1202   ASSERT (Map != NULL);
   1203 
   1204   InitializeListHead (&Map->Used);
   1205   InitializeListHead (&Map->Recycled);
   1206   Map->Count = 0;
   1207 }
   1208 
   1209 
   1210 /**
   1211   To clean up the netmap, that is, release allocated memories.
   1212 
   1213   Removes all nodes of the Used doubly linked list and free memory of all related netmap items.
   1214   Removes all nodes of the Recycled doubly linked list and free memory of all related netmap items.
   1215   The number of the <Key, Value> pairs in the netmap is set to be zero.
   1216 
   1217   If Map is NULL, then ASSERT().
   1218 
   1219   @param[in, out]  Map                   The netmap to clean up.
   1220 
   1221 **/
   1222 VOID
   1223 EFIAPI
   1224 NetMapClean (
   1225   IN OUT NET_MAP            *Map
   1226   )
   1227 {
   1228   NET_MAP_ITEM              *Item;
   1229   LIST_ENTRY                *Entry;
   1230   LIST_ENTRY                *Next;
   1231 
   1232   ASSERT (Map != NULL);
   1233 
   1234   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Used) {
   1235     Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
   1236 
   1237     RemoveEntryList (&Item->Link);
   1238     Map->Count--;
   1239 
   1240     gBS->FreePool (Item);
   1241   }
   1242 
   1243   ASSERT ((Map->Count == 0) && IsListEmpty (&Map->Used));
   1244 
   1245   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Recycled) {
   1246     Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
   1247 
   1248     RemoveEntryList (&Item->Link);
   1249     gBS->FreePool (Item);
   1250   }
   1251 
   1252   ASSERT (IsListEmpty (&Map->Recycled));
   1253 }
   1254 
   1255 
   1256 /**
   1257   Test whether the netmap is empty and return true if it is.
   1258 
   1259   If the number of the <Key, Value> pairs in the netmap is zero, return TRUE.
   1260 
   1261   If Map is NULL, then ASSERT().
   1262 
   1263 
   1264   @param[in]  Map                   The net map to test.
   1265 
   1266   @return TRUE if the netmap is empty, otherwise FALSE.
   1267 
   1268 **/
   1269 BOOLEAN
   1270 EFIAPI
   1271 NetMapIsEmpty (
   1272   IN NET_MAP                *Map
   1273   )
   1274 {
   1275   ASSERT (Map != NULL);
   1276   return (BOOLEAN) (Map->Count == 0);
   1277 }
   1278 
   1279 
   1280 /**
   1281   Return the number of the <Key, Value> pairs in the netmap.
   1282 
   1283   @param[in]  Map                   The netmap to get the entry number.
   1284 
   1285   @return The entry number in the netmap.
   1286 
   1287 **/
   1288 UINTN
   1289 EFIAPI
   1290 NetMapGetCount (
   1291   IN NET_MAP                *Map
   1292   )
   1293 {
   1294   return Map->Count;
   1295 }
   1296 
   1297 
   1298 /**
   1299   Return one allocated item.
   1300 
   1301   If the Recycled doubly linked list of the netmap is empty, it will try to allocate
   1302   a batch of items if there are enough resources and add corresponding nodes to the begining
   1303   of the Recycled doubly linked list of the netmap. Otherwise, it will directly remove
   1304   the fist node entry of the Recycled doubly linked list and return the corresponding item.
   1305 
   1306   If Map is NULL, then ASSERT().
   1307 
   1308   @param[in, out]  Map          The netmap to allocate item for.
   1309 
   1310   @return                       The allocated item. If NULL, the
   1311                                 allocation failed due to resource limit.
   1312 
   1313 **/
   1314 NET_MAP_ITEM *
   1315 NetMapAllocItem (
   1316   IN OUT NET_MAP            *Map
   1317   )
   1318 {
   1319   NET_MAP_ITEM              *Item;
   1320   LIST_ENTRY                *Head;
   1321   UINTN                     Index;
   1322 
   1323   ASSERT (Map != NULL);
   1324 
   1325   Head = &Map->Recycled;
   1326 
   1327   if (IsListEmpty (Head)) {
   1328     for (Index = 0; Index < NET_MAP_INCREAMENT; Index++) {
   1329       Item = AllocatePool (sizeof (NET_MAP_ITEM));
   1330 
   1331       if (Item == NULL) {
   1332         if (Index == 0) {
   1333           return NULL;
   1334         }
   1335 
   1336         break;
   1337       }
   1338 
   1339       InsertHeadList (Head, &Item->Link);
   1340     }
   1341   }
   1342 
   1343   Item = NET_LIST_HEAD (Head, NET_MAP_ITEM, Link);
   1344   NetListRemoveHead (Head);
   1345 
   1346   return Item;
   1347 }
   1348 
   1349 
   1350 /**
   1351   Allocate an item to save the <Key, Value> pair to the head of the netmap.
   1352 
   1353   Allocate an item to save the <Key, Value> pair and add corresponding node entry
   1354   to the beginning of the Used doubly linked list. The number of the <Key, Value>
   1355   pairs in the netmap increase by 1.
   1356 
   1357   If Map is NULL, then ASSERT().
   1358 
   1359   @param[in, out]  Map                   The netmap to insert into.
   1360   @param[in]       Key                   The user's key.
   1361   @param[in]       Value                 The user's value for the key.
   1362 
   1363   @retval EFI_OUT_OF_RESOURCES  Failed to allocate the memory for the item.
   1364   @retval EFI_SUCCESS           The item is inserted to the head.
   1365 
   1366 **/
   1367 EFI_STATUS
   1368 EFIAPI
   1369 NetMapInsertHead (
   1370   IN OUT NET_MAP            *Map,
   1371   IN VOID                   *Key,
   1372   IN VOID                   *Value    OPTIONAL
   1373   )
   1374 {
   1375   NET_MAP_ITEM              *Item;
   1376 
   1377   ASSERT (Map != NULL);
   1378 
   1379   Item = NetMapAllocItem (Map);
   1380 
   1381   if (Item == NULL) {
   1382     return EFI_OUT_OF_RESOURCES;
   1383   }
   1384 
   1385   Item->Key   = Key;
   1386   Item->Value = Value;
   1387   InsertHeadList (&Map->Used, &Item->Link);
   1388 
   1389   Map->Count++;
   1390   return EFI_SUCCESS;
   1391 }
   1392 
   1393 
   1394 /**
   1395   Allocate an item to save the <Key, Value> pair to the tail of the netmap.
   1396 
   1397   Allocate an item to save the <Key, Value> pair and add corresponding node entry
   1398   to the tail of the Used doubly linked list. The number of the <Key, Value>
   1399   pairs in the netmap increase by 1.
   1400 
   1401   If Map is NULL, then ASSERT().
   1402 
   1403   @param[in, out]  Map                   The netmap to insert into.
   1404   @param[in]       Key                   The user's key.
   1405   @param[in]       Value                 The user's value for the key.
   1406 
   1407   @retval EFI_OUT_OF_RESOURCES  Failed to allocate the memory for the item.
   1408   @retval EFI_SUCCESS           The item is inserted to the tail.
   1409 
   1410 **/
   1411 EFI_STATUS
   1412 EFIAPI
   1413 NetMapInsertTail (
   1414   IN OUT NET_MAP            *Map,
   1415   IN VOID                   *Key,
   1416   IN VOID                   *Value    OPTIONAL
   1417   )
   1418 {
   1419   NET_MAP_ITEM              *Item;
   1420 
   1421   ASSERT (Map != NULL);
   1422 
   1423   Item = NetMapAllocItem (Map);
   1424 
   1425   if (Item == NULL) {
   1426     return EFI_OUT_OF_RESOURCES;
   1427   }
   1428 
   1429   Item->Key   = Key;
   1430   Item->Value = Value;
   1431   InsertTailList (&Map->Used, &Item->Link);
   1432 
   1433   Map->Count++;
   1434 
   1435   return EFI_SUCCESS;
   1436 }
   1437 
   1438 
   1439 /**
   1440   Check whether the item is in the Map and return TRUE if it is.
   1441 
   1442   @param[in]  Map                   The netmap to search within.
   1443   @param[in]  Item                  The item to search.
   1444 
   1445   @return TRUE if the item is in the netmap, otherwise FALSE.
   1446 
   1447 **/
   1448 BOOLEAN
   1449 NetItemInMap (
   1450   IN NET_MAP                *Map,
   1451   IN NET_MAP_ITEM           *Item
   1452   )
   1453 {
   1454   LIST_ENTRY            *ListEntry;
   1455 
   1456   NET_LIST_FOR_EACH (ListEntry, &Map->Used) {
   1457     if (ListEntry == &Item->Link) {
   1458       return TRUE;
   1459     }
   1460   }
   1461 
   1462   return FALSE;
   1463 }
   1464 
   1465 
   1466 /**
   1467   Find the key in the netmap and returns the point to the item contains the Key.
   1468 
   1469   Iterate the Used doubly linked list of the netmap to get every item. Compare the key of every
   1470   item with the key to search. It returns the point to the item contains the Key if found.
   1471 
   1472   If Map is NULL, then ASSERT().
   1473 
   1474   @param[in]  Map                   The netmap to search within.
   1475   @param[in]  Key                   The key to search.
   1476 
   1477   @return The point to the item contains the Key, or NULL if Key isn't in the map.
   1478 
   1479 **/
   1480 NET_MAP_ITEM *
   1481 EFIAPI
   1482 NetMapFindKey (
   1483   IN  NET_MAP               *Map,
   1484   IN  VOID                  *Key
   1485   )
   1486 {
   1487   LIST_ENTRY              *Entry;
   1488   NET_MAP_ITEM            *Item;
   1489 
   1490   ASSERT (Map != NULL);
   1491 
   1492   NET_LIST_FOR_EACH (Entry, &Map->Used) {
   1493     Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
   1494 
   1495     if (Item->Key == Key) {
   1496       return Item;
   1497     }
   1498   }
   1499 
   1500   return NULL;
   1501 }
   1502 
   1503 
   1504 /**
   1505   Remove the node entry of the item from the netmap and return the key of the removed item.
   1506 
   1507   Remove the node entry of the item from the Used doubly linked list of the netmap.
   1508   The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
   1509   entry of the item to the Recycled doubly linked list of the netmap. If Value is not NULL,
   1510   Value will point to the value of the item. It returns the key of the removed item.
   1511 
   1512   If Map is NULL, then ASSERT().
   1513   If Item is NULL, then ASSERT().
   1514   if item in not in the netmap, then ASSERT().
   1515 
   1516   @param[in, out]  Map                   The netmap to remove the item from.
   1517   @param[in, out]  Item                  The item to remove.
   1518   @param[out]      Value                 The variable to receive the value if not NULL.
   1519 
   1520   @return                                The key of the removed item.
   1521 
   1522 **/
   1523 VOID *
   1524 EFIAPI
   1525 NetMapRemoveItem (
   1526   IN  OUT NET_MAP             *Map,
   1527   IN  OUT NET_MAP_ITEM        *Item,
   1528   OUT VOID                    **Value           OPTIONAL
   1529   )
   1530 {
   1531   ASSERT ((Map != NULL) && (Item != NULL));
   1532   ASSERT (NetItemInMap (Map, Item));
   1533 
   1534   RemoveEntryList (&Item->Link);
   1535   Map->Count--;
   1536   InsertHeadList (&Map->Recycled, &Item->Link);
   1537 
   1538   if (Value != NULL) {
   1539     *Value = Item->Value;
   1540   }
   1541 
   1542   return Item->Key;
   1543 }
   1544 
   1545 
   1546 /**
   1547   Remove the first node entry on the netmap and return the key of the removed item.
   1548 
   1549   Remove the first node entry from the Used doubly linked list of the netmap.
   1550   The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
   1551   entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
   1552   parameter Value will point to the value of the item. It returns the key of the removed item.
   1553 
   1554   If Map is NULL, then ASSERT().
   1555   If the Used doubly linked list is empty, then ASSERT().
   1556 
   1557   @param[in, out]  Map                   The netmap to remove the head from.
   1558   @param[out]      Value                 The variable to receive the value if not NULL.
   1559 
   1560   @return                                The key of the item removed.
   1561 
   1562 **/
   1563 VOID *
   1564 EFIAPI
   1565 NetMapRemoveHead (
   1566   IN OUT NET_MAP            *Map,
   1567   OUT VOID                  **Value         OPTIONAL
   1568   )
   1569 {
   1570   NET_MAP_ITEM  *Item;
   1571 
   1572   //
   1573   // Often, it indicates a programming error to remove
   1574   // the first entry in an empty list
   1575   //
   1576   ASSERT (Map && !IsListEmpty (&Map->Used));
   1577 
   1578   Item = NET_LIST_HEAD (&Map->Used, NET_MAP_ITEM, Link);
   1579   RemoveEntryList (&Item->Link);
   1580   Map->Count--;
   1581   InsertHeadList (&Map->Recycled, &Item->Link);
   1582 
   1583   if (Value != NULL) {
   1584     *Value = Item->Value;
   1585   }
   1586 
   1587   return Item->Key;
   1588 }
   1589 
   1590 
   1591 /**
   1592   Remove the last node entry on the netmap and return the key of the removed item.
   1593 
   1594   Remove the last node entry from the Used doubly linked list of the netmap.
   1595   The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
   1596   entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
   1597   parameter Value will point to the value of the item. It returns the key of the removed item.
   1598 
   1599   If Map is NULL, then ASSERT().
   1600   If the Used doubly linked list is empty, then ASSERT().
   1601 
   1602   @param[in, out]  Map                   The netmap to remove the tail from.
   1603   @param[out]      Value                 The variable to receive the value if not NULL.
   1604 
   1605   @return                                The key of the item removed.
   1606 
   1607 **/
   1608 VOID *
   1609 EFIAPI
   1610 NetMapRemoveTail (
   1611   IN OUT NET_MAP            *Map,
   1612   OUT VOID                  **Value       OPTIONAL
   1613   )
   1614 {
   1615   NET_MAP_ITEM              *Item;
   1616 
   1617   //
   1618   // Often, it indicates a programming error to remove
   1619   // the last entry in an empty list
   1620   //
   1621   ASSERT (Map && !IsListEmpty (&Map->Used));
   1622 
   1623   Item = NET_LIST_TAIL (&Map->Used, NET_MAP_ITEM, Link);
   1624   RemoveEntryList (&Item->Link);
   1625   Map->Count--;
   1626   InsertHeadList (&Map->Recycled, &Item->Link);
   1627 
   1628   if (Value != NULL) {
   1629     *Value = Item->Value;
   1630   }
   1631 
   1632   return Item->Key;
   1633 }
   1634 
   1635 
   1636 /**
   1637   Iterate through the netmap and call CallBack for each item.
   1638 
   1639   It will contiue the traverse if CallBack returns EFI_SUCCESS, otherwise, break
   1640   from the loop. It returns the CallBack's last return value. This function is
   1641   delete safe for the current item.
   1642 
   1643   If Map is NULL, then ASSERT().
   1644   If CallBack is NULL, then ASSERT().
   1645 
   1646   @param[in]  Map                   The Map to iterate through.
   1647   @param[in]  CallBack              The callback function to call for each item.
   1648   @param[in]  Arg                   The opaque parameter to the callback.
   1649 
   1650   @retval EFI_SUCCESS            There is no item in the netmap or CallBack for each item
   1651                                  return EFI_SUCCESS.
   1652   @retval Others                 It returns the CallBack's last return value.
   1653 
   1654 **/
   1655 EFI_STATUS
   1656 EFIAPI
   1657 NetMapIterate (
   1658   IN NET_MAP                *Map,
   1659   IN NET_MAP_CALLBACK       CallBack,
   1660   IN VOID                   *Arg      OPTIONAL
   1661   )
   1662 {
   1663 
   1664   LIST_ENTRY            *Entry;
   1665   LIST_ENTRY            *Next;
   1666   LIST_ENTRY            *Head;
   1667   NET_MAP_ITEM          *Item;
   1668   EFI_STATUS            Result;
   1669 
   1670   ASSERT ((Map != NULL) && (CallBack != NULL));
   1671 
   1672   Head = &Map->Used;
   1673 
   1674   if (IsListEmpty (Head)) {
   1675     return EFI_SUCCESS;
   1676   }
   1677 
   1678   NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
   1679     Item   = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
   1680     Result = CallBack (Map, Item, Arg);
   1681 
   1682     if (EFI_ERROR (Result)) {
   1683       return Result;
   1684     }
   1685   }
   1686 
   1687   return EFI_SUCCESS;
   1688 }
   1689 
   1690 
   1691 /**
   1692   This is the default unload handle for all the network drivers.
   1693 
   1694   Disconnect the driver specified by ImageHandle from all the devices in the handle database.
   1695   Uninstall all the protocols installed in the driver entry point.
   1696 
   1697   @param[in]  ImageHandle       The drivers' driver image.
   1698 
   1699   @retval EFI_SUCCESS           The image is unloaded.
   1700   @retval Others                Failed to unload the image.
   1701 
   1702 **/
   1703 EFI_STATUS
   1704 EFIAPI
   1705 NetLibDefaultUnload (
   1706   IN EFI_HANDLE             ImageHandle
   1707   )
   1708 {
   1709   EFI_STATUS                        Status;
   1710   EFI_HANDLE                        *DeviceHandleBuffer;
   1711   UINTN                             DeviceHandleCount;
   1712   UINTN                             Index;
   1713   UINTN                             Index2;
   1714   EFI_DRIVER_BINDING_PROTOCOL       *DriverBinding;
   1715   EFI_COMPONENT_NAME_PROTOCOL       *ComponentName;
   1716   EFI_COMPONENT_NAME2_PROTOCOL      *ComponentName2;
   1717 
   1718   //
   1719   // Get the list of all the handles in the handle database.
   1720   // If there is an error getting the list, then the unload
   1721   // operation fails.
   1722   //
   1723   Status = gBS->LocateHandleBuffer (
   1724                   AllHandles,
   1725                   NULL,
   1726                   NULL,
   1727                   &DeviceHandleCount,
   1728                   &DeviceHandleBuffer
   1729                   );
   1730 
   1731   if (EFI_ERROR (Status)) {
   1732     return Status;
   1733   }
   1734 
   1735   for (Index = 0; Index < DeviceHandleCount; Index++) {
   1736     Status = gBS->HandleProtocol (
   1737                     DeviceHandleBuffer[Index],
   1738                     &gEfiDriverBindingProtocolGuid,
   1739                     (VOID **) &DriverBinding
   1740                     );
   1741     if (EFI_ERROR (Status)) {
   1742       continue;
   1743     }
   1744 
   1745     if (DriverBinding->ImageHandle != ImageHandle) {
   1746       continue;
   1747     }
   1748 
   1749     //
   1750     // Disconnect the driver specified by ImageHandle from all
   1751     // the devices in the handle database.
   1752     //
   1753     for (Index2 = 0; Index2 < DeviceHandleCount; Index2++) {
   1754       Status = gBS->DisconnectController (
   1755                       DeviceHandleBuffer[Index2],
   1756                       DriverBinding->DriverBindingHandle,
   1757                       NULL
   1758                       );
   1759     }
   1760 
   1761     //
   1762     // Uninstall all the protocols installed in the driver entry point
   1763     //
   1764     gBS->UninstallProtocolInterface (
   1765           DriverBinding->DriverBindingHandle,
   1766           &gEfiDriverBindingProtocolGuid,
   1767           DriverBinding
   1768           );
   1769 
   1770     Status = gBS->HandleProtocol (
   1771                     DeviceHandleBuffer[Index],
   1772                     &gEfiComponentNameProtocolGuid,
   1773                     (VOID **) &ComponentName
   1774                     );
   1775     if (!EFI_ERROR (Status)) {
   1776       gBS->UninstallProtocolInterface (
   1777              DriverBinding->DriverBindingHandle,
   1778              &gEfiComponentNameProtocolGuid,
   1779              ComponentName
   1780              );
   1781     }
   1782 
   1783     Status = gBS->HandleProtocol (
   1784                     DeviceHandleBuffer[Index],
   1785                     &gEfiComponentName2ProtocolGuid,
   1786                     (VOID **) &ComponentName2
   1787                     );
   1788     if (!EFI_ERROR (Status)) {
   1789       gBS->UninstallProtocolInterface (
   1790              DriverBinding->DriverBindingHandle,
   1791              &gEfiComponentName2ProtocolGuid,
   1792              ComponentName2
   1793              );
   1794     }
   1795   }
   1796 
   1797   //
   1798   // Free the buffer containing the list of handles from the handle database
   1799   //
   1800   if (DeviceHandleBuffer != NULL) {
   1801     gBS->FreePool (DeviceHandleBuffer);
   1802   }
   1803 
   1804   return EFI_SUCCESS;
   1805 }
   1806 
   1807 
   1808 
   1809 /**
   1810   Create a child of the service that is identified by ServiceBindingGuid.
   1811 
   1812   Get the ServiceBinding Protocol first, then use it to create a child.
   1813 
   1814   If ServiceBindingGuid is NULL, then ASSERT().
   1815   If ChildHandle is NULL, then ASSERT().
   1816 
   1817   @param[in]       Controller            The controller which has the service installed.
   1818   @param[in]       Image                 The image handle used to open service.
   1819   @param[in]       ServiceBindingGuid    The service's Guid.
   1820   @param[in, out]  ChildHandle           The handle to receive the create child.
   1821 
   1822   @retval EFI_SUCCESS           The child is successfully created.
   1823   @retval Others                Failed to create the child.
   1824 
   1825 **/
   1826 EFI_STATUS
   1827 EFIAPI
   1828 NetLibCreateServiceChild (
   1829   IN  EFI_HANDLE            Controller,
   1830   IN  EFI_HANDLE            Image,
   1831   IN  EFI_GUID              *ServiceBindingGuid,
   1832   IN  OUT EFI_HANDLE        *ChildHandle
   1833   )
   1834 {
   1835   EFI_STATUS                    Status;
   1836   EFI_SERVICE_BINDING_PROTOCOL  *Service;
   1837 
   1838 
   1839   ASSERT ((ServiceBindingGuid != NULL) && (ChildHandle != NULL));
   1840 
   1841   //
   1842   // Get the ServiceBinding Protocol
   1843   //
   1844   Status = gBS->OpenProtocol (
   1845                   Controller,
   1846                   ServiceBindingGuid,
   1847                   (VOID **) &Service,
   1848                   Image,
   1849                   Controller,
   1850                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1851                   );
   1852 
   1853   if (EFI_ERROR (Status)) {
   1854     return Status;
   1855   }
   1856 
   1857   //
   1858   // Create a child
   1859   //
   1860   Status = Service->CreateChild (Service, ChildHandle);
   1861   return Status;
   1862 }
   1863 
   1864 
   1865 /**
   1866   Destroy a child of the service that is identified by ServiceBindingGuid.
   1867 
   1868   Get the ServiceBinding Protocol first, then use it to destroy a child.
   1869 
   1870   If ServiceBindingGuid is NULL, then ASSERT().
   1871 
   1872   @param[in]   Controller            The controller which has the service installed.
   1873   @param[in]   Image                 The image handle used to open service.
   1874   @param[in]   ServiceBindingGuid    The service's Guid.
   1875   @param[in]   ChildHandle           The child to destroy.
   1876 
   1877   @retval EFI_SUCCESS           The child is successfully destroyed.
   1878   @retval Others                Failed to destroy the child.
   1879 
   1880 **/
   1881 EFI_STATUS
   1882 EFIAPI
   1883 NetLibDestroyServiceChild (
   1884   IN  EFI_HANDLE            Controller,
   1885   IN  EFI_HANDLE            Image,
   1886   IN  EFI_GUID              *ServiceBindingGuid,
   1887   IN  EFI_HANDLE            ChildHandle
   1888   )
   1889 {
   1890   EFI_STATUS                    Status;
   1891   EFI_SERVICE_BINDING_PROTOCOL  *Service;
   1892 
   1893   ASSERT (ServiceBindingGuid != NULL);
   1894 
   1895   //
   1896   // Get the ServiceBinding Protocol
   1897   //
   1898   Status = gBS->OpenProtocol (
   1899                   Controller,
   1900                   ServiceBindingGuid,
   1901                   (VOID **) &Service,
   1902                   Image,
   1903                   Controller,
   1904                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
   1905                   );
   1906 
   1907   if (EFI_ERROR (Status)) {
   1908     return Status;
   1909   }
   1910 
   1911   //
   1912   // destroy the child
   1913   //
   1914   Status = Service->DestroyChild (Service, ChildHandle);
   1915   return Status;
   1916 }
   1917 
   1918 /**
   1919   Get handle with Simple Network Protocol installed on it.
   1920 
   1921   There should be MNP Service Binding Protocol installed on the input ServiceHandle.
   1922   If Simple Network Protocol is already installed on the ServiceHandle, the
   1923   ServiceHandle will be returned. If SNP is not installed on the ServiceHandle,
   1924   try to find its parent handle with SNP installed.
   1925 
   1926   @param[in]   ServiceHandle    The handle where network service binding protocols are
   1927                                 installed on.
   1928   @param[out]  Snp              The pointer to store the address of the SNP instance.
   1929                                 This is an optional parameter that may be NULL.
   1930 
   1931   @return The SNP handle, or NULL if not found.
   1932 
   1933 **/
   1934 EFI_HANDLE
   1935 EFIAPI
   1936 NetLibGetSnpHandle (
   1937   IN   EFI_HANDLE                  ServiceHandle,
   1938   OUT  EFI_SIMPLE_NETWORK_PROTOCOL **Snp  OPTIONAL
   1939   )
   1940 {
   1941   EFI_STATUS                   Status;
   1942   EFI_SIMPLE_NETWORK_PROTOCOL  *SnpInstance;
   1943   EFI_DEVICE_PATH_PROTOCOL     *DevicePath;
   1944   EFI_HANDLE                   SnpHandle;
   1945 
   1946   //
   1947   // Try to open SNP from ServiceHandle
   1948   //
   1949   SnpInstance = NULL;
   1950   Status = gBS->HandleProtocol (ServiceHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);
   1951   if (!EFI_ERROR (Status)) {
   1952     if (Snp != NULL) {
   1953       *Snp = SnpInstance;
   1954     }
   1955     return ServiceHandle;
   1956   }
   1957 
   1958   //
   1959   // Failed to open SNP, try to get SNP handle by LocateDevicePath()
   1960   //
   1961   DevicePath = DevicePathFromHandle (ServiceHandle);
   1962   if (DevicePath == NULL) {
   1963     return NULL;
   1964   }
   1965 
   1966   SnpHandle = NULL;
   1967   Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &DevicePath, &SnpHandle);
   1968   if (EFI_ERROR (Status)) {
   1969     //
   1970     // Failed to find SNP handle
   1971     //
   1972     return NULL;
   1973   }
   1974 
   1975   Status = gBS->HandleProtocol (SnpHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);
   1976   if (!EFI_ERROR (Status)) {
   1977     if (Snp != NULL) {
   1978       *Snp = SnpInstance;
   1979     }
   1980     return SnpHandle;
   1981   }
   1982 
   1983   return NULL;
   1984 }
   1985 
   1986 /**
   1987   Retrieve VLAN ID of a VLAN device handle.
   1988 
   1989   Search VLAN device path node in Device Path of specified ServiceHandle and
   1990   return its VLAN ID. If no VLAN device path node found, then this ServiceHandle
   1991   is not a VLAN device handle, and 0 will be returned.
   1992 
   1993   @param[in]   ServiceHandle    The handle where network service binding protocols are
   1994                                 installed on.
   1995 
   1996   @return VLAN ID of the device handle, or 0 if not a VLAN device.
   1997 
   1998 **/
   1999 UINT16
   2000 EFIAPI
   2001 NetLibGetVlanId (
   2002   IN EFI_HANDLE             ServiceHandle
   2003   )
   2004 {
   2005   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
   2006   EFI_DEVICE_PATH_PROTOCOL  *Node;
   2007 
   2008   DevicePath = DevicePathFromHandle (ServiceHandle);
   2009   if (DevicePath == NULL) {
   2010     return 0;
   2011   }
   2012 
   2013   Node = DevicePath;
   2014   while (!IsDevicePathEnd (Node)) {
   2015     if (Node->Type == MESSAGING_DEVICE_PATH && Node->SubType == MSG_VLAN_DP) {
   2016       return ((VLAN_DEVICE_PATH *) Node)->VlanId;
   2017     }
   2018     Node = NextDevicePathNode (Node);
   2019   }
   2020 
   2021   return 0;
   2022 }
   2023 
   2024 /**
   2025   Find VLAN device handle with specified VLAN ID.
   2026 
   2027   The VLAN child device handle is created by VLAN Config Protocol on ControllerHandle.
   2028   This function will append VLAN device path node to the parent device path,
   2029   and then use LocateDevicePath() to find the correct VLAN device handle.
   2030 
   2031   @param[in]   ControllerHandle The handle where network service binding protocols are
   2032                                 installed on.
   2033   @param[in]   VlanId           The configured VLAN ID for the VLAN device.
   2034 
   2035   @return The VLAN device handle, or NULL if not found.
   2036 
   2037 **/
   2038 EFI_HANDLE
   2039 EFIAPI
   2040 NetLibGetVlanHandle (
   2041   IN EFI_HANDLE             ControllerHandle,
   2042   IN UINT16                 VlanId
   2043   )
   2044 {
   2045   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
   2046   EFI_DEVICE_PATH_PROTOCOL  *VlanDevicePath;
   2047   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
   2048   VLAN_DEVICE_PATH          VlanNode;
   2049   EFI_HANDLE                Handle;
   2050 
   2051   ParentDevicePath = DevicePathFromHandle (ControllerHandle);
   2052   if (ParentDevicePath == NULL) {
   2053     return NULL;
   2054   }
   2055 
   2056   //
   2057   // Construct VLAN device path
   2058   //
   2059   CopyMem (&VlanNode, &mNetVlanDevicePathTemplate, sizeof (VLAN_DEVICE_PATH));
   2060   VlanNode.VlanId = VlanId;
   2061   VlanDevicePath = AppendDevicePathNode (
   2062                      ParentDevicePath,
   2063                      (EFI_DEVICE_PATH_PROTOCOL *) &VlanNode
   2064                      );
   2065   if (VlanDevicePath == NULL) {
   2066     return NULL;
   2067   }
   2068 
   2069   //
   2070   // Find VLAN device handle
   2071   //
   2072   Handle = NULL;
   2073   DevicePath = VlanDevicePath;
   2074   gBS->LocateDevicePath (
   2075          &gEfiDevicePathProtocolGuid,
   2076          &DevicePath,
   2077          &Handle
   2078          );
   2079   if (!IsDevicePathEnd (DevicePath)) {
   2080     //
   2081     // Device path is not exactly match
   2082     //
   2083     Handle = NULL;
   2084   }
   2085 
   2086   FreePool (VlanDevicePath);
   2087   return Handle;
   2088 }
   2089 
   2090 /**
   2091   Get MAC address associated with the network service handle.
   2092 
   2093   There should be MNP Service Binding Protocol installed on the input ServiceHandle.
   2094   If SNP is installed on the ServiceHandle or its parent handle, MAC address will
   2095   be retrieved from SNP. If no SNP found, try to get SNP mode data use MNP.
   2096 
   2097   @param[in]   ServiceHandle    The handle where network service binding protocols are
   2098                                 installed on.
   2099   @param[out]  MacAddress       The pointer to store the returned MAC address.
   2100   @param[out]  AddressSize      The length of returned MAC address.
   2101 
   2102   @retval EFI_SUCCESS           MAC address is returned successfully.
   2103   @retval Others                Failed to get SNP mode data.
   2104 
   2105 **/
   2106 EFI_STATUS
   2107 EFIAPI
   2108 NetLibGetMacAddress (
   2109   IN  EFI_HANDLE            ServiceHandle,
   2110   OUT EFI_MAC_ADDRESS       *MacAddress,
   2111   OUT UINTN                 *AddressSize
   2112   )
   2113 {
   2114   EFI_STATUS                   Status;
   2115   EFI_SIMPLE_NETWORK_PROTOCOL  *Snp;
   2116   EFI_SIMPLE_NETWORK_MODE      *SnpMode;
   2117   EFI_SIMPLE_NETWORK_MODE      SnpModeData;
   2118   EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
   2119   EFI_SERVICE_BINDING_PROTOCOL *MnpSb;
   2120   EFI_HANDLE                   *SnpHandle;
   2121   EFI_HANDLE                   MnpChildHandle;
   2122 
   2123   ASSERT (MacAddress != NULL);
   2124   ASSERT (AddressSize != NULL);
   2125 
   2126   //
   2127   // Try to get SNP handle
   2128   //
   2129   Snp = NULL;
   2130   SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);
   2131   if (SnpHandle != NULL) {
   2132     //
   2133     // SNP found, use it directly
   2134     //
   2135     SnpMode = Snp->Mode;
   2136   } else {
   2137     //
   2138     // Failed to get SNP handle, try to get MAC address from MNP
   2139     //
   2140     MnpChildHandle = NULL;
   2141     Status = gBS->HandleProtocol (
   2142                     ServiceHandle,
   2143                     &gEfiManagedNetworkServiceBindingProtocolGuid,
   2144                     (VOID **) &MnpSb
   2145                     );
   2146     if (EFI_ERROR (Status)) {
   2147       return Status;
   2148     }
   2149 
   2150     //
   2151     // Create a MNP child
   2152     //
   2153     Status = MnpSb->CreateChild (MnpSb, &MnpChildHandle);
   2154     if (EFI_ERROR (Status)) {
   2155       return Status;
   2156     }
   2157 
   2158     //
   2159     // Open MNP protocol
   2160     //
   2161     Status = gBS->HandleProtocol (
   2162                     MnpChildHandle,
   2163                     &gEfiManagedNetworkProtocolGuid,
   2164                     (VOID **) &Mnp
   2165                     );
   2166     if (EFI_ERROR (Status)) {
   2167       MnpSb->DestroyChild (MnpSb, MnpChildHandle);
   2168       return Status;
   2169     }
   2170 
   2171     //
   2172     // Try to get SNP mode from MNP
   2173     //
   2174     Status = Mnp->GetModeData (Mnp, NULL, &SnpModeData);
   2175     if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {
   2176       MnpSb->DestroyChild (MnpSb, MnpChildHandle);
   2177       return Status;
   2178     }
   2179     SnpMode = &SnpModeData;
   2180 
   2181     //
   2182     // Destroy the MNP child
   2183     //
   2184     MnpSb->DestroyChild (MnpSb, MnpChildHandle);
   2185   }
   2186 
   2187   *AddressSize = SnpMode->HwAddressSize;
   2188   CopyMem (MacAddress->Addr, SnpMode->CurrentAddress.Addr, SnpMode->HwAddressSize);
   2189 
   2190   return EFI_SUCCESS;
   2191 }
   2192 
   2193 /**
   2194   Convert MAC address of the NIC associated with specified Service Binding Handle
   2195   to a unicode string. Callers are responsible for freeing the string storage.
   2196 
   2197   Locate simple network protocol associated with the Service Binding Handle and
   2198   get the mac address from SNP. Then convert the mac address into a unicode
   2199   string. It takes 2 unicode characters to represent a 1 byte binary buffer.
   2200   Plus one unicode character for the null-terminator.
   2201 
   2202   @param[in]   ServiceHandle         The handle where network service binding protocol is
   2203                                      installed on.
   2204   @param[in]   ImageHandle           The image handle used to act as the agent handle to
   2205                                      get the simple network protocol. This parameter is
   2206                                      optional and may be NULL.
   2207   @param[out]  MacString             The pointer to store the address of the string
   2208                                      representation of  the mac address.
   2209 
   2210   @retval EFI_SUCCESS           Convert the mac address a unicode string successfully.
   2211   @retval EFI_OUT_OF_RESOURCES  There are not enough memory resource.
   2212   @retval Others                Failed to open the simple network protocol.
   2213 
   2214 **/
   2215 EFI_STATUS
   2216 EFIAPI
   2217 NetLibGetMacString (
   2218   IN  EFI_HANDLE            ServiceHandle,
   2219   IN  EFI_HANDLE            ImageHandle, OPTIONAL
   2220   OUT CHAR16                **MacString
   2221   )
   2222 {
   2223   EFI_STATUS                   Status;
   2224   EFI_MAC_ADDRESS              MacAddress;
   2225   UINT8                        *HwAddress;
   2226   UINTN                        HwAddressSize;
   2227   UINT16                       VlanId;
   2228   CHAR16                       *String;
   2229   UINTN                        Index;
   2230 
   2231   ASSERT (MacString != NULL);
   2232 
   2233   //
   2234   // Get MAC address of the network device
   2235   //
   2236   Status = NetLibGetMacAddress (ServiceHandle, &MacAddress, &HwAddressSize);
   2237   if (EFI_ERROR (Status)) {
   2238     return Status;
   2239   }
   2240 
   2241   //
   2242   // It takes 2 unicode characters to represent a 1 byte binary buffer.
   2243   // If VLAN is configured, it will need extra 5 characters like "\0005".
   2244   // Plus one unicode character for the null-terminator.
   2245   //
   2246   String = AllocateZeroPool ((2 * HwAddressSize + 5 + 1) * sizeof (CHAR16));
   2247   if (String == NULL) {
   2248     return EFI_OUT_OF_RESOURCES;
   2249   }
   2250   *MacString = String;
   2251 
   2252   //
   2253   // Convert the MAC address into a unicode string.
   2254   //
   2255   HwAddress = &MacAddress.Addr[0];
   2256   for (Index = 0; Index < HwAddressSize; Index++) {
   2257     String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(HwAddress++), 2);
   2258   }
   2259 
   2260   //
   2261   // Append VLAN ID if any
   2262   //
   2263   VlanId = NetLibGetVlanId (ServiceHandle);
   2264   if (VlanId != 0) {
   2265     *String++ = L'\\';
   2266     String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, VlanId, 4);
   2267   }
   2268 
   2269   //
   2270   // Null terminate the Unicode string
   2271   //
   2272   *String = L'\0';
   2273 
   2274   return EFI_SUCCESS;
   2275 }
   2276 
   2277 /**
   2278   Detect media status for specified network device.
   2279 
   2280   The underlying UNDI driver may or may not support reporting media status from
   2281   GET_STATUS command (PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED). This routine
   2282   will try to invoke Snp->GetStatus() to get the media status: if media already
   2283   present, it return directly; if media not present, it will stop SNP and then
   2284   restart SNP to get the latest media status, this give chance to get the correct
   2285   media status for old UNDI driver which doesn't support reporting media status
   2286   from GET_STATUS command.
   2287   Note: there will be two limitations for current algorithm:
   2288   1) for UNDI with this capability, in case of cable is not attached, there will
   2289      be an redundant Stop/Start() process;
   2290   2) for UNDI without this capability, in case that network cable is attached when
   2291      Snp->Initialize() is invoked while network cable is unattached later,
   2292      NetLibDetectMedia() will report MediaPresent as TRUE, causing upper layer
   2293      apps to wait for timeout time.
   2294 
   2295   @param[in]   ServiceHandle    The handle where network service binding protocols are
   2296                                 installed on.
   2297   @param[out]  MediaPresent     The pointer to store the media status.
   2298 
   2299   @retval EFI_SUCCESS           Media detection success.
   2300   @retval EFI_INVALID_PARAMETER ServiceHandle is not valid network device handle.
   2301   @retval EFI_UNSUPPORTED       Network device does not support media detection.
   2302   @retval EFI_DEVICE_ERROR      SNP is in unknown state.
   2303 
   2304 **/
   2305 EFI_STATUS
   2306 EFIAPI
   2307 NetLibDetectMedia (
   2308   IN  EFI_HANDLE            ServiceHandle,
   2309   OUT BOOLEAN               *MediaPresent
   2310   )
   2311 {
   2312   EFI_STATUS                   Status;
   2313   EFI_HANDLE                   SnpHandle;
   2314   EFI_SIMPLE_NETWORK_PROTOCOL  *Snp;
   2315   UINT32                       InterruptStatus;
   2316   UINT32                       OldState;
   2317   EFI_MAC_ADDRESS              *MCastFilter;
   2318   UINT32                       MCastFilterCount;
   2319   UINT32                       EnableFilterBits;
   2320   UINT32                       DisableFilterBits;
   2321   BOOLEAN                      ResetMCastFilters;
   2322 
   2323   ASSERT (MediaPresent != NULL);
   2324 
   2325   //
   2326   // Get SNP handle
   2327   //
   2328   Snp = NULL;
   2329   SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);
   2330   if (SnpHandle == NULL) {
   2331     return EFI_INVALID_PARAMETER;
   2332   }
   2333 
   2334   //
   2335   // Check whether SNP support media detection
   2336   //
   2337   if (!Snp->Mode->MediaPresentSupported) {
   2338     return EFI_UNSUPPORTED;
   2339   }
   2340 
   2341   //
   2342   // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
   2343   //
   2344   Status = Snp->GetStatus (Snp, &InterruptStatus, NULL);
   2345   if (EFI_ERROR (Status)) {
   2346     return Status;
   2347   }
   2348 
   2349   if (Snp->Mode->MediaPresent) {
   2350     //
   2351     // Media is present, return directly
   2352     //
   2353     *MediaPresent = TRUE;
   2354     return EFI_SUCCESS;
   2355   }
   2356 
   2357   //
   2358   // Till now, GetStatus() report no media; while, in case UNDI not support
   2359   // reporting media status from GetStatus(), this media status may be incorrect.
   2360   // So, we will stop SNP and then restart it to get the correct media status.
   2361   //
   2362   OldState = Snp->Mode->State;
   2363   if (OldState >= EfiSimpleNetworkMaxState) {
   2364     return EFI_DEVICE_ERROR;
   2365   }
   2366 
   2367   MCastFilter = NULL;
   2368 
   2369   if (OldState == EfiSimpleNetworkInitialized) {
   2370     //
   2371     // SNP is already in use, need Shutdown/Stop and then Start/Initialize
   2372     //
   2373 
   2374     //
   2375     // Backup current SNP receive filter settings
   2376     //
   2377     EnableFilterBits  = Snp->Mode->ReceiveFilterSetting;
   2378     DisableFilterBits = Snp->Mode->ReceiveFilterMask ^ EnableFilterBits;
   2379 
   2380     ResetMCastFilters = TRUE;
   2381     MCastFilterCount  = Snp->Mode->MCastFilterCount;
   2382     if (MCastFilterCount != 0) {
   2383       MCastFilter = AllocateCopyPool (
   2384                       MCastFilterCount * sizeof (EFI_MAC_ADDRESS),
   2385                       Snp->Mode->MCastFilter
   2386                       );
   2387       ASSERT (MCastFilter != NULL);
   2388 
   2389       ResetMCastFilters = FALSE;
   2390     }
   2391 
   2392     //
   2393     // Shutdown/Stop the simple network
   2394     //
   2395     Status = Snp->Shutdown (Snp);
   2396     if (!EFI_ERROR (Status)) {
   2397       Status = Snp->Stop (Snp);
   2398     }
   2399     if (EFI_ERROR (Status)) {
   2400       goto Exit;
   2401     }
   2402 
   2403     //
   2404     // Start/Initialize the simple network
   2405     //
   2406     Status = Snp->Start (Snp);
   2407     if (!EFI_ERROR (Status)) {
   2408       Status = Snp->Initialize (Snp, 0, 0);
   2409     }
   2410     if (EFI_ERROR (Status)) {
   2411       goto Exit;
   2412     }
   2413 
   2414     //
   2415     // Here we get the correct media status
   2416     //
   2417     *MediaPresent = Snp->Mode->MediaPresent;
   2418 
   2419     //
   2420     // Restore SNP receive filter settings
   2421     //
   2422     Status = Snp->ReceiveFilters (
   2423                     Snp,
   2424                     EnableFilterBits,
   2425                     DisableFilterBits,
   2426                     ResetMCastFilters,
   2427                     MCastFilterCount,
   2428                     MCastFilter
   2429                     );
   2430 
   2431     if (MCastFilter != NULL) {
   2432       FreePool (MCastFilter);
   2433     }
   2434 
   2435     return Status;
   2436   }
   2437 
   2438   //
   2439   // SNP is not in use, it's in state of EfiSimpleNetworkStopped or EfiSimpleNetworkStarted
   2440   //
   2441   if (OldState == EfiSimpleNetworkStopped) {
   2442     //
   2443     // SNP not start yet, start it
   2444     //
   2445     Status = Snp->Start (Snp);
   2446     if (EFI_ERROR (Status)) {
   2447       goto Exit;
   2448     }
   2449   }
   2450 
   2451   //
   2452   // Initialize the simple network
   2453   //
   2454   Status = Snp->Initialize (Snp, 0, 0);
   2455   if (EFI_ERROR (Status)) {
   2456     Status = EFI_DEVICE_ERROR;
   2457     goto Exit;
   2458   }
   2459 
   2460   //
   2461   // Here we get the correct media status
   2462   //
   2463   *MediaPresent = Snp->Mode->MediaPresent;
   2464 
   2465   //
   2466   // Shut down the simple network
   2467   //
   2468   Snp->Shutdown (Snp);
   2469 
   2470 Exit:
   2471   if (OldState == EfiSimpleNetworkStopped) {
   2472     //
   2473     // Original SNP sate is Stopped, restore to original state
   2474     //
   2475     Snp->Stop (Snp);
   2476   }
   2477 
   2478   if (MCastFilter != NULL) {
   2479     FreePool (MCastFilter);
   2480   }
   2481 
   2482   return Status;
   2483 }
   2484 
   2485 /**
   2486   Check the default address used by the IPv4 driver is static or dynamic (acquired
   2487   from DHCP).
   2488 
   2489   If the controller handle does not have the EFI_IP4_CONFIG2_PROTOCOL installed, the
   2490   default address is static. If failed to get the policy from Ip4 Config2 Protocol,
   2491   the default address is static. Otherwise, get the result from Ip4 Config2 Protocol.
   2492 
   2493   @param[in]   Controller     The controller handle which has the EFI_IP4_CONFIG2_PROTOCOL
   2494                               relative with the default address to judge.
   2495 
   2496   @retval TRUE           If the default address is static.
   2497   @retval FALSE          If the default address is acquired from DHCP.
   2498 
   2499 **/
   2500 BOOLEAN
   2501 NetLibDefaultAddressIsStatic (
   2502   IN EFI_HANDLE  Controller
   2503   )
   2504 {
   2505   EFI_STATUS                       Status;
   2506   EFI_IP4_CONFIG2_PROTOCOL         *Ip4Config2;
   2507   UINTN                            DataSize;
   2508   EFI_IP4_CONFIG2_POLICY           Policy;
   2509   BOOLEAN                          IsStatic;
   2510 
   2511   Ip4Config2 = NULL;
   2512 
   2513   DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
   2514 
   2515   IsStatic   = TRUE;
   2516 
   2517   //
   2518   // Get Ip4Config2 policy.
   2519   //
   2520   Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);
   2521   if (EFI_ERROR (Status)) {
   2522     goto ON_EXIT;
   2523   }
   2524 
   2525   Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypePolicy, &DataSize, &Policy);
   2526   if (EFI_ERROR (Status)) {
   2527     goto ON_EXIT;
   2528   }
   2529 
   2530   IsStatic = (BOOLEAN) (Policy == Ip4Config2PolicyStatic);
   2531 
   2532 ON_EXIT:
   2533 
   2534   return IsStatic;
   2535 }
   2536 
   2537 /**
   2538   Create an IPv4 device path node.
   2539 
   2540   The header type of IPv4 device path node is MESSAGING_DEVICE_PATH.
   2541   The header subtype of IPv4 device path node is MSG_IPv4_DP.
   2542   Get other info from parameters to make up the whole IPv4 device path node.
   2543 
   2544   @param[in, out]  Node                  Pointer to the IPv4 device path node.
   2545   @param[in]       Controller            The controller handle.
   2546   @param[in]       LocalIp               The local IPv4 address.
   2547   @param[in]       LocalPort             The local port.
   2548   @param[in]       RemoteIp              The remote IPv4 address.
   2549   @param[in]       RemotePort            The remote port.
   2550   @param[in]       Protocol              The protocol type in the IP header.
   2551   @param[in]       UseDefaultAddress     Whether this instance is using default address or not.
   2552 
   2553 **/
   2554 VOID
   2555 EFIAPI
   2556 NetLibCreateIPv4DPathNode (
   2557   IN OUT IPv4_DEVICE_PATH  *Node,
   2558   IN EFI_HANDLE            Controller,
   2559   IN IP4_ADDR              LocalIp,
   2560   IN UINT16                LocalPort,
   2561   IN IP4_ADDR              RemoteIp,
   2562   IN UINT16                RemotePort,
   2563   IN UINT16                Protocol,
   2564   IN BOOLEAN               UseDefaultAddress
   2565   )
   2566 {
   2567   Node->Header.Type    = MESSAGING_DEVICE_PATH;
   2568   Node->Header.SubType = MSG_IPv4_DP;
   2569   SetDevicePathNodeLength (&Node->Header, sizeof (IPv4_DEVICE_PATH));
   2570 
   2571   CopyMem (&Node->LocalIpAddress, &LocalIp, sizeof (EFI_IPv4_ADDRESS));
   2572   CopyMem (&Node->RemoteIpAddress, &RemoteIp, sizeof (EFI_IPv4_ADDRESS));
   2573 
   2574   Node->LocalPort  = LocalPort;
   2575   Node->RemotePort = RemotePort;
   2576 
   2577   Node->Protocol = Protocol;
   2578 
   2579   if (!UseDefaultAddress) {
   2580     Node->StaticIpAddress = TRUE;
   2581   } else {
   2582     Node->StaticIpAddress = NetLibDefaultAddressIsStatic (Controller);
   2583   }
   2584 
   2585   //
   2586   // Set the Gateway IP address to default value 0:0:0:0.
   2587   // Set the Subnet mask to default value 255:255:255:0.
   2588   //
   2589   ZeroMem (&Node->GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS));
   2590   SetMem (&Node->SubnetMask, sizeof (EFI_IPv4_ADDRESS), 0xff);
   2591   Node->SubnetMask.Addr[3] = 0;
   2592 }
   2593 
   2594 /**
   2595   Create an IPv6 device path node.
   2596 
   2597   The header type of IPv6 device path node is MESSAGING_DEVICE_PATH.
   2598   The header subtype of IPv6 device path node is MSG_IPv6_DP.
   2599   Get other info from parameters to make up the whole IPv6 device path node.
   2600 
   2601   @param[in, out]  Node                  Pointer to the IPv6 device path node.
   2602   @param[in]       Controller            The controller handle.
   2603   @param[in]       LocalIp               The local IPv6 address.
   2604   @param[in]       LocalPort             The local port.
   2605   @param[in]       RemoteIp              The remote IPv6 address.
   2606   @param[in]       RemotePort            The remote port.
   2607   @param[in]       Protocol              The protocol type in the IP header.
   2608 
   2609 **/
   2610 VOID
   2611 EFIAPI
   2612 NetLibCreateIPv6DPathNode (
   2613   IN OUT IPv6_DEVICE_PATH  *Node,
   2614   IN EFI_HANDLE            Controller,
   2615   IN EFI_IPv6_ADDRESS      *LocalIp,
   2616   IN UINT16                LocalPort,
   2617   IN EFI_IPv6_ADDRESS      *RemoteIp,
   2618   IN UINT16                RemotePort,
   2619   IN UINT16                Protocol
   2620   )
   2621 {
   2622   Node->Header.Type    = MESSAGING_DEVICE_PATH;
   2623   Node->Header.SubType = MSG_IPv6_DP;
   2624   SetDevicePathNodeLength (&Node->Header, sizeof (IPv6_DEVICE_PATH));
   2625 
   2626   CopyMem (&Node->LocalIpAddress, LocalIp, sizeof (EFI_IPv6_ADDRESS));
   2627   CopyMem (&Node->RemoteIpAddress, RemoteIp, sizeof (EFI_IPv6_ADDRESS));
   2628 
   2629   Node->LocalPort  = LocalPort;
   2630   Node->RemotePort = RemotePort;
   2631 
   2632   Node->Protocol        = Protocol;
   2633 
   2634   //
   2635   // Set default value to IPAddressOrigin, PrefixLength.
   2636   // Set the Gateway IP address to unspecified address.
   2637   //
   2638   Node->IpAddressOrigin = 0;
   2639   Node->PrefixLength    = IP6_PREFIX_LENGTH;
   2640   ZeroMem (&Node->GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS));
   2641 }
   2642 
   2643 /**
   2644   Find the UNDI/SNP handle from controller and protocol GUID.
   2645 
   2646   For example, IP will open a MNP child to transmit/receive
   2647   packets, when MNP is stopped, IP should also be stopped. IP
   2648   needs to find its own private data which is related the IP's
   2649   service binding instance that is install on UNDI/SNP handle.
   2650   Now, the controller is either a MNP or ARP child handle. But
   2651   IP opens these handle BY_DRIVER, use that info, we can get the
   2652   UNDI/SNP handle.
   2653 
   2654   @param[in]  Controller            Then protocol handle to check.
   2655   @param[in]  ProtocolGuid          The protocol that is related with the handle.
   2656 
   2657   @return The UNDI/SNP handle or NULL for errors.
   2658 
   2659 **/
   2660 EFI_HANDLE
   2661 EFIAPI
   2662 NetLibGetNicHandle (
   2663   IN EFI_HANDLE             Controller,
   2664   IN EFI_GUID               *ProtocolGuid
   2665   )
   2666 {
   2667   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenBuffer;
   2668   EFI_HANDLE                          Handle;
   2669   EFI_STATUS                          Status;
   2670   UINTN                               OpenCount;
   2671   UINTN                               Index;
   2672 
   2673   Status = gBS->OpenProtocolInformation (
   2674                   Controller,
   2675                   ProtocolGuid,
   2676                   &OpenBuffer,
   2677                   &OpenCount
   2678                   );
   2679 
   2680   if (EFI_ERROR (Status)) {
   2681     return NULL;
   2682   }
   2683 
   2684   Handle = NULL;
   2685 
   2686   for (Index = 0; Index < OpenCount; Index++) {
   2687     if ((OpenBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
   2688       Handle = OpenBuffer[Index].ControllerHandle;
   2689       break;
   2690     }
   2691   }
   2692 
   2693   gBS->FreePool (OpenBuffer);
   2694   return Handle;
   2695 }
   2696 
   2697 /**
   2698   Convert one Null-terminated ASCII string (decimal dotted) to EFI_IPv4_ADDRESS.
   2699 
   2700   @param[in]      String         The pointer to the Ascii string.
   2701   @param[out]     Ip4Address     The pointer to the converted IPv4 address.
   2702 
   2703   @retval EFI_SUCCESS            Convert to IPv4 address successfully.
   2704   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip4Address is NULL.
   2705 
   2706 **/
   2707 EFI_STATUS
   2708 EFIAPI
   2709 NetLibAsciiStrToIp4 (
   2710   IN CONST CHAR8                 *String,
   2711   OUT      EFI_IPv4_ADDRESS      *Ip4Address
   2712   )
   2713 {
   2714   UINT8                          Index;
   2715   CHAR8                          *Ip4Str;
   2716   CHAR8                          *TempStr;
   2717   UINTN                          NodeVal;
   2718 
   2719   if ((String == NULL) || (Ip4Address == NULL)) {
   2720     return EFI_INVALID_PARAMETER;
   2721   }
   2722 
   2723   Ip4Str = (CHAR8 *) String;
   2724 
   2725   for (Index = 0; Index < 4; Index++) {
   2726     TempStr = Ip4Str;
   2727 
   2728     while ((*Ip4Str != '\0') && (*Ip4Str != '.')) {
   2729       Ip4Str++;
   2730     }
   2731 
   2732     //
   2733     // The IPv4 address is X.X.X.X
   2734     //
   2735     if (*Ip4Str == '.') {
   2736       if (Index == 3) {
   2737         return EFI_INVALID_PARAMETER;
   2738       }
   2739     } else {
   2740       if (Index != 3) {
   2741         return EFI_INVALID_PARAMETER;
   2742       }
   2743     }
   2744 
   2745     //
   2746     // Convert the string to IPv4 address. AsciiStrDecimalToUintn stops at the
   2747     // first character that is not a valid decimal character, '.' or '\0' here.
   2748     //
   2749     NodeVal = AsciiStrDecimalToUintn (TempStr);
   2750     if (NodeVal > 0xFF) {
   2751       return EFI_INVALID_PARAMETER;
   2752     }
   2753 
   2754     Ip4Address->Addr[Index] = (UINT8) NodeVal;
   2755 
   2756     Ip4Str++;
   2757   }
   2758 
   2759   return EFI_SUCCESS;
   2760 }
   2761 
   2762 
   2763 /**
   2764   Convert one Null-terminated ASCII string to EFI_IPv6_ADDRESS. The format of the
   2765   string is defined in RFC 4291 - Text Pepresentation of Addresses.
   2766 
   2767   @param[in]      String         The pointer to the Ascii string.
   2768   @param[out]     Ip6Address     The pointer to the converted IPv6 address.
   2769 
   2770   @retval EFI_SUCCESS            Convert to IPv6 address successfully.
   2771   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip6Address is NULL.
   2772 
   2773 **/
   2774 EFI_STATUS
   2775 EFIAPI
   2776 NetLibAsciiStrToIp6 (
   2777   IN CONST CHAR8                 *String,
   2778   OUT      EFI_IPv6_ADDRESS      *Ip6Address
   2779   )
   2780 {
   2781   UINT8                          Index;
   2782   CHAR8                          *Ip6Str;
   2783   CHAR8                          *TempStr;
   2784   CHAR8                          *TempStr2;
   2785   UINT8                          NodeCnt;
   2786   UINT8                          TailNodeCnt;
   2787   UINT8                          AllowedCnt;
   2788   UINTN                          NodeVal;
   2789   BOOLEAN                        Short;
   2790   BOOLEAN                        Update;
   2791   BOOLEAN                        LeadZero;
   2792   UINT8                          LeadZeroCnt;
   2793   UINT8                          Cnt;
   2794 
   2795   if ((String == NULL) || (Ip6Address == NULL)) {
   2796     return EFI_INVALID_PARAMETER;
   2797   }
   2798 
   2799   Ip6Str      = (CHAR8 *) String;
   2800   AllowedCnt  = 6;
   2801   LeadZeroCnt = 0;
   2802 
   2803   //
   2804   // An IPv6 address leading with : looks strange.
   2805   //
   2806   if (*Ip6Str == ':') {
   2807     if (*(Ip6Str + 1) != ':') {
   2808       return EFI_INVALID_PARAMETER;
   2809     } else {
   2810       AllowedCnt = 7;
   2811     }
   2812   }
   2813 
   2814   ZeroMem (Ip6Address, sizeof (EFI_IPv6_ADDRESS));
   2815 
   2816   NodeCnt     = 0;
   2817   TailNodeCnt = 0;
   2818   Short       = FALSE;
   2819   Update      = FALSE;
   2820   LeadZero    = FALSE;
   2821 
   2822   for (Index = 0; Index < 15; Index = (UINT8) (Index + 2)) {
   2823     TempStr = Ip6Str;
   2824 
   2825     while ((*Ip6Str != '\0') && (*Ip6Str != ':')) {
   2826       Ip6Str++;
   2827     }
   2828 
   2829     if ((*Ip6Str == '\0') && (Index != 14)) {
   2830       return EFI_INVALID_PARAMETER;
   2831     }
   2832 
   2833     if (*Ip6Str == ':') {
   2834       if (*(Ip6Str + 1) == ':') {
   2835         if ((NodeCnt > 6) ||
   2836             ((*(Ip6Str + 2) != '\0') && (AsciiStrHexToUintn (Ip6Str + 2) == 0))) {
   2837           //
   2838           // ::0 looks strange. report error to user.
   2839           //
   2840           return EFI_INVALID_PARAMETER;
   2841         }
   2842         if ((NodeCnt == 6) && (*(Ip6Str + 2) != '\0') &&
   2843             (AsciiStrHexToUintn (Ip6Str + 2) != 0)) {
   2844           return EFI_INVALID_PARAMETER;
   2845         }
   2846 
   2847         //
   2848         // Skip the abbreviation part of IPv6 address.
   2849         //
   2850         TempStr2 = Ip6Str + 2;
   2851         while ((*TempStr2 != '\0')) {
   2852           if (*TempStr2 == ':') {
   2853             if (*(TempStr2 + 1) == ':') {
   2854               //
   2855               // :: can only appear once in IPv6 address.
   2856               //
   2857               return EFI_INVALID_PARAMETER;
   2858             }
   2859 
   2860             TailNodeCnt++;
   2861             if (TailNodeCnt >= (AllowedCnt - NodeCnt)) {
   2862               //
   2863               // :: indicates one or more groups of 16 bits of zeros.
   2864               //
   2865               return EFI_INVALID_PARAMETER;
   2866             }
   2867           }
   2868 
   2869           TempStr2++;
   2870         }
   2871 
   2872         Short  = TRUE;
   2873         Update = TRUE;
   2874 
   2875         Ip6Str = Ip6Str + 2;
   2876       } else {
   2877         if (*(Ip6Str + 1) == '\0') {
   2878           return EFI_INVALID_PARAMETER;
   2879         }
   2880         Ip6Str++;
   2881         NodeCnt++;
   2882         if ((Short && (NodeCnt > 6)) || (!Short && (NodeCnt > 7))) {
   2883           //
   2884           // There are more than 8 groups of 16 bits of zeros.
   2885           //
   2886           return EFI_INVALID_PARAMETER;
   2887         }
   2888       }
   2889     }
   2890 
   2891     //
   2892     // Convert the string to IPv6 address. AsciiStrHexToUintn stops at the first
   2893     // character that is not a valid hexadecimal character, ':' or '\0' here.
   2894     //
   2895     NodeVal = AsciiStrHexToUintn (TempStr);
   2896     if ((NodeVal > 0xFFFF) || (Index > 14)) {
   2897       return EFI_INVALID_PARAMETER;
   2898     }
   2899     if (NodeVal != 0) {
   2900       if ((*TempStr  == '0') &&
   2901           ((*(TempStr + 2) == ':') || (*(TempStr + 3) == ':') ||
   2902           (*(TempStr + 2) == '\0') || (*(TempStr + 3) == '\0'))) {
   2903         return EFI_INVALID_PARAMETER;
   2904       }
   2905       if ((*TempStr  == '0') && (*(TempStr + 4) != '\0') &&
   2906           (*(TempStr + 4) != ':')) {
   2907         return EFI_INVALID_PARAMETER;
   2908       }
   2909     } else {
   2910       if (((*TempStr  == '0') && (*(TempStr + 1) == '0') &&
   2911           ((*(TempStr + 2) == ':') || (*(TempStr + 2) == '\0'))) ||
   2912           ((*TempStr  == '0') && (*(TempStr + 1) == '0') && (*(TempStr + 2) == '0') &&
   2913           ((*(TempStr + 3) == ':') || (*(TempStr + 3) == '\0')))) {
   2914         return EFI_INVALID_PARAMETER;
   2915       }
   2916     }
   2917 
   2918     Cnt = 0;
   2919     while ((TempStr[Cnt] != ':') && (TempStr[Cnt] != '\0')) {
   2920       Cnt++;
   2921     }
   2922     if (LeadZeroCnt == 0) {
   2923       if ((Cnt == 4) && (*TempStr  == '0')) {
   2924         LeadZero = TRUE;
   2925         LeadZeroCnt++;
   2926       }
   2927       if ((Cnt != 0) && (Cnt < 4)) {
   2928         LeadZero = FALSE;
   2929         LeadZeroCnt++;
   2930       }
   2931     } else {
   2932       if ((Cnt == 4) && (*TempStr  == '0') && !LeadZero) {
   2933         return EFI_INVALID_PARAMETER;
   2934       }
   2935       if ((Cnt != 0) && (Cnt < 4) && LeadZero) {
   2936         return EFI_INVALID_PARAMETER;
   2937       }
   2938     }
   2939 
   2940     Ip6Address->Addr[Index] = (UINT8) (NodeVal >> 8);
   2941     Ip6Address->Addr[Index + 1] = (UINT8) (NodeVal & 0xFF);
   2942 
   2943     //
   2944     // Skip the groups of zeros by ::
   2945     //
   2946     if (Short && Update) {
   2947       Index  = (UINT8) (16 - (TailNodeCnt + 2) * 2);
   2948       Update = FALSE;
   2949     }
   2950   }
   2951 
   2952   if ((!Short && Index != 16) || (*Ip6Str != '\0')) {
   2953     return EFI_INVALID_PARAMETER;
   2954   }
   2955 
   2956   return EFI_SUCCESS;
   2957 }
   2958 
   2959 
   2960 /**
   2961   Convert one Null-terminated Unicode string (decimal dotted) to EFI_IPv4_ADDRESS.
   2962 
   2963   @param[in]      String         The pointer to the Ascii string.
   2964   @param[out]     Ip4Address     The pointer to the converted IPv4 address.
   2965 
   2966   @retval EFI_SUCCESS            Convert to IPv4 address successfully.
   2967   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip4Address is NULL.
   2968   @retval EFI_OUT_OF_RESOURCES   Fail to perform the operation due to lack of resource.
   2969 
   2970 **/
   2971 EFI_STATUS
   2972 EFIAPI
   2973 NetLibStrToIp4 (
   2974   IN CONST CHAR16                *String,
   2975   OUT      EFI_IPv4_ADDRESS      *Ip4Address
   2976   )
   2977 {
   2978   CHAR8                          *Ip4Str;
   2979   EFI_STATUS                     Status;
   2980 
   2981   if ((String == NULL) || (Ip4Address == NULL)) {
   2982     return EFI_INVALID_PARAMETER;
   2983   }
   2984 
   2985   Ip4Str = (CHAR8 *) AllocatePool ((StrLen (String) + 1) * sizeof (CHAR8));
   2986   if (Ip4Str == NULL) {
   2987     return EFI_OUT_OF_RESOURCES;
   2988   }
   2989 
   2990   UnicodeStrToAsciiStr (String, Ip4Str);
   2991 
   2992   Status = NetLibAsciiStrToIp4 (Ip4Str, Ip4Address);
   2993 
   2994   FreePool (Ip4Str);
   2995 
   2996   return Status;
   2997 }
   2998 
   2999 
   3000 /**
   3001   Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS.  The format of
   3002   the string is defined in RFC 4291 - Text Pepresentation of Addresses.
   3003 
   3004   @param[in]      String         The pointer to the Ascii string.
   3005   @param[out]     Ip6Address     The pointer to the converted IPv6 address.
   3006 
   3007   @retval EFI_SUCCESS            Convert to IPv6 address successfully.
   3008   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip6Address is NULL.
   3009   @retval EFI_OUT_OF_RESOURCES   Fail to perform the operation due to lack of resource.
   3010 
   3011 **/
   3012 EFI_STATUS
   3013 EFIAPI
   3014 NetLibStrToIp6 (
   3015   IN CONST CHAR16                *String,
   3016   OUT      EFI_IPv6_ADDRESS      *Ip6Address
   3017   )
   3018 {
   3019   CHAR8                          *Ip6Str;
   3020   EFI_STATUS                     Status;
   3021 
   3022   if ((String == NULL) || (Ip6Address == NULL)) {
   3023     return EFI_INVALID_PARAMETER;
   3024   }
   3025 
   3026   Ip6Str = (CHAR8 *) AllocatePool ((StrLen (String) + 1) * sizeof (CHAR8));
   3027   if (Ip6Str == NULL) {
   3028     return EFI_OUT_OF_RESOURCES;
   3029   }
   3030 
   3031   UnicodeStrToAsciiStr (String, Ip6Str);
   3032 
   3033   Status = NetLibAsciiStrToIp6 (Ip6Str, Ip6Address);
   3034 
   3035   FreePool (Ip6Str);
   3036 
   3037   return Status;
   3038 }
   3039 
   3040 /**
   3041   Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS and prefix length.
   3042   The format of the string is defined in RFC 4291 - Text Pepresentation of Addresses
   3043   Prefixes: ipv6-address/prefix-length.
   3044 
   3045   @param[in]      String         The pointer to the Ascii string.
   3046   @param[out]     Ip6Address     The pointer to the converted IPv6 address.
   3047   @param[out]     PrefixLength   The pointer to the converted prefix length.
   3048 
   3049   @retval EFI_SUCCESS            Convert to IPv6 address successfully.
   3050   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip6Address is NULL.
   3051   @retval EFI_OUT_OF_RESOURCES   Fail to perform the operation due to lack of resource.
   3052 
   3053 **/
   3054 EFI_STATUS
   3055 EFIAPI
   3056 NetLibStrToIp6andPrefix (
   3057   IN CONST CHAR16                *String,
   3058   OUT      EFI_IPv6_ADDRESS      *Ip6Address,
   3059   OUT      UINT8                 *PrefixLength
   3060   )
   3061 {
   3062   CHAR8                          *Ip6Str;
   3063   CHAR8                          *PrefixStr;
   3064   CHAR8                          *TempStr;
   3065   EFI_STATUS                     Status;
   3066   UINT8                          Length;
   3067 
   3068   if ((String == NULL) || (Ip6Address == NULL) || (PrefixLength == NULL)) {
   3069     return EFI_INVALID_PARAMETER;
   3070   }
   3071 
   3072   Ip6Str = (CHAR8 *) AllocatePool ((StrLen (String) + 1) * sizeof (CHAR8));
   3073   if (Ip6Str == NULL) {
   3074     return EFI_OUT_OF_RESOURCES;
   3075   }
   3076 
   3077   UnicodeStrToAsciiStr (String, Ip6Str);
   3078 
   3079   //
   3080   // Get the sub string describing prefix length.
   3081   //
   3082   TempStr = Ip6Str;
   3083   while (*TempStr != '\0' && (*TempStr != '/')) {
   3084     TempStr++;
   3085   }
   3086 
   3087   if (*TempStr == '/') {
   3088     PrefixStr = TempStr + 1;
   3089   } else {
   3090     PrefixStr = NULL;
   3091   }
   3092 
   3093   //
   3094   // Get the sub string describing IPv6 address and convert it.
   3095   //
   3096   *TempStr = '\0';
   3097 
   3098   Status = NetLibAsciiStrToIp6 (Ip6Str, Ip6Address);
   3099   if (EFI_ERROR (Status)) {
   3100     goto Exit;
   3101   }
   3102 
   3103   //
   3104   // If input string doesn't indicate the prefix length, return 0xff.
   3105   //
   3106   Length = 0xFF;
   3107 
   3108   //
   3109   // Convert the string to prefix length
   3110   //
   3111   if (PrefixStr != NULL) {
   3112 
   3113     Status = EFI_INVALID_PARAMETER;
   3114     Length = 0;
   3115     while (*PrefixStr != '\0') {
   3116       if (NET_IS_DIGIT (*PrefixStr)) {
   3117         Length = (UINT8) (Length * 10 + (*PrefixStr - '0'));
   3118         if (Length >= IP6_PREFIX_NUM) {
   3119           goto Exit;
   3120         }
   3121       } else {
   3122         goto Exit;
   3123       }
   3124 
   3125       PrefixStr++;
   3126     }
   3127   }
   3128 
   3129   *PrefixLength = Length;
   3130   Status        = EFI_SUCCESS;
   3131 
   3132 Exit:
   3133 
   3134   FreePool (Ip6Str);
   3135   return Status;
   3136 }
   3137 
   3138 /**
   3139 
   3140   Convert one EFI_IPv6_ADDRESS to Null-terminated Unicode string.
   3141   The text representation of address is defined in RFC 4291.
   3142 
   3143   @param[in]       Ip6Address     The pointer to the IPv6 address.
   3144   @param[out]      String         The buffer to return the converted string.
   3145   @param[in]       StringSize     The length in bytes of the input String.
   3146 
   3147   @retval EFI_SUCCESS             Convert to string successfully.
   3148   @retval EFI_INVALID_PARAMETER   The input parameter is invalid.
   3149   @retval EFI_BUFFER_TOO_SMALL    The BufferSize is too small for the result. BufferSize has been
   3150                                   updated with the size needed to complete the request.
   3151 **/
   3152 EFI_STATUS
   3153 EFIAPI
   3154 NetLibIp6ToStr (
   3155   IN         EFI_IPv6_ADDRESS      *Ip6Address,
   3156   OUT        CHAR16                *String,
   3157   IN         UINTN                 StringSize
   3158   )
   3159 {
   3160   UINT16     Ip6Addr[8];
   3161   UINTN      Index;
   3162   UINTN      LongestZerosStart;
   3163   UINTN      LongestZerosLength;
   3164   UINTN      CurrentZerosStart;
   3165   UINTN      CurrentZerosLength;
   3166   CHAR16     Buffer[sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
   3167   CHAR16     *Ptr;
   3168 
   3169   if (Ip6Address == NULL || String == NULL || StringSize == 0) {
   3170     return EFI_INVALID_PARAMETER;
   3171   }
   3172 
   3173   //
   3174   // Convert the UINT8 array to an UINT16 array for easy handling.
   3175   //
   3176   ZeroMem (Ip6Addr, sizeof (Ip6Addr));
   3177   for (Index = 0; Index < 16; Index++) {
   3178     Ip6Addr[Index / 2] |= (Ip6Address->Addr[Index] << ((1 - (Index % 2)) << 3));
   3179   }
   3180 
   3181   //
   3182   // Find the longest zeros and mark it.
   3183   //
   3184   CurrentZerosStart  = DEFAULT_ZERO_START;
   3185   CurrentZerosLength = 0;
   3186   LongestZerosStart  = DEFAULT_ZERO_START;
   3187   LongestZerosLength = 0;
   3188   for (Index = 0; Index < 8; Index++) {
   3189     if (Ip6Addr[Index] == 0) {
   3190       if (CurrentZerosStart == DEFAULT_ZERO_START) {
   3191         CurrentZerosStart = Index;
   3192         CurrentZerosLength = 1;
   3193       } else {
   3194         CurrentZerosLength++;
   3195       }
   3196     } else {
   3197       if (CurrentZerosStart != DEFAULT_ZERO_START) {
   3198         if (CurrentZerosLength > 2 && (LongestZerosStart == (DEFAULT_ZERO_START) || CurrentZerosLength > LongestZerosLength)) {
   3199           LongestZerosStart  = CurrentZerosStart;
   3200           LongestZerosLength = CurrentZerosLength;
   3201         }
   3202         CurrentZerosStart  = DEFAULT_ZERO_START;
   3203         CurrentZerosLength = 0;
   3204       }
   3205     }
   3206   }
   3207 
   3208   if (CurrentZerosStart != DEFAULT_ZERO_START && CurrentZerosLength > 2) {
   3209     if (LongestZerosStart == DEFAULT_ZERO_START || LongestZerosLength < CurrentZerosLength) {
   3210       LongestZerosStart  = CurrentZerosStart;
   3211       LongestZerosLength = CurrentZerosLength;
   3212     }
   3213   }
   3214 
   3215   Ptr = Buffer;
   3216   for (Index = 0; Index < 8; Index++) {
   3217     if (LongestZerosStart != DEFAULT_ZERO_START && Index >= LongestZerosStart && Index < LongestZerosStart + LongestZerosLength) {
   3218       if (Index == LongestZerosStart) {
   3219         *Ptr++ = L':';
   3220       }
   3221       continue;
   3222     }
   3223     if (Index != 0) {
   3224       *Ptr++ = L':';
   3225     }
   3226     Ptr += UnicodeSPrint(Ptr, 10, L"%x", Ip6Addr[Index]);
   3227   }
   3228 
   3229   if (LongestZerosStart != DEFAULT_ZERO_START && LongestZerosStart + LongestZerosLength == 8) {
   3230     *Ptr++ = L':';
   3231   }
   3232   *Ptr = L'\0';
   3233 
   3234   if ((UINTN)Ptr - (UINTN)Buffer > StringSize) {
   3235     return EFI_BUFFER_TOO_SMALL;
   3236   }
   3237 
   3238   StrCpyS (String, StringSize / sizeof (CHAR16), Buffer);
   3239 
   3240   return EFI_SUCCESS;
   3241 }
   3242 
   3243 /**
   3244   This function obtains the system guid from the smbios table.
   3245 
   3246   @param[out]  SystemGuid     The pointer of the returned system guid.
   3247 
   3248   @retval EFI_SUCCESS         Successfully obtained the system guid.
   3249   @retval EFI_NOT_FOUND       Did not find the SMBIOS table.
   3250 
   3251 **/
   3252 EFI_STATUS
   3253 EFIAPI
   3254 NetLibGetSystemGuid (
   3255   OUT EFI_GUID              *SystemGuid
   3256   )
   3257 {
   3258   EFI_STATUS                    Status;
   3259   SMBIOS_TABLE_ENTRY_POINT      *SmbiosTable;
   3260   SMBIOS_TABLE_3_0_ENTRY_POINT  *Smbios30Table;
   3261   SMBIOS_STRUCTURE_POINTER      Smbios;
   3262   SMBIOS_STRUCTURE_POINTER      SmbiosEnd;
   3263   CHAR8                         *String;
   3264 
   3265   SmbiosTable = NULL;
   3266   Status = EfiGetSystemConfigurationTable (&gEfiSmbios3TableGuid, (VOID **) &Smbios30Table);
   3267   if (!(EFI_ERROR (Status) || Smbios30Table == NULL)) {
   3268     Smbios.Hdr = (SMBIOS_STRUCTURE *) (UINTN) Smbios30Table->TableAddress;
   3269     SmbiosEnd.Raw = (UINT8 *) (UINTN) (Smbios30Table->TableAddress + Smbios30Table->TableMaximumSize);
   3270   } else {
   3271     Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SmbiosTable);
   3272     if (EFI_ERROR (Status) || SmbiosTable == NULL) {
   3273       return EFI_NOT_FOUND;
   3274     }
   3275     Smbios.Hdr    = (SMBIOS_STRUCTURE *) (UINTN) SmbiosTable->TableAddress;
   3276     SmbiosEnd.Raw = (UINT8 *) (UINTN) (SmbiosTable->TableAddress + SmbiosTable->TableLength);
   3277   }
   3278 
   3279   do {
   3280     if (Smbios.Hdr->Type == 1) {
   3281       if (Smbios.Hdr->Length < 0x19) {
   3282         //
   3283         // Older version did not support UUID.
   3284         //
   3285         return EFI_NOT_FOUND;
   3286       }
   3287 
   3288       //
   3289       // SMBIOS tables are byte packed so we need to do a byte copy to
   3290       // prevend alignment faults on Itanium-based platform.
   3291       //
   3292       CopyMem (SystemGuid, &Smbios.Type1->Uuid, sizeof (EFI_GUID));
   3293       return EFI_SUCCESS;
   3294     }
   3295 
   3296     //
   3297     // Go to the next SMBIOS structure. Each SMBIOS structure may include 2 parts:
   3298     // 1. Formatted section; 2. Unformatted string section. So, 2 steps are needed
   3299     // to skip one SMBIOS structure.
   3300     //
   3301 
   3302     //
   3303     // Step 1: Skip over formatted section.
   3304     //
   3305     String = (CHAR8 *) (Smbios.Raw + Smbios.Hdr->Length);
   3306 
   3307     //
   3308     // Step 2: Skip over unformated string section.
   3309     //
   3310     do {
   3311       //
   3312       // Each string is terminated with a NULL(00h) BYTE and the sets of strings
   3313       // is terminated with an additional NULL(00h) BYTE.
   3314       //
   3315       for ( ; *String != 0; String++) {
   3316       }
   3317 
   3318       if (*(UINT8*)++String == 0) {
   3319         //
   3320         // Pointer to the next SMBIOS structure.
   3321         //
   3322         Smbios.Raw = (UINT8 *)++String;
   3323         break;
   3324       }
   3325     } while (TRUE);
   3326   } while (Smbios.Raw < SmbiosEnd.Raw);
   3327   return EFI_NOT_FOUND;
   3328 }
   3329