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