• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *
SyslogLocateSnp(VOID)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
SyslogSendPacket(IN CHAR8 * Packet,IN UINT32 Length)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
SyslogBuildPacket(IN UINT32 Level,IN UINT8 * Module,IN UINT8 * File,IN UINT32 Line,IN UINT8 * Message,IN UINT32 BufLen,OUT CHAR8 * Buf)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
NetDebugASPrint(IN CHAR8 * Format,...)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
NetDebugOutput(IN UINT32 Level,IN UINT8 * Module,IN UINT8 * File,IN UINT32 Line,IN UINT8 * Message)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
NetGetMaskLength(IN IP4_ADDR NetMask)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
NetGetIpClass(IN IP4_ADDR Addr)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
NetIp4IsUnicast(IN IP4_ADDR Ip,IN IP4_ADDR NetMask)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
NetIp6IsValidUnicast(IN EFI_IPv6_ADDRESS * Ip6)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
NetIp6IsUnspecifiedAddr(IN EFI_IPv6_ADDRESS * Ip6)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
NetIp6IsLinkLocalAddr(IN EFI_IPv6_ADDRESS * Ip6)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
NetIp6IsNetEqual(EFI_IPv6_ADDRESS * Ip1,EFI_IPv6_ADDRESS * Ip2,UINT8 PrefixLength)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
Ip6Swap128(EFI_IPv6_ADDRESS * Ip6)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
NetRandomInitSeed(VOID)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
NetGetUint32(IN UINT8 * Buf)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
NetPutUint32(IN OUT UINT8 * Buf,IN UINT32 Data)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
NetListRemoveHead(IN OUT LIST_ENTRY * Head)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
NetListRemoveTail(IN OUT LIST_ENTRY * Head)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
NetListInsertAfter(IN OUT LIST_ENTRY * PrevEntry,IN OUT LIST_ENTRY * NewEntry)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
NetListInsertBefore(IN OUT LIST_ENTRY * PostEntry,IN OUT LIST_ENTRY * NewEntry)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
NetDestroyLinkList(IN LIST_ENTRY * List,IN NET_DESTROY_LINK_LIST_CALLBACK CallBack,IN VOID * Context,OPTIONAL OUT UINTN * ListLength OPTIONAL)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
NetIsInHandleBuffer(IN EFI_HANDLE Handle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)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
NetMapInit(IN OUT NET_MAP * Map)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
NetMapClean(IN OUT NET_MAP * Map)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
NetMapIsEmpty(IN NET_MAP * Map)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
NetMapGetCount(IN NET_MAP * Map)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 *
NetMapAllocItem(IN OUT NET_MAP * Map)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
NetMapInsertHead(IN OUT NET_MAP * Map,IN VOID * Key,IN VOID * Value OPTIONAL)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
NetMapInsertTail(IN OUT NET_MAP * Map,IN VOID * Key,IN VOID * Value OPTIONAL)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
NetItemInMap(IN NET_MAP * Map,IN NET_MAP_ITEM * Item)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
NetMapFindKey(IN NET_MAP * Map,IN VOID * Key)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
NetMapRemoveItem(IN OUT NET_MAP * Map,IN OUT NET_MAP_ITEM * Item,OUT VOID ** Value OPTIONAL)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
NetMapRemoveHead(IN OUT NET_MAP * Map,OUT VOID ** Value OPTIONAL)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
NetMapRemoveTail(IN OUT NET_MAP * Map,OUT VOID ** Value OPTIONAL)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
NetMapIterate(IN NET_MAP * Map,IN NET_MAP_CALLBACK CallBack,IN VOID * Arg OPTIONAL)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
NetLibDefaultUnload(IN EFI_HANDLE ImageHandle)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
NetLibCreateServiceChild(IN EFI_HANDLE Controller,IN EFI_HANDLE Image,IN EFI_GUID * ServiceBindingGuid,IN OUT EFI_HANDLE * ChildHandle)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
NetLibDestroyServiceChild(IN EFI_HANDLE Controller,IN EFI_HANDLE Image,IN EFI_GUID * ServiceBindingGuid,IN EFI_HANDLE ChildHandle)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
NetLibGetSnpHandle(IN EFI_HANDLE ServiceHandle,OUT EFI_SIMPLE_NETWORK_PROTOCOL ** Snp OPTIONAL)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
NetLibGetVlanId(IN EFI_HANDLE ServiceHandle)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
NetLibGetVlanHandle(IN EFI_HANDLE ControllerHandle,IN UINT16 VlanId)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
NetLibGetMacAddress(IN EFI_HANDLE ServiceHandle,OUT EFI_MAC_ADDRESS * MacAddress,OUT UINTN * AddressSize)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
NetLibGetMacString(IN EFI_HANDLE ServiceHandle,IN EFI_HANDLE ImageHandle,OPTIONAL OUT CHAR16 ** MacString)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
NetLibDetectMedia(IN EFI_HANDLE ServiceHandle,OUT BOOLEAN * MediaPresent)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
NetLibDefaultAddressIsStatic(IN EFI_HANDLE Controller)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
NetLibCreateIPv4DPathNode(IN OUT IPv4_DEVICE_PATH * Node,IN EFI_HANDLE Controller,IN IP4_ADDR LocalIp,IN UINT16 LocalPort,IN IP4_ADDR RemoteIp,IN UINT16 RemotePort,IN UINT16 Protocol,IN BOOLEAN UseDefaultAddress)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
NetLibCreateIPv6DPathNode(IN OUT IPv6_DEVICE_PATH * Node,IN EFI_HANDLE Controller,IN EFI_IPv6_ADDRESS * LocalIp,IN UINT16 LocalPort,IN EFI_IPv6_ADDRESS * RemoteIp,IN UINT16 RemotePort,IN UINT16 Protocol)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
NetLibGetNicHandle(IN EFI_HANDLE Controller,IN EFI_GUID * ProtocolGuid)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
NetLibAsciiStrToIp4(IN CONST CHAR8 * String,OUT EFI_IPv4_ADDRESS * Ip4Address)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
NetLibAsciiStrToIp6(IN CONST CHAR8 * String,OUT EFI_IPv6_ADDRESS * Ip6Address)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
NetLibStrToIp4(IN CONST CHAR16 * String,OUT EFI_IPv4_ADDRESS * Ip4Address)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
NetLibStrToIp6(IN CONST CHAR16 * String,OUT EFI_IPv6_ADDRESS * Ip6Address)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
NetLibStrToIp6andPrefix(IN CONST CHAR16 * String,OUT EFI_IPv6_ADDRESS * Ip6Address,OUT UINT8 * PrefixLength)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
NetLibIp6ToStr(IN EFI_IPv6_ADDRESS * Ip6Address,OUT CHAR16 * String,IN UINTN StringSize)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
NetLibGetSystemGuid(OUT EFI_GUID * SystemGuid)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