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