9ab7ab07c082a4e02362f64842793075db21dfb0
[efi/edk2/.git] / edk2 / MdeModulePkg / Library / DxeNetLib / DxeNetLib.c
1 /** @file\r
2   Network library.\r
3 \r
4 Copyright (c) 2005 - 2010, Intel Corporation.<BR>\r
5 All rights reserved. This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution.  The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9 \r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 **/\r
13 \r
14 #include <Uefi.h>\r
15 \r
16 #include <Protocol/DriverBinding.h>\r
17 #include <Protocol/ServiceBinding.h>\r
18 #include <Protocol/SimpleNetwork.h>\r
19 #include <Protocol/ManagedNetwork.h>\r
20 #include <Protocol/HiiConfigRouting.h>\r
21 #include <Protocol/ComponentName.h>\r
22 #include <Protocol/ComponentName2.h>\r
23 \r
24 #include <Guid/NicIp4ConfigNvData.h>\r
25 \r
26 #include <Library/NetLib.h>\r
27 #include <Library/BaseLib.h>\r
28 #include <Library/DebugLib.h>\r
29 #include <Library/BaseMemoryLib.h>\r
30 #include <Library/UefiBootServicesTableLib.h>\r
31 #include <Library/UefiRuntimeServicesTableLib.h>\r
32 #include <Library/MemoryAllocationLib.h>\r
33 #include <Library/DevicePathLib.h>\r
34 #include <Library/HiiLib.h>\r
35 #include <Library/PrintLib.h>\r
36 \r
37 #define NIC_ITEM_CONFIG_SIZE   sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE\r
38 \r
39 //\r
40 // All the supported IP4 maskes in host byte order.\r
41 //\r
42 GLOBAL_REMOVE_IF_UNREFERENCED IP4_ADDR  gIp4AllMasks[IP4_MASK_NUM] = {\r
43   0x00000000,\r
44   0x80000000,\r
45   0xC0000000,\r
46   0xE0000000,\r
47   0xF0000000,\r
48   0xF8000000,\r
49   0xFC000000,\r
50   0xFE000000,\r
51 \r
52   0xFF000000,\r
53   0xFF800000,\r
54   0xFFC00000,\r
55   0xFFE00000,\r
56   0xFFF00000,\r
57   0xFFF80000,\r
58   0xFFFC0000,\r
59   0xFFFE0000,\r
60 \r
61   0xFFFF0000,\r
62   0xFFFF8000,\r
63   0xFFFFC000,\r
64   0xFFFFE000,\r
65   0xFFFFF000,\r
66   0xFFFFF800,\r
67   0xFFFFFC00,\r
68   0xFFFFFE00,\r
69 \r
70   0xFFFFFF00,\r
71   0xFFFFFF80,\r
72   0xFFFFFFC0,\r
73   0xFFFFFFE0,\r
74   0xFFFFFFF0,\r
75   0xFFFFFFF8,\r
76   0xFFFFFFFC,\r
77   0xFFFFFFFE,\r
78   0xFFFFFFFF,\r
79 };\r
80 \r
81 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IPv4_ADDRESS  mZeroIp4Addr = {{0, 0, 0, 0}};\r
82 \r
83 //\r
84 // Any error level digitally larger than mNetDebugLevelMax\r
85 // will be silently discarded.\r
86 //\r
87 GLOBAL_REMOVE_IF_UNREFERENCED UINTN  mNetDebugLevelMax = NETDEBUG_LEVEL_ERROR;\r
88 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogPacketSeq  = 0xDEADBEEF;\r
89 \r
90 //\r
91 // You can change mSyslogDstMac mSyslogDstIp and mSyslogSrcIp\r
92 // here to direct the syslog packets to the syslog deamon. The\r
93 // default is broadcast to both the ethernet and IP.\r
94 //\r
95 GLOBAL_REMOVE_IF_UNREFERENCED UINT8  mSyslogDstMac[NET_ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
96 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogDstIp                      = 0xffffffff;\r
97 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogSrcIp                      = 0;\r
98 \r
99 GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mMonthName[] = {\r
100   "Jan",\r
101   "Feb",\r
102   "Mar",\r
103   "Apr",\r
104   "May",\r
105   "Jun",\r
106   "Jul",\r
107   "Aug",\r
108   "Sep",\r
109   "Oct",\r
110   "Nov",\r
111   "Dec"\r
112 };\r
113 \r
114 //\r
115 // VLAN device path node template\r
116 //\r
117 GLOBAL_REMOVE_IF_UNREFERENCED VLAN_DEVICE_PATH mNetVlanDevicePathTemplate = {\r
118   {\r
119     MESSAGING_DEVICE_PATH,\r
120     MSG_VLAN_DP,\r
121     {\r
122       (UINT8) (sizeof (VLAN_DEVICE_PATH)),\r
123       (UINT8) ((sizeof (VLAN_DEVICE_PATH)) >> 8)\r
124     }\r
125   },\r
126   0\r
127 };\r
128 \r
129 /**\r
130   Locate the handles that support SNP, then open one of them\r
131   to send the syslog packets. The caller isn't required to close\r
132   the SNP after use because the SNP is opened by HandleProtocol.\r
133 \r
134   @return The point to SNP if one is properly openned. Otherwise NULL\r
135 \r
136 **/\r
137 EFI_SIMPLE_NETWORK_PROTOCOL *\r
138 SyslogLocateSnp (\r
139   VOID\r
140   )\r
141 {\r
142   EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
143   EFI_STATUS                  Status;\r
144   EFI_HANDLE                  *Handles;\r
145   UINTN                       HandleCount;\r
146   UINTN                       Index;\r
147 \r
148   //\r
149   // Locate the handles which has SNP installed.\r
150   //\r
151   Handles = NULL;\r
152   Status  = gBS->LocateHandleBuffer (\r
153                    ByProtocol,\r
154                    &gEfiSimpleNetworkProtocolGuid,\r
155                    NULL,\r
156                    &HandleCount,\r
157                    &Handles\r
158                    );\r
159 \r
160   if (EFI_ERROR (Status) || (HandleCount == 0)) {\r
161     return NULL;\r
162   }\r
163 \r
164   //\r
165   // Try to open one of the ethernet SNP protocol to send packet\r
166   //\r
167   Snp = NULL;\r
168 \r
169   for (Index = 0; Index < HandleCount; Index++) {\r
170     Status = gBS->HandleProtocol (\r
171                     Handles[Index],\r
172                     &gEfiSimpleNetworkProtocolGuid,\r
173                     (VOID **) &Snp\r
174                     );\r
175 \r
176     if ((Status == EFI_SUCCESS) && (Snp != NULL) &&\r
177         (Snp->Mode->IfType == NET_IFTYPE_ETHERNET) &&\r
178         (Snp->Mode->MaxPacketSize >= NET_SYSLOG_PACKET_LEN)) {\r
179 \r
180       break;\r
181     }\r
182 \r
183     Snp = NULL;\r
184   }\r
185 \r
186   FreePool (Handles);\r
187   return Snp;\r
188 }\r
189 \r
190 /**\r
191   Transmit a syslog packet synchronously through SNP. The Packet\r
192   already has the ethernet header prepended. This function should\r
193   fill in the source MAC because it will try to locate a SNP each\r
194   time it is called to avoid the problem if SNP is unloaded.\r
195   This code snip is copied from MNP.\r
196 \r
197   @param[in] Packet          The Syslog packet\r
198   @param[in] Length          The length of the packet\r
199 \r
200   @retval EFI_DEVICE_ERROR   Failed to locate a usable SNP protocol\r
201   @retval EFI_TIMEOUT        Timeout happened to send the packet.\r
202   @retval EFI_SUCCESS        Packet is sent.\r
203 \r
204 **/\r
205 EFI_STATUS\r
206 SyslogSendPacket (\r
207   IN CHAR8                    *Packet,\r
208   IN UINT32                   Length\r
209   )\r
210 {\r
211   EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
212   ETHER_HEAD                  *Ether;\r
213   EFI_STATUS                  Status;\r
214   EFI_EVENT                   TimeoutEvent;\r
215   UINT8                       *TxBuf;\r
216 \r
217   Snp = SyslogLocateSnp ();\r
218 \r
219   if (Snp == NULL) {\r
220     return EFI_DEVICE_ERROR;\r
221   }\r
222 \r
223   Ether = (ETHER_HEAD *) Packet;\r
224   CopyMem (Ether->SrcMac, Snp->Mode->CurrentAddress.Addr, NET_ETHER_ADDR_LEN);\r
225 \r
226   //\r
227   // Start the timeout event.\r
228   //\r
229   Status = gBS->CreateEvent (\r
230                   EVT_TIMER,\r
231                   TPL_NOTIFY,\r
232                   NULL,\r
233                   NULL,\r
234                   &TimeoutEvent\r
235                   );\r
236 \r
237   if (EFI_ERROR (Status)) {\r
238     return Status;\r
239   }\r
240 \r
241   Status = gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);\r
242 \r
243   if (EFI_ERROR (Status)) {\r
244     goto ON_EXIT;\r
245   }\r
246 \r
247   for (;;) {\r
248     //\r
249     // Transmit the packet through SNP.\r
250     //\r
251     Status = Snp->Transmit (Snp, 0, Length, Packet, NULL, NULL, NULL);\r
252 \r
253     if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {\r
254       Status = EFI_DEVICE_ERROR;\r
255       break;\r
256     }\r
257 \r
258     //\r
259     // If Status is EFI_SUCCESS, the packet is put in the transmit queue.\r
260     // if Status is EFI_NOT_READY, the transmit engine of the network\r
261     // interface is busy. Both need to sync SNP.\r
262     //\r
263     TxBuf = NULL;\r
264 \r
265     do {\r
266       //\r
267       // Get the recycled transmit buffer status.\r
268       //\r
269       Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf);\r
270 \r
271       if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
272         Status = EFI_TIMEOUT;\r
273         break;\r
274       }\r
275 \r
276     } while (TxBuf == NULL);\r
277 \r
278     if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {\r
279       break;\r
280     }\r
281 \r
282     //\r
283     // Status is EFI_NOT_READY. Restart the timer event and\r
284     // call Snp->Transmit again.\r
285     //\r
286     gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);\r
287   }\r
288 \r
289   gBS->SetTimer (TimeoutEvent, TimerCancel, 0);\r
290 \r
291 ON_EXIT:\r
292   gBS->CloseEvent (TimeoutEvent);\r
293   return Status;\r
294 }\r
295 \r
296 /**\r
297   Build a syslog packet, including the Ethernet/Ip/Udp headers\r
298   and user's message.\r
299 \r
300   @param[in]  Level     Syslog servity level\r
301   @param[in]  Module    The module that generates the log\r
302   @param[in]  File      The file that contains the current log\r
303   @param[in]  Line      The line of code in the File that contains the current log\r
304   @param[in]  Message   The log message\r
305   @param[in]  BufLen    The lenght of the Buf\r
306   @param[out] Buf       The buffer to put the packet data\r
307 \r
308   @return The length of the syslog packet built.\r
309 \r
310 **/\r
311 UINT32\r
312 SyslogBuildPacket (\r
313   IN  UINT32                Level,\r
314   IN  UINT8                 *Module,\r
315   IN  UINT8                 *File,\r
316   IN  UINT32                Line,\r
317   IN  UINT8                 *Message,\r
318   IN  UINT32                BufLen,\r
319   OUT CHAR8                 *Buf\r
320   )\r
321 {\r
322   ETHER_HEAD                *Ether;\r
323   IP4_HEAD                  *Ip4;\r
324   EFI_UDP_HEADER            *Udp4;\r
325   EFI_TIME                  Time;\r
326   UINT32                    Pri;\r
327   UINT32                    Len;\r
328 \r
329   //\r
330   // Fill in the Ethernet header. Leave alone the source MAC.\r
331   // SyslogSendPacket will fill in the address for us.\r
332   //\r
333   Ether = (ETHER_HEAD *) Buf;\r
334   CopyMem (Ether->DstMac, mSyslogDstMac, NET_ETHER_ADDR_LEN);\r
335   ZeroMem (Ether->SrcMac, NET_ETHER_ADDR_LEN);\r
336 \r
337   Ether->EtherType = HTONS (0x0800);    // IPv4 protocol\r
338 \r
339   Buf             += sizeof (ETHER_HEAD);\r
340   BufLen          -= sizeof (ETHER_HEAD);\r
341 \r
342   //\r
343   // Fill in the IP header\r
344   //\r
345   Ip4              = (IP4_HEAD *) Buf;\r
346   Ip4->HeadLen     = 5;\r
347   Ip4->Ver         = 4;\r
348   Ip4->Tos         = 0;\r
349   Ip4->TotalLen    = 0;\r
350   Ip4->Id          = (UINT16) mSyslogPacketSeq;\r
351   Ip4->Fragment    = 0;\r
352   Ip4->Ttl         = 16;\r
353   Ip4->Protocol    = 0x11;\r
354   Ip4->Checksum    = 0;\r
355   Ip4->Src         = mSyslogSrcIp;\r
356   Ip4->Dst         = mSyslogDstIp;\r
357 \r
358   Buf             += sizeof (IP4_HEAD);\r
359   BufLen          -= sizeof (IP4_HEAD);\r
360 \r
361   //\r
362   // Fill in the UDP header, Udp checksum is optional. Leave it zero.\r
363   //\r
364   Udp4             = (EFI_UDP_HEADER *) Buf;\r
365   Udp4->SrcPort    = HTONS (514);\r
366   Udp4->DstPort    = HTONS (514);\r
367   Udp4->Length     = 0;\r
368   Udp4->Checksum   = 0;\r
369 \r
370   Buf             += sizeof (EFI_UDP_HEADER);\r
371   BufLen          -= sizeof (EFI_UDP_HEADER);\r
372 \r
373   //\r
374   // Build the syslog message body with <PRI> Timestamp  machine module Message\r
375   //\r
376   Pri = ((NET_SYSLOG_FACILITY & 31) << 3) | (Level & 7);\r
377   gRT->GetTime (&Time, NULL);\r
378   ASSERT ((Time.Month <= 12) && (Time.Month >= 1));\r
379 \r
380   //\r
381   // Use %a to format the ASCII strings, %s to format UNICODE strings\r
382   //\r
383   Len  = 0;\r
384   Len += (UINT32) AsciiSPrint (\r
385                     Buf,\r
386                     BufLen,\r
387                     "<%d> %a %d %d:%d:%d ",\r
388                     Pri,\r
389                     mMonthName [Time.Month-1],\r
390                     Time.Day,\r
391                     Time.Hour,\r
392                     Time.Minute,\r
393                     Time.Second\r
394                     );\r
395   Len--;\r
396 \r
397   Len += (UINT32) AsciiSPrint (\r
398                     Buf + Len,\r
399                     BufLen - Len,\r
400                     "Tiano %a: %a (Line: %d File: %a)",\r
401                     Module,\r
402                     Message,\r
403                     Line,\r
404                     File\r
405                     );\r
406   Len--;\r
407 \r
408   //\r
409   // OK, patch the IP length/checksum and UDP length fields.\r
410   //\r
411   Len           += sizeof (EFI_UDP_HEADER);\r
412   Udp4->Length   = HTONS ((UINT16) Len);\r
413 \r
414   Len           += sizeof (IP4_HEAD);\r
415   Ip4->TotalLen  = HTONS ((UINT16) Len);\r
416   Ip4->Checksum  = (UINT16) (~NetblockChecksum ((UINT8 *) Ip4, sizeof (IP4_HEAD)));\r
417 \r
418   return Len + sizeof (ETHER_HEAD);\r
419 }\r
420 \r
421 /**\r
422   Allocate a buffer, then format the message to it. This is a\r
423   help function for the NET_DEBUG_XXX macros. The PrintArg of\r
424   these macros treats the variable length print parameters as a\r
425   single parameter, and pass it to the NetDebugASPrint. For\r
426   example, NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name))\r
427   if extracted to:\r
428 \r
429          NetDebugOutput (\r
430            NETDEBUG_LEVEL_TRACE,\r
431            "Tcp",\r
432            __FILE__,\r
433            __LINE__,\r
434            NetDebugASPrint ("State transit to %a\n", Name)\r
435          )\r
436 \r
437   @param Format  The ASCII format string.\r
438   @param ...     The variable length parameter whose format is determined\r
439                  by the Format string.\r
440 \r
441   @return        The buffer containing the formatted message,\r
442                  or NULL if failed to allocate memory.\r
443 \r
444 **/\r
445 CHAR8 *\r
446 NetDebugASPrint (\r
447   IN CHAR8                  *Format,\r
448   ...\r
449   )\r
450 {\r
451   VA_LIST                   Marker;\r
452   CHAR8                     *Buf;\r
453 \r
454   Buf = (CHAR8 *) AllocatePool (NET_DEBUG_MSG_LEN);\r
455 \r
456   if (Buf == NULL) {\r
457     return NULL;\r
458   }\r
459 \r
460   VA_START (Marker, Format);\r
461   AsciiVSPrint (Buf, NET_DEBUG_MSG_LEN, Format, Marker);\r
462   VA_END (Marker);\r
463 \r
464   return Buf;\r
465 }\r
466 \r
467 /**\r
468   Builds an UDP4 syslog packet and send it using SNP.\r
469 \r
470   This function will locate a instance of SNP then send the message through it.\r
471   Because it isn't open the SNP BY_DRIVER, apply caution when using it.\r
472 \r
473   @param Level    The servity level of the message.\r
474   @param Module   The Moudle that generates the log.\r
475   @param File     The file that contains the log.\r
476   @param Line     The exact line that contains the log.\r
477   @param Message  The user message to log.\r
478 \r
479   @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
480   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory for the packet\r
481   @retval EFI_SUCCESS           The log is discard because that it is more verbose\r
482                                 than the mNetDebugLevelMax. Or, it has been sent out.\r
483 **/\r
484 EFI_STATUS\r
485 NetDebugOutput (\r
486   IN UINT32                    Level,\r
487   IN UINT8                     *Module,\r
488   IN UINT8                     *File,\r
489   IN UINT32                    Line,\r
490   IN UINT8                     *Message\r
491   )\r
492 {\r
493   CHAR8                        *Packet;\r
494   UINT32                       Len;\r
495   EFI_STATUS                   Status;\r
496 \r
497   //\r
498   // Check whether the message should be sent out\r
499   //\r
500   if (Message == NULL) {\r
501     return EFI_INVALID_PARAMETER;\r
502   }\r
503 \r
504   if (Level > mNetDebugLevelMax) {\r
505     Status = EFI_SUCCESS;\r
506     goto ON_EXIT;\r
507   }\r
508 \r
509   //\r
510   // Allocate a maxium of 1024 bytes, the caller should ensure\r
511   // that the message plus the ethernet/ip/udp header is shorter\r
512   // than this\r
513   //\r
514   Packet = (CHAR8 *) AllocatePool (NET_SYSLOG_PACKET_LEN);\r
515 \r
516   if (Packet == NULL) {\r
517     Status = EFI_OUT_OF_RESOURCES;\r
518     goto ON_EXIT;\r
519   }\r
520 \r
521   //\r
522   // Build the message: Ethernet header + IP header + Udp Header + user data\r
523   //\r
524   Len = SyslogBuildPacket (\r
525           Level,\r
526           Module,\r
527           File,\r
528           Line,\r
529           Message,\r
530           NET_SYSLOG_PACKET_LEN,\r
531           Packet\r
532           );\r
533 \r
534   mSyslogPacketSeq++;\r
535   Status = SyslogSendPacket (Packet, Len);\r
536   FreePool (Packet);\r
537 \r
538 ON_EXIT:\r
539   FreePool (Message);\r
540   return Status;\r
541 }\r
542 /**\r
543   Return the length of the mask.\r
544 \r
545   Return the length of the mask, the correct value is from 0 to 32.\r
546   If the mask is invalid, return the invalid length 33, which is IP4_MASK_NUM.\r
547   NetMask is in the host byte order.\r
548 \r
549   @param[in]  NetMask              The netmask to get the length from.\r
550 \r
551   @return The length of the netmask, IP4_MASK_NUM if the mask is invalid.\r
552 \r
553 **/\r
554 INTN\r
555 EFIAPI\r
556 NetGetMaskLength (\r
557   IN IP4_ADDR               NetMask\r
558   )\r
559 {\r
560   INTN                      Index;\r
561 \r
562   for (Index = 0; Index < IP4_MASK_NUM; Index++) {\r
563     if (NetMask == gIp4AllMasks[Index]) {\r
564       break;\r
565     }\r
566   }\r
567 \r
568   return Index;\r
569 }\r
570 \r
571 \r
572 \r
573 /**\r
574   Return the class of the IP address, such as class A, B, C.\r
575   Addr is in host byte order.\r
576 \r
577   The address of class A  starts with 0.\r
578   If the address belong to class A, return IP4_ADDR_CLASSA.\r
579   The address of class B  starts with 10.\r
580   If the address belong to class B, return IP4_ADDR_CLASSB.\r
581   The address of class C  starts with 110.\r
582   If the address belong to class C, return IP4_ADDR_CLASSC.\r
583   The address of class D  starts with 1110.\r
584   If the address belong to class D, return IP4_ADDR_CLASSD.\r
585   The address of class E  starts with 1111.\r
586   If the address belong to class E, return IP4_ADDR_CLASSE.\r
587 \r
588 \r
589   @param[in]   Addr                  The address to get the class from.\r
590 \r
591   @return IP address class, such as IP4_ADDR_CLASSA.\r
592 \r
593 **/\r
594 INTN\r
595 EFIAPI\r
596 NetGetIpClass (\r
597   IN IP4_ADDR               Addr\r
598   )\r
599 {\r
600   UINT8                     ByteOne;\r
601 \r
602   ByteOne = (UINT8) (Addr >> 24);\r
603 \r
604   if ((ByteOne & 0x80) == 0) {\r
605     return IP4_ADDR_CLASSA;\r
606 \r
607   } else if ((ByteOne & 0xC0) == 0x80) {\r
608     return IP4_ADDR_CLASSB;\r
609 \r
610   } else if ((ByteOne & 0xE0) == 0xC0) {\r
611     return IP4_ADDR_CLASSC;\r
612 \r
613   } else if ((ByteOne & 0xF0) == 0xE0) {\r
614     return IP4_ADDR_CLASSD;\r
615 \r
616   } else {\r
617     return IP4_ADDR_CLASSE;\r
618 \r
619   }\r
620 }\r
621 \r
622 \r
623 /**\r
624   Check whether the IP is a valid unicast address according to\r
625   the netmask. If NetMask is zero, use the IP address's class to get the default mask.\r
626 \r
627   If Ip is 0, IP is not a valid unicast address.\r
628   Class D address is used for multicasting and class E address is reserved for future. If Ip\r
629   belongs to class D or class E, IP is not a valid unicast address.\r
630   If all bits of the host address of IP are 0 or 1, IP is also not a valid unicast address.\r
631 \r
632   @param[in]  Ip                    The IP to check against.\r
633   @param[in]  NetMask               The mask of the IP.\r
634 \r
635   @return TRUE if IP is a valid unicast address on the network, otherwise FALSE.\r
636 \r
637 **/\r
638 BOOLEAN\r
639 EFIAPI\r
640 NetIp4IsUnicast (\r
641   IN IP4_ADDR               Ip,\r
642   IN IP4_ADDR               NetMask\r
643   )\r
644 {\r
645   INTN                      Class;\r
646 \r
647   Class = NetGetIpClass (Ip);\r
648 \r
649   if ((Ip == 0) || (Class >= IP4_ADDR_CLASSD)) {\r
650     return FALSE;\r
651   }\r
652 \r
653   if (NetMask == 0) {\r
654     NetMask = gIp4AllMasks[Class << 3];\r
655   }\r
656 \r
657   if (((Ip &~NetMask) == ~NetMask) || ((Ip &~NetMask) == 0)) {\r
658     return FALSE;\r
659   }\r
660 \r
661   return TRUE;\r
662 }\r
663 \r
664 /**\r
665   Check whether the incoming IPv6 address is a valid unicast address.\r
666 \r
667   If the address is a multicast address has binary 0xFF at the start, it is not\r
668   a valid unicast address. If the address is unspecified ::, it is not a valid\r
669   unicast address to be assigned to any node. If the address is loopback address\r
670   ::1, it is also not a valid unicast address to be assigned to any physical\r
671   interface.\r
672 \r
673   @param[in]  Ip6                   The IPv6 address to check against.\r
674 \r
675   @return TRUE if Ip6 is a valid unicast address on the network, otherwise FALSE.\r
676 \r
677 **/\r
678 BOOLEAN\r
679 NetIp6IsValidUnicast (\r
680   IN EFI_IPv6_ADDRESS       *Ip6\r
681   )\r
682 {\r
683   UINT8 Byte;\r
684   UINT8 Index;\r
685 \r
686   if (Ip6->Addr[0] == 0xFF) {\r
687     return FALSE;\r
688   }\r
689 \r
690   for (Index = 0; Index < 15; Index++) {\r
691     if (Ip6->Addr[Index] != 0) {\r
692       return TRUE;\r
693     }\r
694   }\r
695 \r
696   Byte = Ip6->Addr[Index];\r
697 \r
698   if (Byte == 0x0 || Byte == 0x1) {\r
699     return FALSE;\r
700   }\r
701 \r
702   return TRUE;\r
703 }\r
704 \r
705 /**\r
706   Check whether the incoming Ipv6 address is the unspecified address or not.\r
707 \r
708   @param[in] Ip6   - Ip6 address, in network order.\r
709 \r
710   @retval TRUE     - Yes, unspecified\r
711   @retval FALSE    - No\r
712 \r
713 **/\r
714 BOOLEAN\r
715 NetIp6IsUnspecifiedAddr (\r
716   IN EFI_IPv6_ADDRESS       *Ip6\r
717   )\r
718 {\r
719   UINT8 Index;\r
720 \r
721   for (Index = 0; Index < 16; Index++) {\r
722     if (Ip6->Addr[Index] != 0) {\r
723       return FALSE;\r
724     }\r
725   }\r
726 \r
727   return TRUE;\r
728 }\r
729 \r
730 /**\r
731   Check whether the incoming Ipv6 address is a link-local address.\r
732 \r
733   @param[in] Ip6   - Ip6 address, in network order.\r
734 \r
735   @retval TRUE  - Yes, link-local address\r
736   @retval FALSE - No\r
737 \r
738 **/\r
739 BOOLEAN\r
740 NetIp6IsLinkLocalAddr (\r
741   IN EFI_IPv6_ADDRESS *Ip6\r
742   )\r
743 {\r
744   UINT8 Index;\r
745 \r
746   ASSERT (Ip6 != NULL);\r
747 \r
748   if (Ip6->Addr[0] != 0xFE) {\r
749     return FALSE;\r
750   }\r
751 \r
752   if (Ip6->Addr[1] != 0x80) {\r
753     return FALSE;\r
754   }\r
755 \r
756   for (Index = 2; Index < 8; Index++) {\r
757     if (Ip6->Addr[Index] != 0) {\r
758       return FALSE;\r
759     }\r
760   }\r
761 \r
762   return TRUE;\r
763 }\r
764 \r
765 /**\r
766   Check whether the Ipv6 address1 and address2 are on the connected network.\r
767 \r
768   @param[in] Ip1          - Ip6 address1, in network order.\r
769   @param[in] Ip2          - Ip6 address2, in network order.\r
770   @param[in] PrefixLength - The prefix length of the checking net.\r
771 \r
772   @retval TRUE            - Yes, connected.\r
773   @retval FALSE           - No.\r
774 \r
775 **/\r
776 BOOLEAN\r
777 NetIp6IsNetEqual (\r
778   EFI_IPv6_ADDRESS *Ip1,\r
779   EFI_IPv6_ADDRESS *Ip2,\r
780   UINT8            PrefixLength\r
781   )\r
782 {\r
783   UINT8 Byte;\r
784   UINT8 Bit;\r
785   UINT8 Mask;\r
786 \r
787   ASSERT ((Ip1 != NULL) && (Ip2 != NULL) && (PrefixLength < IP6_PREFIX_NUM));\r
788 \r
789   if (PrefixLength == 0) {\r
790     return TRUE;\r
791   }\r
792 \r
793   Byte = (UINT8) (PrefixLength / 8);\r
794   Bit  = (UINT8) (PrefixLength % 8);\r
795 \r
796   if (CompareMem (Ip1, Ip2, Byte) != 0) {\r
797     return FALSE;\r
798   }\r
799 \r
800   if (Bit > 0) {\r
801     Mask = (UINT8) (0xFF << (8 - Bit));\r
802 \r
803     ASSERT (Byte < 16);\r
804     if ((Ip1->Addr[Byte] & Mask) != (Ip2->Addr[Byte] & Mask)) {\r
805       return FALSE;\r
806     }\r
807   }\r
808 \r
809   return TRUE;\r
810 }\r
811 \r
812 \r
813 /**\r
814   Switches the endianess of an IPv6 address\r
815 \r
816   This function swaps the bytes in a 128-bit IPv6 address to switch the value\r
817   from little endian to big endian or vice versa. The byte swapped value is\r
818   returned.\r
819 \r
820   @param  Ip6 Points to an IPv6 address\r
821 \r
822   @return The byte swapped IPv6 address.\r
823 \r
824 **/\r
825 EFI_IPv6_ADDRESS *\r
826 Ip6Swap128 (\r
827   EFI_IPv6_ADDRESS *Ip6\r
828   )\r
829 {\r
830   UINT64 High;\r
831   UINT64 Low;\r
832 \r
833   CopyMem (&High, Ip6, sizeof (UINT64));\r
834   CopyMem (&Low, &Ip6->Addr[8], sizeof (UINT64));\r
835 \r
836   High = SwapBytes64 (High);\r
837   Low  = SwapBytes64 (Low);\r
838 \r
839   CopyMem (Ip6, &Low, sizeof (UINT64));\r
840   CopyMem (&Ip6->Addr[8], &High, sizeof (UINT64));\r
841 \r
842   return Ip6;\r
843 }\r
844 \r
845 /**\r
846   Initialize a random seed using current time.\r
847 \r
848   Get current time first. Then initialize a random seed based on some basic\r
849   mathematics operation on the hour, day, minute, second, nanosecond and year\r
850   of the current time.\r
851 \r
852   @return The random seed initialized with current time.\r
853 \r
854 **/\r
855 UINT32\r
856 EFIAPI\r
857 NetRandomInitSeed (\r
858   VOID\r
859   )\r
860 {\r
861   EFI_TIME                  Time;\r
862   UINT32                    Seed;\r
863 \r
864   gRT->GetTime (&Time, NULL);\r
865   Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second);\r
866   Seed ^= Time.Nanosecond;\r
867   Seed ^= Time.Year << 7;\r
868 \r
869   return Seed;\r
870 }\r
871 \r
872 \r
873 /**\r
874   Extract a UINT32 from a byte stream.\r
875 \r
876   Copy a UINT32 from a byte stream, then converts it from Network\r
877   byte order to host byte order. Use this function to avoid alignment error.\r
878 \r
879   @param[in]  Buf                 The buffer to extract the UINT32.\r
880 \r
881   @return The UINT32 extracted.\r
882 \r
883 **/\r
884 UINT32\r
885 EFIAPI\r
886 NetGetUint32 (\r
887   IN UINT8                  *Buf\r
888   )\r
889 {\r
890   UINT32                    Value;\r
891 \r
892   CopyMem (&Value, Buf, sizeof (UINT32));\r
893   return NTOHL (Value);\r
894 }\r
895 \r
896 \r
897 /**\r
898   Put a UINT32 to the byte stream in network byte order.\r
899 \r
900   Converts a UINT32 from host byte order to network byte order. Then copy it to the\r
901   byte stream.\r
902 \r
903   @param[in, out]  Buf          The buffer to put the UINT32.\r
904   @param[in]      Data          The data to put.\r
905 \r
906 **/\r
907 VOID\r
908 EFIAPI\r
909 NetPutUint32 (\r
910   IN OUT UINT8                 *Buf,\r
911   IN     UINT32                Data\r
912   )\r
913 {\r
914   Data = HTONL (Data);\r
915   CopyMem (Buf, &Data, sizeof (UINT32));\r
916 }\r
917 \r
918 \r
919 /**\r
920   Remove the first node entry on the list, and return the removed node entry.\r
921 \r
922   Removes the first node Entry from a doubly linked list. It is up to the caller of\r
923   this function to release the memory used by the first node if that is required. On\r
924   exit, the removed node is returned.\r
925 \r
926   If Head is NULL, then ASSERT().\r
927   If Head was not initialized, then ASSERT().\r
928   If PcdMaximumLinkedListLength is not zero, and the number of nodes in the\r
929   linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,\r
930   then ASSERT().\r
931 \r
932   @param[in, out]  Head                  The list header.\r
933 \r
934   @return The first node entry that is removed from the list, NULL if the list is empty.\r
935 \r
936 **/\r
937 LIST_ENTRY *\r
938 EFIAPI\r
939 NetListRemoveHead (\r
940   IN OUT LIST_ENTRY            *Head\r
941   )\r
942 {\r
943   LIST_ENTRY            *First;\r
944 \r
945   ASSERT (Head != NULL);\r
946 \r
947   if (IsListEmpty (Head)) {\r
948     return NULL;\r
949   }\r
950 \r
951   First                         = Head->ForwardLink;\r
952   Head->ForwardLink             = First->ForwardLink;\r
953   First->ForwardLink->BackLink  = Head;\r
954 \r
955   DEBUG_CODE (\r
956     First->ForwardLink  = (LIST_ENTRY *) NULL;\r
957     First->BackLink     = (LIST_ENTRY *) NULL;\r
958   );\r
959 \r
960   return First;\r
961 }\r
962 \r
963 \r
964 /**\r
965   Remove the last node entry on the list and and return the removed node entry.\r
966 \r
967   Removes the last node entry from a doubly linked list. It is up to the caller of\r
968   this function to release the memory used by the first node if that is required. On\r
969   exit, the removed node is returned.\r
970 \r
971   If Head is NULL, then ASSERT().\r
972   If Head was not initialized, then ASSERT().\r
973   If PcdMaximumLinkedListLength is not zero, and the number of nodes in the\r
974   linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,\r
975   then ASSERT().\r
976 \r
977   @param[in, out]  Head                  The list head.\r
978 \r
979   @return The last node entry that is removed from the list, NULL if the list is empty.\r
980 \r
981 **/\r
982 LIST_ENTRY *\r
983 EFIAPI\r
984 NetListRemoveTail (\r
985   IN OUT LIST_ENTRY            *Head\r
986   )\r
987 {\r
988   LIST_ENTRY            *Last;\r
989 \r
990   ASSERT (Head != NULL);\r
991 \r
992   if (IsListEmpty (Head)) {\r
993     return NULL;\r
994   }\r
995 \r
996   Last                        = Head->BackLink;\r
997   Head->BackLink              = Last->BackLink;\r
998   Last->BackLink->ForwardLink = Head;\r
999 \r
1000   DEBUG_CODE (\r
1001     Last->ForwardLink = (LIST_ENTRY *) NULL;\r
1002     Last->BackLink    = (LIST_ENTRY *) NULL;\r
1003   );\r
1004 \r
1005   return Last;\r
1006 }\r
1007 \r
1008 \r
1009 /**\r
1010   Insert a new node entry after a designated node entry of a doubly linked list.\r
1011 \r
1012   Inserts a new node entry donated by NewEntry after the node entry donated by PrevEntry\r
1013   of the doubly linked list.\r
1014 \r
1015   @param[in, out]  PrevEntry             The previous entry to insert after.\r
1016   @param[in, out]  NewEntry              The new entry to insert.\r
1017 \r
1018 **/\r
1019 VOID\r
1020 EFIAPI\r
1021 NetListInsertAfter (\r
1022   IN OUT LIST_ENTRY         *PrevEntry,\r
1023   IN OUT LIST_ENTRY         *NewEntry\r
1024   )\r
1025 {\r
1026   NewEntry->BackLink                = PrevEntry;\r
1027   NewEntry->ForwardLink             = PrevEntry->ForwardLink;\r
1028   PrevEntry->ForwardLink->BackLink  = NewEntry;\r
1029   PrevEntry->ForwardLink            = NewEntry;\r
1030 }\r
1031 \r
1032 \r
1033 /**\r
1034   Insert a new node entry before a designated node entry of a doubly linked list.\r
1035 \r
1036   Inserts a new node entry donated by NewEntry after the node entry donated by PostEntry\r
1037   of the doubly linked list.\r
1038 \r
1039   @param[in, out]  PostEntry             The entry to insert before.\r
1040   @param[in, out]  NewEntry              The new entry to insert.\r
1041 \r
1042 **/\r
1043 VOID\r
1044 EFIAPI\r
1045 NetListInsertBefore (\r
1046   IN OUT LIST_ENTRY     *PostEntry,\r
1047   IN OUT LIST_ENTRY     *NewEntry\r
1048   )\r
1049 {\r
1050   NewEntry->ForwardLink             = PostEntry;\r
1051   NewEntry->BackLink                = PostEntry->BackLink;\r
1052   PostEntry->BackLink->ForwardLink  = NewEntry;\r
1053   PostEntry->BackLink               = NewEntry;\r
1054 }\r
1055 \r
1056 \r
1057 /**\r
1058   Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.\r
1059 \r
1060   Initialize the forward and backward links of two head nodes donated by Map->Used\r
1061   and Map->Recycled of two doubly linked lists.\r
1062   Initializes the count of the <Key, Value> pairs in the netmap to zero.\r
1063 \r
1064   If Map is NULL, then ASSERT().\r
1065   If the address of Map->Used is NULL, then ASSERT().\r
1066   If the address of Map->Recycled is NULl, then ASSERT().\r
1067 \r
1068   @param[in, out]  Map                   The netmap to initialize.\r
1069 \r
1070 **/\r
1071 VOID\r
1072 EFIAPI\r
1073 NetMapInit (\r
1074   IN OUT NET_MAP                *Map\r
1075   )\r
1076 {\r
1077   ASSERT (Map != NULL);\r
1078 \r
1079   InitializeListHead (&Map->Used);\r
1080   InitializeListHead (&Map->Recycled);\r
1081   Map->Count = 0;\r
1082 }\r
1083 \r
1084 \r
1085 /**\r
1086   To clean up the netmap, that is, release allocated memories.\r
1087 \r
1088   Removes all nodes of the Used doubly linked list and free memory of all related netmap items.\r
1089   Removes all nodes of the Recycled doubly linked list and free memory of all related netmap items.\r
1090   The number of the <Key, Value> pairs in the netmap is set to be zero.\r
1091 \r
1092   If Map is NULL, then ASSERT().\r
1093 \r
1094   @param[in, out]  Map                   The netmap to clean up.\r
1095 \r
1096 **/\r
1097 VOID\r
1098 EFIAPI\r
1099 NetMapClean (\r
1100   IN OUT NET_MAP            *Map\r
1101   )\r
1102 {\r
1103   NET_MAP_ITEM              *Item;\r
1104   LIST_ENTRY                *Entry;\r
1105   LIST_ENTRY                *Next;\r
1106 \r
1107   ASSERT (Map != NULL);\r
1108 \r
1109   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Used) {\r
1110     Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
1111 \r
1112     RemoveEntryList (&Item->Link);\r
1113     Map->Count--;\r
1114 \r
1115     gBS->FreePool (Item);\r
1116   }\r
1117 \r
1118   ASSERT ((Map->Count == 0) && IsListEmpty (&Map->Used));\r
1119 \r
1120   NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Recycled) {\r
1121     Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
1122 \r
1123     RemoveEntryList (&Item->Link);\r
1124     gBS->FreePool (Item);\r
1125   }\r
1126 \r
1127   ASSERT (IsListEmpty (&Map->Recycled));\r
1128 }\r
1129 \r
1130 \r
1131 /**\r
1132   Test whether the netmap is empty and return true if it is.\r
1133 \r
1134   If the number of the <Key, Value> pairs in the netmap is zero, return TRUE.\r
1135 \r
1136   If Map is NULL, then ASSERT().\r
1137 \r
1138 \r
1139   @param[in]  Map                   The net map to test.\r
1140 \r
1141   @return TRUE if the netmap is empty, otherwise FALSE.\r
1142 \r
1143 **/\r
1144 BOOLEAN\r
1145 EFIAPI\r
1146 NetMapIsEmpty (\r
1147   IN NET_MAP                *Map\r
1148   )\r
1149 {\r
1150   ASSERT (Map != NULL);\r
1151   return (BOOLEAN) (Map->Count == 0);\r
1152 }\r
1153 \r
1154 \r
1155 /**\r
1156   Return the number of the <Key, Value> pairs in the netmap.\r
1157 \r
1158   @param[in]  Map                   The netmap to get the entry number.\r
1159 \r
1160   @return The entry number in the netmap.\r
1161 \r
1162 **/\r
1163 UINTN\r
1164 EFIAPI\r
1165 NetMapGetCount (\r
1166   IN NET_MAP                *Map\r
1167   )\r
1168 {\r
1169   return Map->Count;\r
1170 }\r
1171 \r
1172 \r
1173 /**\r
1174   Return one allocated item.\r
1175 \r
1176   If the Recycled doubly linked list of the netmap is empty, it will try to allocate\r
1177   a batch of items if there are enough resources and add corresponding nodes to the begining\r
1178   of the Recycled doubly linked list of the netmap. Otherwise, it will directly remove\r
1179   the fist node entry of the Recycled doubly linked list and return the corresponding item.\r
1180 \r
1181   If Map is NULL, then ASSERT().\r
1182 \r
1183   @param[in, out]  Map          The netmap to allocate item for.\r
1184 \r
1185   @return                       The allocated item. If NULL, the\r
1186                                 allocation failed due to resource limit.\r
1187 \r
1188 **/\r
1189 NET_MAP_ITEM *\r
1190 NetMapAllocItem (\r
1191   IN OUT NET_MAP            *Map\r
1192   )\r
1193 {\r
1194   NET_MAP_ITEM              *Item;\r
1195   LIST_ENTRY                *Head;\r
1196   UINTN                     Index;\r
1197 \r
1198   ASSERT (Map != NULL);\r
1199 \r
1200   Head = &Map->Recycled;\r
1201 \r
1202   if (IsListEmpty (Head)) {\r
1203     for (Index = 0; Index < NET_MAP_INCREAMENT; Index++) {\r
1204       Item = AllocatePool (sizeof (NET_MAP_ITEM));\r
1205 \r
1206       if (Item == NULL) {\r
1207         if (Index == 0) {\r
1208           return NULL;\r
1209         }\r
1210 \r
1211         break;\r
1212       }\r
1213 \r
1214       InsertHeadList (Head, &Item->Link);\r
1215     }\r
1216   }\r
1217 \r
1218   Item = NET_LIST_HEAD (Head, NET_MAP_ITEM, Link);\r
1219   NetListRemoveHead (Head);\r
1220 \r
1221   return Item;\r
1222 }\r
1223 \r
1224 \r
1225 /**\r
1226   Allocate an item to save the <Key, Value> pair to the head of the netmap.\r
1227 \r
1228   Allocate an item to save the <Key, Value> pair and add corresponding node entry\r
1229   to the beginning of the Used doubly linked list. The number of the <Key, Value>\r
1230   pairs in the netmap increase by 1.\r
1231 \r
1232   If Map is NULL, then ASSERT().\r
1233 \r
1234   @param[in, out]  Map                   The netmap to insert into.\r
1235   @param[in]       Key                   The user's key.\r
1236   @param[in]       Value                 The user's value for the key.\r
1237 \r
1238   @retval EFI_OUT_OF_RESOURCES  Failed to allocate the memory for the item.\r
1239   @retval EFI_SUCCESS           The item is inserted to the head.\r
1240 \r
1241 **/\r
1242 EFI_STATUS\r
1243 EFIAPI\r
1244 NetMapInsertHead (\r
1245   IN OUT NET_MAP            *Map,\r
1246   IN VOID                   *Key,\r
1247   IN VOID                   *Value    OPTIONAL\r
1248   )\r
1249 {\r
1250   NET_MAP_ITEM              *Item;\r
1251 \r
1252   ASSERT (Map != NULL);\r
1253 \r
1254   Item = NetMapAllocItem (Map);\r
1255 \r
1256   if (Item == NULL) {\r
1257     return EFI_OUT_OF_RESOURCES;\r
1258   }\r
1259 \r
1260   Item->Key   = Key;\r
1261   Item->Value = Value;\r
1262   InsertHeadList (&Map->Used, &Item->Link);\r
1263 \r
1264   Map->Count++;\r
1265   return EFI_SUCCESS;\r
1266 }\r
1267 \r
1268 \r
1269 /**\r
1270   Allocate an item to save the <Key, Value> pair to the tail of the netmap.\r
1271 \r
1272   Allocate an item to save the <Key, Value> pair and add corresponding node entry\r
1273   to the tail of the Used doubly linked list. The number of the <Key, Value>\r
1274   pairs in the netmap increase by 1.\r
1275 \r
1276   If Map is NULL, then ASSERT().\r
1277 \r
1278   @param[in, out]  Map                   The netmap to insert into.\r
1279   @param[in]       Key                   The user's key.\r
1280   @param[in]       Value                 The user's value for the key.\r
1281 \r
1282   @retval EFI_OUT_OF_RESOURCES  Failed to allocate the memory for the item.\r
1283   @retval EFI_SUCCESS           The item is inserted to the tail.\r
1284 \r
1285 **/\r
1286 EFI_STATUS\r
1287 EFIAPI\r
1288 NetMapInsertTail (\r
1289   IN OUT NET_MAP            *Map,\r
1290   IN VOID                   *Key,\r
1291   IN VOID                   *Value    OPTIONAL\r
1292   )\r
1293 {\r
1294   NET_MAP_ITEM              *Item;\r
1295 \r
1296   ASSERT (Map != NULL);\r
1297 \r
1298   Item = NetMapAllocItem (Map);\r
1299 \r
1300   if (Item == NULL) {\r
1301     return EFI_OUT_OF_RESOURCES;\r
1302   }\r
1303 \r
1304   Item->Key   = Key;\r
1305   Item->Value = Value;\r
1306   InsertTailList (&Map->Used, &Item->Link);\r
1307 \r
1308   Map->Count++;\r
1309 \r
1310   return EFI_SUCCESS;\r
1311 }\r
1312 \r
1313 \r
1314 /**\r
1315   Check whether the item is in the Map and return TRUE if it is.\r
1316 \r
1317   @param[in]  Map                   The netmap to search within.\r
1318   @param[in]  Item                  The item to search.\r
1319 \r
1320   @return TRUE if the item is in the netmap, otherwise FALSE.\r
1321 \r
1322 **/\r
1323 BOOLEAN\r
1324 NetItemInMap (\r
1325   IN NET_MAP                *Map,\r
1326   IN NET_MAP_ITEM           *Item\r
1327   )\r
1328 {\r
1329   LIST_ENTRY            *ListEntry;\r
1330 \r
1331   NET_LIST_FOR_EACH (ListEntry, &Map->Used) {\r
1332     if (ListEntry == &Item->Link) {\r
1333       return TRUE;\r
1334     }\r
1335   }\r
1336 \r
1337   return FALSE;\r
1338 }\r
1339 \r
1340 \r
1341 /**\r
1342   Find the key in the netmap and returns the point to the item contains the Key.\r
1343 \r
1344   Iterate the Used doubly linked list of the netmap to get every item. Compare the key of every\r
1345   item with the key to search. It returns the point to the item contains the Key if found.\r
1346 \r
1347   If Map is NULL, then ASSERT().\r
1348 \r
1349   @param[in]  Map                   The netmap to search within.\r
1350   @param[in]  Key                   The key to search.\r
1351 \r
1352   @return The point to the item contains the Key, or NULL if Key isn't in the map.\r
1353 \r
1354 **/\r
1355 NET_MAP_ITEM *\r
1356 EFIAPI\r
1357 NetMapFindKey (\r
1358   IN  NET_MAP               *Map,\r
1359   IN  VOID                  *Key\r
1360   )\r
1361 {\r
1362   LIST_ENTRY              *Entry;\r
1363   NET_MAP_ITEM            *Item;\r
1364 \r
1365   ASSERT (Map != NULL);\r
1366 \r
1367   NET_LIST_FOR_EACH (Entry, &Map->Used) {\r
1368     Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
1369 \r
1370     if (Item->Key == Key) {\r
1371       return Item;\r
1372     }\r
1373   }\r
1374 \r
1375   return NULL;\r
1376 }\r
1377 \r
1378 \r
1379 /**\r
1380   Remove the node entry of the item from the netmap and return the key of the removed item.\r
1381 \r
1382   Remove the node entry of the item from the Used doubly linked list of the netmap.\r
1383   The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node\r
1384   entry of the item to the Recycled doubly linked list of the netmap. If Value is not NULL,\r
1385   Value will point to the value of the item. It returns the key of the removed item.\r
1386 \r
1387   If Map is NULL, then ASSERT().\r
1388   If Item is NULL, then ASSERT().\r
1389   if item in not in the netmap, then ASSERT().\r
1390 \r
1391   @param[in, out]  Map                   The netmap to remove the item from.\r
1392   @param[in, out]  Item                  The item to remove.\r
1393   @param[out]      Value                 The variable to receive the value if not NULL.\r
1394 \r
1395   @return                                The key of the removed item.\r
1396 \r
1397 **/\r
1398 VOID *\r
1399 EFIAPI\r
1400 NetMapRemoveItem (\r
1401   IN  OUT NET_MAP             *Map,\r
1402   IN  OUT NET_MAP_ITEM        *Item,\r
1403   OUT VOID                    **Value           OPTIONAL\r
1404   )\r
1405 {\r
1406   ASSERT ((Map != NULL) && (Item != NULL));\r
1407   ASSERT (NetItemInMap (Map, Item));\r
1408 \r
1409   RemoveEntryList (&Item->Link);\r
1410   Map->Count--;\r
1411   InsertHeadList (&Map->Recycled, &Item->Link);\r
1412 \r
1413   if (Value != NULL) {\r
1414     *Value = Item->Value;\r
1415   }\r
1416 \r
1417   return Item->Key;\r
1418 }\r
1419 \r
1420 \r
1421 /**\r
1422   Remove the first node entry on the netmap and return the key of the removed item.\r
1423 \r
1424   Remove the first node entry from the Used doubly linked list of the netmap.\r
1425   The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node\r
1426   entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,\r
1427   parameter Value will point to the value of the item. It returns the key of the removed item.\r
1428 \r
1429   If Map is NULL, then ASSERT().\r
1430   If the Used doubly linked list is empty, then ASSERT().\r
1431 \r
1432   @param[in, out]  Map                   The netmap to remove the head from.\r
1433   @param[out]      Value                 The variable to receive the value if not NULL.\r
1434 \r
1435   @return                                The key of the item removed.\r
1436 \r
1437 **/\r
1438 VOID *\r
1439 EFIAPI\r
1440 NetMapRemoveHead (\r
1441   IN OUT NET_MAP            *Map,\r
1442   OUT VOID                  **Value         OPTIONAL\r
1443   )\r
1444 {\r
1445   NET_MAP_ITEM  *Item;\r
1446 \r
1447   //\r
1448   // Often, it indicates a programming error to remove\r
1449   // the first entry in an empty list\r
1450   //\r
1451   ASSERT (Map && !IsListEmpty (&Map->Used));\r
1452 \r
1453   Item = NET_LIST_HEAD (&Map->Used, NET_MAP_ITEM, Link);\r
1454   RemoveEntryList (&Item->Link);\r
1455   Map->Count--;\r
1456   InsertHeadList (&Map->Recycled, &Item->Link);\r
1457 \r
1458   if (Value != NULL) {\r
1459     *Value = Item->Value;\r
1460   }\r
1461 \r
1462   return Item->Key;\r
1463 }\r
1464 \r
1465 \r
1466 /**\r
1467   Remove the last node entry on the netmap and return the key of the removed item.\r
1468 \r
1469   Remove the last node entry from the Used doubly linked list of the netmap.\r
1470   The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node\r
1471   entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,\r
1472   parameter Value will point to the value of the item. It returns the key of the removed item.\r
1473 \r
1474   If Map is NULL, then ASSERT().\r
1475   If the Used doubly linked list is empty, then ASSERT().\r
1476 \r
1477   @param[in, out]  Map                   The netmap to remove the tail from.\r
1478   @param[out]      Value                 The variable to receive the value if not NULL.\r
1479 \r
1480   @return                                The key of the item removed.\r
1481 \r
1482 **/\r
1483 VOID *\r
1484 EFIAPI\r
1485 NetMapRemoveTail (\r
1486   IN OUT NET_MAP            *Map,\r
1487   OUT VOID                  **Value       OPTIONAL\r
1488   )\r
1489 {\r
1490   NET_MAP_ITEM              *Item;\r
1491 \r
1492   //\r
1493   // Often, it indicates a programming error to remove\r
1494   // the last entry in an empty list\r
1495   //\r
1496   ASSERT (Map && !IsListEmpty (&Map->Used));\r
1497 \r
1498   Item = NET_LIST_TAIL (&Map->Used, NET_MAP_ITEM, Link);\r
1499   RemoveEntryList (&Item->Link);\r
1500   Map->Count--;\r
1501   InsertHeadList (&Map->Recycled, &Item->Link);\r
1502 \r
1503   if (Value != NULL) {\r
1504     *Value = Item->Value;\r
1505   }\r
1506 \r
1507   return Item->Key;\r
1508 }\r
1509 \r
1510 \r
1511 /**\r
1512   Iterate through the netmap and call CallBack for each item.\r
1513 \r
1514   It will contiue the traverse if CallBack returns EFI_SUCCESS, otherwise, break\r
1515   from the loop. It returns the CallBack's last return value. This function is\r
1516   delete safe for the current item.\r
1517 \r
1518   If Map is NULL, then ASSERT().\r
1519   If CallBack is NULL, then ASSERT().\r
1520 \r
1521   @param[in]  Map                   The Map to iterate through.\r
1522   @param[in]  CallBack              The callback function to call for each item.\r
1523   @param[in]  Arg                   The opaque parameter to the callback.\r
1524 \r
1525   @retval EFI_SUCCESS            There is no item in the netmap or CallBack for each item\r
1526                                  return EFI_SUCCESS.\r
1527   @retval Others                 It returns the CallBack's last return value.\r
1528 \r
1529 **/\r
1530 EFI_STATUS\r
1531 EFIAPI\r
1532 NetMapIterate (\r
1533   IN NET_MAP                *Map,\r
1534   IN NET_MAP_CALLBACK       CallBack,\r
1535   IN VOID                   *Arg      OPTIONAL\r
1536   )\r
1537 {\r
1538 \r
1539   LIST_ENTRY            *Entry;\r
1540   LIST_ENTRY            *Next;\r
1541   LIST_ENTRY            *Head;\r
1542   NET_MAP_ITEM          *Item;\r
1543   EFI_STATUS            Result;\r
1544 \r
1545   ASSERT ((Map != NULL) && (CallBack != NULL));\r
1546 \r
1547   Head = &Map->Used;\r
1548 \r
1549   if (IsListEmpty (Head)) {\r
1550     return EFI_SUCCESS;\r
1551   }\r
1552 \r
1553   NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {\r
1554     Item   = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
1555     Result = CallBack (Map, Item, Arg);\r
1556 \r
1557     if (EFI_ERROR (Result)) {\r
1558       return Result;\r
1559     }\r
1560   }\r
1561 \r
1562   return EFI_SUCCESS;\r
1563 }\r
1564 \r
1565 \r
1566 /**\r
1567   This is the default unload handle for all the network drivers.\r
1568 \r
1569   Disconnect the driver specified by ImageHandle from all the devices in the handle database.\r
1570   Uninstall all the protocols installed in the driver entry point.\r
1571 \r
1572   @param[in]  ImageHandle       The drivers' driver image.\r
1573 \r
1574   @retval EFI_SUCCESS           The image is unloaded.\r
1575   @retval Others                Failed to unload the image.\r
1576 \r
1577 **/\r
1578 EFI_STATUS\r
1579 EFIAPI\r
1580 NetLibDefaultUnload (\r
1581   IN EFI_HANDLE             ImageHandle\r
1582   )\r
1583 {\r
1584   EFI_STATUS                        Status;\r
1585   EFI_HANDLE                        *DeviceHandleBuffer;\r
1586   UINTN                             DeviceHandleCount;\r
1587   UINTN                             Index;\r
1588   EFI_DRIVER_BINDING_PROTOCOL       *DriverBinding;\r
1589   EFI_COMPONENT_NAME_PROTOCOL       *ComponentName;\r
1590   EFI_COMPONENT_NAME2_PROTOCOL      *ComponentName2;\r
1591 \r
1592   //\r
1593   // Get the list of all the handles in the handle database.\r
1594   // If there is an error getting the list, then the unload\r
1595   // operation fails.\r
1596   //\r
1597   Status = gBS->LocateHandleBuffer (\r
1598                   AllHandles,\r
1599                   NULL,\r
1600                   NULL,\r
1601                   &DeviceHandleCount,\r
1602                   &DeviceHandleBuffer\r
1603                   );\r
1604 \r
1605   if (EFI_ERROR (Status)) {\r
1606     return Status;\r
1607   }\r
1608 \r
1609   //\r
1610   // Disconnect the driver specified by ImageHandle from all\r
1611   // the devices in the handle database.\r
1612   //\r
1613   for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1614     Status = gBS->DisconnectController (\r
1615                     DeviceHandleBuffer[Index],\r
1616                     ImageHandle,\r
1617                     NULL\r
1618                     );\r
1619   }\r
1620 \r
1621   //\r
1622   // Uninstall all the protocols installed in the driver entry point\r
1623   //\r
1624   for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1625     Status = gBS->HandleProtocol (\r
1626                     DeviceHandleBuffer[Index],\r
1627                     &gEfiDriverBindingProtocolGuid,\r
1628                     (VOID **) &DriverBinding\r
1629                     );\r
1630 \r
1631     if (EFI_ERROR (Status)) {\r
1632       continue;\r
1633     }\r
1634 \r
1635     if (DriverBinding->ImageHandle != ImageHandle) {\r
1636       continue;\r
1637     }\r
1638 \r
1639     gBS->UninstallProtocolInterface (\r
1640           ImageHandle,\r
1641           &gEfiDriverBindingProtocolGuid,\r
1642           DriverBinding\r
1643           );\r
1644     Status = gBS->HandleProtocol (\r
1645                     DeviceHandleBuffer[Index],\r
1646                     &gEfiComponentNameProtocolGuid,\r
1647                     (VOID **) &ComponentName\r
1648                     );\r
1649     if (!EFI_ERROR (Status)) {\r
1650       gBS->UninstallProtocolInterface (\r
1651              ImageHandle,\r
1652              &gEfiComponentNameProtocolGuid,\r
1653              ComponentName\r
1654              );\r
1655     }\r
1656 \r
1657     Status = gBS->HandleProtocol (\r
1658                     DeviceHandleBuffer[Index],\r
1659                     &gEfiComponentName2ProtocolGuid,\r
1660                     (VOID **) &ComponentName2\r
1661                     );\r
1662     if (!EFI_ERROR (Status)) {\r
1663       gBS->UninstallProtocolInterface (\r
1664              ImageHandle,\r
1665              &gEfiComponentName2ProtocolGuid,\r
1666              ComponentName2\r
1667              );\r
1668     }\r
1669   }\r
1670 \r
1671   //\r
1672   // Free the buffer containing the list of handles from the handle database\r
1673   //\r
1674   if (DeviceHandleBuffer != NULL) {\r
1675     gBS->FreePool (DeviceHandleBuffer);\r
1676   }\r
1677 \r
1678   return EFI_SUCCESS;\r
1679 }\r
1680 \r
1681 \r
1682 \r
1683 /**\r
1684   Create a child of the service that is identified by ServiceBindingGuid.\r
1685 \r
1686   Get the ServiceBinding Protocol first, then use it to create a child.\r
1687 \r
1688   If ServiceBindingGuid is NULL, then ASSERT().\r
1689   If ChildHandle is NULL, then ASSERT().\r
1690 \r
1691   @param[in]       Controller            The controller which has the service installed.\r
1692   @param[in]       Image                 The image handle used to open service.\r
1693   @param[in]       ServiceBindingGuid    The service's Guid.\r
1694   @param[in, out]  ChildHandle           The handle to receive the create child.\r
1695 \r
1696   @retval EFI_SUCCESS           The child is successfully created.\r
1697   @retval Others                Failed to create the child.\r
1698 \r
1699 **/\r
1700 EFI_STATUS\r
1701 EFIAPI\r
1702 NetLibCreateServiceChild (\r
1703   IN  EFI_HANDLE            Controller,\r
1704   IN  EFI_HANDLE            Image,\r
1705   IN  EFI_GUID              *ServiceBindingGuid,\r
1706   IN  OUT EFI_HANDLE        *ChildHandle\r
1707   )\r
1708 {\r
1709   EFI_STATUS                    Status;\r
1710   EFI_SERVICE_BINDING_PROTOCOL  *Service;\r
1711 \r
1712 \r
1713   ASSERT ((ServiceBindingGuid != NULL) && (ChildHandle != NULL));\r
1714 \r
1715   //\r
1716   // Get the ServiceBinding Protocol\r
1717   //\r
1718   Status = gBS->OpenProtocol (\r
1719                   Controller,\r
1720                   ServiceBindingGuid,\r
1721                   (VOID **) &Service,\r
1722                   Image,\r
1723                   Controller,\r
1724                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1725                   );\r
1726 \r
1727   if (EFI_ERROR (Status)) {\r
1728     return Status;\r
1729   }\r
1730 \r
1731   //\r
1732   // Create a child\r
1733   //\r
1734   Status = Service->CreateChild (Service, ChildHandle);\r
1735   return Status;\r
1736 }\r
1737 \r
1738 \r
1739 /**\r
1740   Destory a child of the service that is identified by ServiceBindingGuid.\r
1741 \r
1742   Get the ServiceBinding Protocol first, then use it to destroy a child.\r
1743 \r
1744   If ServiceBindingGuid is NULL, then ASSERT().\r
1745 \r
1746   @param[in]   Controller            The controller which has the service installed.\r
1747   @param[in]   Image                 The image handle used to open service.\r
1748   @param[in]   ServiceBindingGuid    The service's Guid.\r
1749   @param[in]   ChildHandle           The child to destory.\r
1750 \r
1751   @retval EFI_SUCCESS           The child is successfully destoried.\r
1752   @retval Others                Failed to destory the child.\r
1753 \r
1754 **/\r
1755 EFI_STATUS\r
1756 EFIAPI\r
1757 NetLibDestroyServiceChild (\r
1758   IN  EFI_HANDLE            Controller,\r
1759   IN  EFI_HANDLE            Image,\r
1760   IN  EFI_GUID              *ServiceBindingGuid,\r
1761   IN  EFI_HANDLE            ChildHandle\r
1762   )\r
1763 {\r
1764   EFI_STATUS                    Status;\r
1765   EFI_SERVICE_BINDING_PROTOCOL  *Service;\r
1766 \r
1767   ASSERT (ServiceBindingGuid != NULL);\r
1768 \r
1769   //\r
1770   // Get the ServiceBinding Protocol\r
1771   //\r
1772   Status = gBS->OpenProtocol (\r
1773                   Controller,\r
1774                   ServiceBindingGuid,\r
1775                   (VOID **) &Service,\r
1776                   Image,\r
1777                   Controller,\r
1778                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1779                   );\r
1780 \r
1781   if (EFI_ERROR (Status)) {\r
1782     return Status;\r
1783   }\r
1784 \r
1785   //\r
1786   // destory the child\r
1787   //\r
1788   Status = Service->DestroyChild (Service, ChildHandle);\r
1789   return Status;\r
1790 }\r
1791 \r
1792 /**\r
1793   Get handle with Simple Network Protocol installed on it.\r
1794 \r
1795   There should be MNP Service Binding Protocol installed on the input ServiceHandle.\r
1796   If Simple Network Protocol is already installed on the ServiceHandle, the\r
1797   ServiceHandle will be returned. If SNP is not installed on the ServiceHandle,\r
1798   try to find its parent handle with SNP installed.\r
1799 \r
1800   @param[in]   ServiceHandle    The handle where network service binding protocols are\r
1801                                 installed on.\r
1802   @param[out]  Snp              The pointer to store the address of the SNP instance.\r
1803                                 This is an optional parameter that may be NULL.\r
1804 \r
1805   @return The SNP handle, or NULL if not found.\r
1806 \r
1807 **/\r
1808 EFI_HANDLE\r
1809 EFIAPI\r
1810 NetLibGetSnpHandle (\r
1811   IN   EFI_HANDLE                  ServiceHandle,\r
1812   OUT  EFI_SIMPLE_NETWORK_PROTOCOL **Snp  OPTIONAL\r
1813   )\r
1814 {\r
1815   EFI_STATUS                   Status;\r
1816   EFI_SIMPLE_NETWORK_PROTOCOL  *SnpInstance;\r
1817   EFI_DEVICE_PATH_PROTOCOL     *DevicePath;\r
1818   EFI_HANDLE                   SnpHandle;\r
1819 \r
1820   //\r
1821   // Try to open SNP from ServiceHandle\r
1822   //\r
1823   SnpInstance = NULL;\r
1824   Status = gBS->HandleProtocol (ServiceHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);\r
1825   if (!EFI_ERROR (Status)) {\r
1826     if (Snp != NULL) {\r
1827       *Snp = SnpInstance;\r
1828     }\r
1829     return ServiceHandle;\r
1830   }\r
1831 \r
1832   //\r
1833   // Failed to open SNP, try to get SNP handle by LocateDevicePath()\r
1834   //\r
1835   DevicePath = DevicePathFromHandle (ServiceHandle);\r
1836   if (DevicePath == NULL) {\r
1837     return NULL;\r
1838   }\r
1839 \r
1840   SnpHandle = NULL;\r
1841   Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &DevicePath, &SnpHandle);\r
1842   if (EFI_ERROR (Status)) {\r
1843     //\r
1844     // Failed to find SNP handle\r
1845     //\r
1846     return NULL;\r
1847   }\r
1848 \r
1849   Status = gBS->HandleProtocol (SnpHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);\r
1850   if (!EFI_ERROR (Status)) {\r
1851     if (Snp != NULL) {\r
1852       *Snp = SnpInstance;\r
1853     }\r
1854     return SnpHandle;\r
1855   }\r
1856 \r
1857   return NULL;\r
1858 }\r
1859 \r
1860 /**\r
1861   Retrieve VLAN ID of a VLAN device handle.\r
1862 \r
1863   Search VLAN device path node in Device Path of specified ServiceHandle and\r
1864   return its VLAN ID. If no VLAN device path node found, then this ServiceHandle\r
1865   is not a VLAN device handle, and 0 will be returned.\r
1866 \r
1867   @param[in]   ServiceHandle    The handle where network service binding protocols are\r
1868                                 installed on.\r
1869 \r
1870   @return VLAN ID of the device handle, or 0 if not a VLAN device.\r
1871 \r
1872 **/\r
1873 UINT16\r
1874 EFIAPI\r
1875 NetLibGetVlanId (\r
1876   IN EFI_HANDLE             ServiceHandle\r
1877   )\r
1878 {\r
1879   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
1880   EFI_DEVICE_PATH_PROTOCOL  *Node;\r
1881 \r
1882   DevicePath = DevicePathFromHandle (ServiceHandle);\r
1883   if (DevicePath == NULL) {\r
1884     return 0;\r
1885   }\r
1886 \r
1887   Node = DevicePath;\r
1888   while (!IsDevicePathEnd (Node)) {\r
1889     if (Node->Type == MESSAGING_DEVICE_PATH && Node->SubType == MSG_VLAN_DP) {\r
1890       return ((VLAN_DEVICE_PATH *) Node)->VlanId;\r
1891     }\r
1892     Node = NextDevicePathNode (Node);\r
1893   }\r
1894 \r
1895   return 0;\r
1896 }\r
1897 \r
1898 /**\r
1899   Find VLAN device handle with specified VLAN ID.\r
1900 \r
1901   The VLAN child device handle is created by VLAN Config Protocol on ControllerHandle.\r
1902   This function will append VLAN device path node to the parent device path,\r
1903   and then use LocateDevicePath() to find the correct VLAN device handle.\r
1904 \r
1905   @param[in]   ControllerHandle The handle where network service binding protocols are\r
1906                                 installed on.\r
1907   @param[in]   VlanId           The configured VLAN ID for the VLAN device.\r
1908 \r
1909   @return The VLAN device handle, or NULL if not found.\r
1910 \r
1911 **/\r
1912 EFI_HANDLE\r
1913 EFIAPI\r
1914 NetLibGetVlanHandle (\r
1915   IN EFI_HANDLE             ControllerHandle,\r
1916   IN UINT16                 VlanId\r
1917   )\r
1918 {\r
1919   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;\r
1920   EFI_DEVICE_PATH_PROTOCOL  *VlanDevicePath;\r
1921   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
1922   VLAN_DEVICE_PATH          VlanNode;\r
1923   EFI_HANDLE                Handle;\r
1924 \r
1925   ParentDevicePath = DevicePathFromHandle (ControllerHandle);\r
1926   if (ParentDevicePath == NULL) {\r
1927     return NULL;\r
1928   }\r
1929 \r
1930   //\r
1931   // Construct VLAN device path\r
1932   //\r
1933   CopyMem (&VlanNode, &mNetVlanDevicePathTemplate, sizeof (VLAN_DEVICE_PATH));\r
1934   VlanNode.VlanId = VlanId;\r
1935   VlanDevicePath = AppendDevicePathNode (\r
1936                      ParentDevicePath,\r
1937                      (EFI_DEVICE_PATH_PROTOCOL *) &VlanNode\r
1938                      );\r
1939   if (VlanDevicePath == NULL) {\r
1940     return NULL;\r
1941   }\r
1942 \r
1943   //\r
1944   // Find VLAN device handle\r
1945   //\r
1946   Handle = NULL;\r
1947   DevicePath = VlanDevicePath;\r
1948   gBS->LocateDevicePath (\r
1949          &gEfiDevicePathProtocolGuid,\r
1950          &DevicePath,\r
1951          &Handle\r
1952          );\r
1953   if (!IsDevicePathEnd (DevicePath)) {\r
1954     //\r
1955     // Device path is not exactly match\r
1956     //\r
1957     Handle = NULL;\r
1958   }\r
1959 \r
1960   FreePool (VlanDevicePath);\r
1961   return Handle;\r
1962 }\r
1963 \r
1964 /**\r
1965   Get MAC address associated with the network service handle.\r
1966 \r
1967   There should be MNP Service Binding Protocol installed on the input ServiceHandle.\r
1968   If SNP is installed on the ServiceHandle or its parent handle, MAC address will\r
1969   be retrieved from SNP. If no SNP found, try to get SNP mode data use MNP.\r
1970 \r
1971   @param[in]   ServiceHandle    The handle where network service binding protocols are\r
1972                                 installed on.\r
1973   @param[out]  MacAddress       The pointer to store the returned MAC address.\r
1974   @param[out]  AddressSize      The length of returned MAC address.\r
1975 \r
1976   @retval EFI_SUCCESS           MAC address is returned successfully.\r
1977   @retval Others                Failed to get SNP mode data.\r
1978 \r
1979 **/\r
1980 EFI_STATUS\r
1981 EFIAPI\r
1982 NetLibGetMacAddress (\r
1983   IN  EFI_HANDLE            ServiceHandle,\r
1984   OUT EFI_MAC_ADDRESS       *MacAddress,\r
1985   OUT UINTN                 *AddressSize\r
1986   )\r
1987 {\r
1988   EFI_STATUS                   Status;\r
1989   EFI_SIMPLE_NETWORK_PROTOCOL  *Snp;\r
1990   EFI_SIMPLE_NETWORK_MODE      *SnpMode;\r
1991   EFI_SIMPLE_NETWORK_MODE      SnpModeData;\r
1992   EFI_MANAGED_NETWORK_PROTOCOL *Mnp;\r
1993   EFI_SERVICE_BINDING_PROTOCOL *MnpSb;\r
1994   EFI_HANDLE                   *SnpHandle;\r
1995   EFI_HANDLE                   MnpChildHandle;\r
1996 \r
1997   ASSERT (MacAddress != NULL);\r
1998   ASSERT (AddressSize != NULL);\r
1999 \r
2000   //\r
2001   // Try to get SNP handle\r
2002   //\r
2003   Snp = NULL;\r
2004   SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);\r
2005   if (SnpHandle != NULL) {\r
2006     //\r
2007     // SNP found, use it directly\r
2008     //\r
2009     SnpMode = Snp->Mode;\r
2010   } else {\r
2011     //\r
2012     // Failed to get SNP handle, try to get MAC address from MNP\r
2013     //\r
2014     MnpChildHandle = NULL;\r
2015     Status = gBS->HandleProtocol (\r
2016                     ServiceHandle,\r
2017                     &gEfiManagedNetworkServiceBindingProtocolGuid,\r
2018                     (VOID **) &MnpSb\r
2019                     );\r
2020     if (EFI_ERROR (Status)) {\r
2021       return Status;\r
2022     }\r
2023 \r
2024     //\r
2025     // Create a MNP child\r
2026     //\r
2027     Status = MnpSb->CreateChild (MnpSb, &MnpChildHandle);\r
2028     if (EFI_ERROR (Status)) {\r
2029       return Status;\r
2030     }\r
2031 \r
2032     //\r
2033     // Open MNP protocol\r
2034     //\r
2035     Status = gBS->HandleProtocol (\r
2036                     MnpChildHandle,\r
2037                     &gEfiManagedNetworkProtocolGuid,\r
2038                     (VOID **) &Mnp\r
2039                     );\r
2040     if (EFI_ERROR (Status)) {\r
2041       return Status;\r
2042     }\r
2043 \r
2044     //\r
2045     // Try to get SNP mode from MNP\r
2046     //\r
2047     Status = Mnp->GetModeData (Mnp, NULL, &SnpModeData);\r
2048     if (EFI_ERROR (Status)) {\r
2049       return Status;\r
2050     }\r
2051     SnpMode = &SnpModeData;\r
2052 \r
2053     //\r
2054     // Destroy the MNP child\r
2055     //\r
2056     MnpSb->DestroyChild (MnpSb, MnpChildHandle);\r
2057   }\r
2058 \r
2059   *AddressSize = SnpMode->HwAddressSize;\r
2060   CopyMem (MacAddress->Addr, SnpMode->CurrentAddress.Addr, SnpMode->HwAddressSize);\r
2061 \r
2062   return EFI_SUCCESS;\r
2063 }\r
2064 \r
2065 /**\r
2066   Convert MAC address of the NIC associated with specified Service Binding Handle\r
2067   to a unicode string. Callers are responsible for freeing the string storage.\r
2068 \r
2069   Locate simple network protocol associated with the Service Binding Handle and\r
2070   get the mac address from SNP. Then convert the mac address into a unicode\r
2071   string. It takes 2 unicode characters to represent a 1 byte binary buffer.\r
2072   Plus one unicode character for the null-terminator.\r
2073 \r
2074   @param[in]   ServiceHandle         The handle where network service binding protocol is\r
2075                                      installed on.\r
2076   @param[in]   ImageHandle           The image handle used to act as the agent handle to\r
2077                                      get the simple network protocol.\r
2078   @param[out]  MacString             The pointer to store the address of the string\r
2079                                      representation of  the mac address.\r
2080 \r
2081   @retval EFI_SUCCESS           Convert the mac address a unicode string successfully.\r
2082   @retval EFI_OUT_OF_RESOURCES  There are not enough memory resource.\r
2083   @retval Others                Failed to open the simple network protocol.\r
2084 \r
2085 **/\r
2086 EFI_STATUS\r
2087 EFIAPI\r
2088 NetLibGetMacString (\r
2089   IN  EFI_HANDLE            ServiceHandle,\r
2090   IN  EFI_HANDLE            ImageHandle,\r
2091   OUT CHAR16                **MacString\r
2092   )\r
2093 {\r
2094   EFI_STATUS                   Status;\r
2095   EFI_MAC_ADDRESS              MacAddress;\r
2096   UINT8                        *HwAddress;\r
2097   UINTN                        HwAddressSize;\r
2098   UINT16                       VlanId;\r
2099   CHAR16                       *String;\r
2100   UINTN                        Index;\r
2101 \r
2102   ASSERT (MacString != NULL);\r
2103 \r
2104   //\r
2105   // Get MAC address of the network device\r
2106   //\r
2107   Status = NetLibGetMacAddress (ServiceHandle, &MacAddress, &HwAddressSize);\r
2108   if (EFI_ERROR (Status)) {\r
2109     return Status;\r
2110   }\r
2111 \r
2112   //\r
2113   // It takes 2 unicode characters to represent a 1 byte binary buffer.\r
2114   // If VLAN is configured, it will need extra 5 characters like "\0005".\r
2115   // Plus one unicode character for the null-terminator.\r
2116   //\r
2117   String = AllocateZeroPool ((2 * HwAddressSize + 5 + 1) * sizeof (CHAR16));\r
2118   if (String == NULL) {\r
2119     return EFI_OUT_OF_RESOURCES;\r
2120   }\r
2121   *MacString = String;\r
2122 \r
2123   //\r
2124   // Convert the MAC address into a unicode string.\r
2125   //\r
2126   HwAddress = &MacAddress.Addr[0];\r
2127   for (Index = 0; Index < HwAddressSize; Index++) {\r
2128     String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(HwAddress++), 2);\r
2129   }\r
2130 \r
2131   //\r
2132   // Append VLAN ID if any\r
2133   //\r
2134   VlanId = NetLibGetVlanId (ServiceHandle);\r
2135   if (VlanId != 0) {\r
2136     *String++ = L'\\';\r
2137     String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, VlanId, 4);\r
2138   }\r
2139 \r
2140   //\r
2141   // Null terminate the Unicode string\r
2142   //\r
2143   *String = L'\0';\r
2144 \r
2145   return EFI_SUCCESS;\r
2146 }\r
2147 \r
2148 /**\r
2149   Check the default address used by the IPv4 driver is static or dynamic (acquired\r
2150   from DHCP).\r
2151 \r
2152   If the controller handle does not have the NIC Ip4 Config Protocol installed, the\r
2153   default address is static. If the EFI variable to save the configuration is not found,\r
2154   the default address is static. Otherwise, get the result from the EFI variable which\r
2155   saving the configuration.\r
2156 \r
2157   @param[in]   Controller     The controller handle which has the NIC Ip4 Config Protocol\r
2158                               relative with the default address to judge.\r
2159 \r
2160   @retval TRUE           If the default address is static.\r
2161   @retval FALSE          If the default address is acquired from DHCP.\r
2162 \r
2163 **/\r
2164 BOOLEAN\r
2165 NetLibDefaultAddressIsStatic (\r
2166   IN EFI_HANDLE  Controller\r
2167   )\r
2168 {\r
2169   EFI_STATUS                       Status;\r
2170   EFI_HII_CONFIG_ROUTING_PROTOCOL  *HiiConfigRouting;\r
2171   UINTN                            Len;\r
2172   NIC_IP4_CONFIG_INFO              *ConfigInfo;\r
2173   BOOLEAN                          IsStatic;\r
2174   EFI_STRING                       ConfigHdr;\r
2175   EFI_STRING                       ConfigResp;\r
2176   EFI_STRING                       AccessProgress;\r
2177   EFI_STRING                       AccessResults;\r
2178   EFI_STRING                       String;\r
2179 \r
2180   ConfigInfo       = NULL;\r
2181   ConfigHdr        = NULL;\r
2182   ConfigResp       = NULL;\r
2183   AccessProgress   = NULL;\r
2184   AccessResults    = NULL;\r
2185   IsStatic         = TRUE;\r
2186 \r
2187   Status = gBS->LocateProtocol (\r
2188                   &gEfiHiiConfigRoutingProtocolGuid,\r
2189                   NULL,\r
2190                   (VOID **) &HiiConfigRouting\r
2191                   );\r
2192   if (EFI_ERROR (Status)) {\r
2193     return TRUE;\r
2194   }\r
2195 \r
2196   //\r
2197   // Construct config request string header\r
2198   //\r
2199   ConfigHdr = HiiConstructConfigHdr (&gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE, Controller);\r
2200   if (ConfigHdr == NULL) {\r
2201     return TRUE;\r
2202   }\r
2203 \r
2204   Len = StrLen (ConfigHdr);\r
2205   ConfigResp = AllocateZeroPool ((Len + NIC_ITEM_CONFIG_SIZE * 2 + 100) * sizeof (CHAR16));\r
2206   if (ConfigResp == NULL) {\r
2207     goto ON_EXIT;\r
2208   }\r
2209   StrCpy (ConfigResp, ConfigHdr);\r
2210 \r
2211   String = ConfigResp + Len;\r
2212   UnicodeSPrint (\r
2213     String,\r
2214     (8 + 4 + 7 + 4 + 1) * sizeof (CHAR16),\r
2215     L"&OFFSET=%04X&WIDTH=%04X",\r
2216     OFFSET_OF (NIC_IP4_CONFIG_INFO, Source),\r
2217     sizeof (UINT32)\r
2218     );\r
2219 \r
2220   Status = HiiConfigRouting->ExtractConfig (\r
2221                                HiiConfigRouting,\r
2222                                ConfigResp,\r
2223                                &AccessProgress,\r
2224                                &AccessResults\r
2225                                );\r
2226   if (EFI_ERROR (Status)) {\r
2227     goto ON_EXIT;\r
2228   }\r
2229 \r
2230   ConfigInfo = AllocateZeroPool (sizeof (NIC_ITEM_CONFIG_SIZE));\r
2231   if (ConfigInfo == NULL) {\r
2232     goto ON_EXIT;\r
2233   }\r
2234 \r
2235   ConfigInfo->Source = IP4_CONFIG_SOURCE_STATIC;\r
2236   Len = NIC_ITEM_CONFIG_SIZE;\r
2237   Status = HiiConfigRouting->ConfigToBlock (\r
2238                                HiiConfigRouting,\r
2239                                AccessResults,\r
2240                                (UINT8 *) ConfigInfo,\r
2241                                &Len,\r
2242                                &AccessProgress\r
2243                                );\r
2244   if (EFI_ERROR (Status)) {\r
2245     goto ON_EXIT;\r
2246   }\r
2247 \r
2248   IsStatic = (BOOLEAN) (ConfigInfo->Source == IP4_CONFIG_SOURCE_STATIC);\r
2249 \r
2250 ON_EXIT:\r
2251 \r
2252   if (AccessResults != NULL) {\r
2253     FreePool (AccessResults);\r
2254   }\r
2255   if (ConfigInfo != NULL) {\r
2256     FreePool (ConfigInfo);\r
2257   }\r
2258   if (ConfigResp != NULL) {\r
2259     FreePool (ConfigResp);\r
2260   }\r
2261   if (ConfigHdr != NULL) {\r
2262     FreePool (ConfigHdr);\r
2263   }\r
2264 \r
2265   return IsStatic;\r
2266 }\r
2267 \r
2268 /**\r
2269   Create an IPv4 device path node.\r
2270 \r
2271   The header type of IPv4 device path node is MESSAGING_DEVICE_PATH.\r
2272   The header subtype of IPv4 device path node is MSG_IPv4_DP.\r
2273   The length of the IPv4 device path node in bytes is 19.\r
2274   Get other info from parameters to make up the whole IPv4 device path node.\r
2275 \r
2276   @param[in, out]  Node                  Pointer to the IPv4 device path node.\r
2277   @param[in]       Controller            The controller handle.\r
2278   @param[in]       LocalIp               The local IPv4 address.\r
2279   @param[in]       LocalPort             The local port.\r
2280   @param[in]       RemoteIp              The remote IPv4 address.\r
2281   @param[in]       RemotePort            The remote port.\r
2282   @param[in]       Protocol              The protocol type in the IP header.\r
2283   @param[in]       UseDefaultAddress     Whether this instance is using default address or not.\r
2284 \r
2285 **/\r
2286 VOID\r
2287 EFIAPI\r
2288 NetLibCreateIPv4DPathNode (\r
2289   IN OUT IPv4_DEVICE_PATH  *Node,\r
2290   IN EFI_HANDLE            Controller,\r
2291   IN IP4_ADDR              LocalIp,\r
2292   IN UINT16                LocalPort,\r
2293   IN IP4_ADDR              RemoteIp,\r
2294   IN UINT16                RemotePort,\r
2295   IN UINT16                Protocol,\r
2296   IN BOOLEAN               UseDefaultAddress\r
2297   )\r
2298 {\r
2299   Node->Header.Type    = MESSAGING_DEVICE_PATH;\r
2300   Node->Header.SubType = MSG_IPv4_DP;\r
2301   SetDevicePathNodeLength (&Node->Header, 19);\r
2302 \r
2303   CopyMem (&Node->LocalIpAddress, &LocalIp, sizeof (EFI_IPv4_ADDRESS));\r
2304   CopyMem (&Node->RemoteIpAddress, &RemoteIp, sizeof (EFI_IPv4_ADDRESS));\r
2305 \r
2306   Node->LocalPort  = LocalPort;\r
2307   Node->RemotePort = RemotePort;\r
2308 \r
2309   Node->Protocol = Protocol;\r
2310 \r
2311   if (!UseDefaultAddress) {\r
2312     Node->StaticIpAddress = TRUE;\r
2313   } else {\r
2314     Node->StaticIpAddress = NetLibDefaultAddressIsStatic (Controller);\r
2315   }\r
2316 }\r
2317 \r
2318 /**\r
2319   Create an IPv6 device path node.\r
2320 \r
2321   The header type of IPv6 device path node is MESSAGING_DEVICE_PATH.\r
2322   The header subtype of IPv6 device path node is MSG_IPv6_DP.\r
2323   Get other info from parameters to make up the whole IPv6 device path node.\r
2324 \r
2325   @param[in, out]  Node                  Pointer to the IPv6 device path node.\r
2326   @param[in]       Controller            The controller handle.\r
2327   @param[in]       LocalIp               The local IPv6 address.\r
2328   @param[in]       LocalPort             The local port.\r
2329   @param[in]       RemoteIp              The remote IPv6 address.\r
2330   @param[in]       RemotePort            The remote port.\r
2331   @param[in]       Protocol              The protocol type in the IP header.\r
2332 \r
2333 **/\r
2334 VOID\r
2335 EFIAPI\r
2336 NetLibCreateIPv6DPathNode (\r
2337   IN OUT IPv6_DEVICE_PATH  *Node,\r
2338   IN EFI_HANDLE            Controller,\r
2339   IN EFI_IPv6_ADDRESS      *LocalIp,\r
2340   IN UINT16                LocalPort,\r
2341   IN EFI_IPv6_ADDRESS      *RemoteIp,\r
2342   IN UINT16                RemotePort,\r
2343   IN UINT16                Protocol\r
2344   )\r
2345 {\r
2346   Node->Header.Type    = MESSAGING_DEVICE_PATH;\r
2347   Node->Header.SubType = MSG_IPv6_DP;\r
2348   SetDevicePathNodeLength (&Node->Header, sizeof (IPv6_DEVICE_PATH));\r
2349 \r
2350   CopyMem (&Node->LocalIpAddress, LocalIp, sizeof (EFI_IPv6_ADDRESS));\r
2351   CopyMem (&Node->RemoteIpAddress, RemoteIp, sizeof (EFI_IPv6_ADDRESS));\r
2352 \r
2353   Node->LocalPort  = LocalPort;\r
2354   Node->RemotePort = RemotePort;\r
2355 \r
2356   Node->Protocol        = Protocol;\r
2357   Node->StaticIpAddress = FALSE;\r
2358 }\r
2359 \r
2360 /**\r
2361   Find the UNDI/SNP handle from controller and protocol GUID.\r
2362 \r
2363   For example, IP will open a MNP child to transmit/receive\r
2364   packets, when MNP is stopped, IP should also be stopped. IP\r
2365   needs to find its own private data which is related the IP's\r
2366   service binding instance that is install on UNDI/SNP handle.\r
2367   Now, the controller is either a MNP or ARP child handle. But\r
2368   IP opens these handle BY_DRIVER, use that info, we can get the\r
2369   UNDI/SNP handle.\r
2370 \r
2371   @param[in]  Controller            Then protocol handle to check.\r
2372   @param[in]  ProtocolGuid          The protocol that is related with the handle.\r
2373 \r
2374   @return The UNDI/SNP handle or NULL for errors.\r
2375 \r
2376 **/\r
2377 EFI_HANDLE\r
2378 EFIAPI\r
2379 NetLibGetNicHandle (\r
2380   IN EFI_HANDLE             Controller,\r
2381   IN EFI_GUID               *ProtocolGuid\r
2382   )\r
2383 {\r
2384   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenBuffer;\r
2385   EFI_HANDLE                          Handle;\r
2386   EFI_STATUS                          Status;\r
2387   UINTN                               OpenCount;\r
2388   UINTN                               Index;\r
2389 \r
2390   Status = gBS->OpenProtocolInformation (\r
2391                   Controller,\r
2392                   ProtocolGuid,\r
2393                   &OpenBuffer,\r
2394                   &OpenCount\r
2395                   );\r
2396 \r
2397   if (EFI_ERROR (Status)) {\r
2398     return NULL;\r
2399   }\r
2400 \r
2401   Handle = NULL;\r
2402 \r
2403   for (Index = 0; Index < OpenCount; Index++) {\r
2404     if ((OpenBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {\r
2405       Handle = OpenBuffer[Index].ControllerHandle;\r
2406       break;\r
2407     }\r
2408   }\r
2409 \r
2410   gBS->FreePool (OpenBuffer);\r
2411   return Handle;\r
2412 }\r
2413 \r
2414 /**\r
2415   Convert one Null-terminated ASCII string (decimal dotted) to EFI_IPv4_ADDRESS.\r
2416 \r
2417   @param[in]      String         The pointer to the Ascii string.\r
2418   @param[out]     Ip4Address     The pointer to the converted IPv4 address.\r
2419 \r
2420   @retval EFI_SUCCESS            Convert to IPv4 address successfully.  \r
2421   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip4Address is NULL.\r
2422 \r
2423 **/\r
2424 EFI_STATUS\r
2425 NetLibAsciiStrToIp4 (\r
2426   IN CONST CHAR8                 *String,\r
2427   OUT      EFI_IPv4_ADDRESS      *Ip4Address\r
2428   )\r
2429 {\r
2430   UINT8                          Index;\r
2431   CHAR8                          *Ip4Str;\r
2432   CHAR8                          *TempStr;\r
2433   UINTN                          NodeVal;\r
2434 \r
2435   if ((String == NULL) || (Ip4Address == NULL)) {\r
2436     return EFI_INVALID_PARAMETER;\r
2437   }\r
2438 \r
2439   Ip4Str = (CHAR8 *) String;\r
2440 \r
2441   for (Index = 0; Index < 4; Index++) {\r
2442     TempStr = Ip4Str;\r
2443 \r
2444     while ((*Ip4Str != '\0') && (*Ip4Str != '.')) {\r
2445       Ip4Str++;\r
2446     }\r
2447 \r
2448     //\r
2449     // The IPv4 address is X.X.X.X\r
2450     //\r
2451     if (*Ip4Str == '.') {\r
2452       if (Index == 3) {\r
2453         return EFI_INVALID_PARAMETER;\r
2454       }\r
2455     } else {\r
2456       if (Index != 3) {\r
2457         return EFI_INVALID_PARAMETER;\r
2458       }\r
2459     }\r
2460 \r
2461     NodeVal = AsciiStrDecimalToUintn (TempStr);\r
2462     if (NodeVal > 0xFF) {\r
2463       return EFI_INVALID_PARAMETER;\r
2464     }\r
2465 \r
2466     Ip4Address->Addr[Index] = (UINT8) NodeVal;\r
2467 \r
2468     Ip4Str++;\r
2469   }\r
2470 \r
2471   return EFI_SUCCESS;\r
2472 }\r
2473 \r
2474 \r
2475 /**\r
2476   Convert one Null-terminated ASCII string to EFI_IPv6_ADDRESS. The format of the\r
2477   string is defined in RFC 4291 - Text Pepresentation of Addresses.\r
2478 \r
2479   @param[in]      String         The pointer to the Ascii string.\r
2480   @param[out]     Ip6Address     The pointer to the converted IPv6 address.\r
2481 \r
2482   @retval EFI_SUCCESS            Convert to IPv6 address successfully.  \r
2483   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip6Address is NULL.\r
2484 \r
2485 **/\r
2486 EFI_STATUS\r
2487 NetLibAsciiStrToIp6 (\r
2488   IN CONST CHAR8                 *String,\r
2489   OUT      EFI_IPv6_ADDRESS      *Ip6Address\r
2490   )\r
2491 {\r
2492   UINT8                          Index;\r
2493   CHAR8                          *Ip6Str;\r
2494   CHAR8                          *TempStr;\r
2495   CHAR8                          *TempStr2;\r
2496   UINT8                          NodeCnt;\r
2497   UINT8                          TailNodeCnt;\r
2498   UINT8                          AllowedCnt;\r
2499   UINTN                          NodeVal;\r
2500   BOOLEAN                        Short;\r
2501   BOOLEAN                        Update;\r
2502 \r
2503   if ((String == NULL) || (Ip6Address == NULL)) {\r
2504     return EFI_INVALID_PARAMETER;\r
2505   }\r
2506 \r
2507   Ip6Str     = (CHAR8 *) String;\r
2508   AllowedCnt = 6;\r
2509 \r
2510   //\r
2511   // An IPv6 address leading with : looks strange.\r
2512   //\r
2513   if (*Ip6Str == ':') {\r
2514     if (*(Ip6Str + 1) != ':') {\r
2515       return EFI_INVALID_PARAMETER;\r
2516     } else {\r
2517       AllowedCnt = 7;\r
2518     }    \r
2519   }\r
2520 \r
2521   ZeroMem (Ip6Address, sizeof (EFI_IPv6_ADDRESS));\r
2522 \r
2523   NodeCnt     = 0;\r
2524   TailNodeCnt = 0;\r
2525   Short       = FALSE;\r
2526   Update      = FALSE;\r
2527 \r
2528   for (Index = 0; (Index + 1) < 16; Index = (UINT8) (Index + 2)) {\r
2529     TempStr = Ip6Str;\r
2530 \r
2531     while ((*Ip6Str != '\0') && (*Ip6Str != ':')) {\r
2532       Ip6Str++;\r
2533     }\r
2534 \r
2535     if ((*Ip6Str == '\0') && (Index != 14)) {\r
2536       return EFI_INVALID_PARAMETER;\r
2537     }\r
2538 \r
2539     if (*Ip6Str == ':') {\r
2540       if (*(Ip6Str + 1) == ':') {\r
2541         if ((*(Ip6Str + 2) == '0') || (NodeCnt > 6)) {\r
2542           //\r
2543           // ::0 looks strange. report error to user.\r
2544           //\r
2545           return EFI_INVALID_PARAMETER;\r
2546         }           \r
2547 \r
2548         //\r
2549         // Skip the abbreviation part of IPv6 address.\r
2550         //\r
2551         TempStr2 = Ip6Str + 2;\r
2552         while ((*TempStr2 != '\0')) {\r
2553           if (*TempStr2 == ':') {\r
2554             if (*(TempStr2 + 1) == ':') {\r
2555               //\r
2556               // :: can only appear once in IPv6 address.\r
2557               //\r
2558               return EFI_INVALID_PARAMETER;\r
2559             }\r
2560             \r
2561             TailNodeCnt++;\r
2562             if (TailNodeCnt >= (AllowedCnt - NodeCnt)) {\r
2563               //\r
2564               // :: indicates one or more groups of 16 bits of zeros.\r
2565               //\r
2566               return EFI_INVALID_PARAMETER;\r
2567             }\r
2568           }\r
2569 \r
2570           TempStr2++;\r
2571         }       \r
2572 \r
2573         Short  = TRUE;\r
2574         Update = TRUE;\r
2575 \r
2576         Ip6Str = Ip6Str + 2;\r
2577       } else {\r
2578         Ip6Str++;\r
2579         NodeCnt++;\r
2580         if ((Short && (NodeCnt > 6)) || (!Short && (NodeCnt > 7))) {\r
2581           //\r
2582           // There are more than 8 groups of 16 bits of zeros.\r
2583           //\r
2584           return EFI_INVALID_PARAMETER;\r
2585         }\r
2586       }      \r
2587     }    \r
2588 \r
2589     //\r
2590     // Convert the Str to IPv6 address.\r
2591     //\r
2592     NodeVal = AsciiStrHexToUintn (TempStr);\r
2593     if ((NodeVal > 0xFFFF) || (Index > 14)) {\r
2594       return EFI_INVALID_PARAMETER;\r
2595     }\r
2596 \r
2597     Ip6Address->Addr[Index] = (UINT8) (NodeVal >> 8);\r
2598     Ip6Address->Addr[Index + 1] = (UINT8) (NodeVal & 0xFF);\r
2599 \r
2600     //\r
2601     // Skip the groups of zeros by ::\r
2602     //\r
2603     if (Short && Update) {\r
2604       Index  = (UINT8) (16 - (TailNodeCnt + 2) * 2);\r
2605       Update = FALSE;\r
2606     }\r
2607   }\r
2608 \r
2609   if ((!Short && Index != 16) || (*Ip6Str != '\0')) {\r
2610     return EFI_INVALID_PARAMETER;\r
2611   }\r
2612 \r
2613   return EFI_SUCCESS;\r
2614 }\r
2615 \r
2616 \r
2617 /**\r
2618   Convert one Null-terminated Unicode string (decimal dotted) to EFI_IPv4_ADDRESS.\r
2619 \r
2620   @param[in]      String         The pointer to the Ascii string.\r
2621   @param[out]     Ip4Address     The pointer to the converted IPv4 address.\r
2622 \r
2623   @retval EFI_SUCCESS            Convert to IPv4 address successfully.  \r
2624   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip4Address is NULL.\r
2625   @retval EFI_OUT_OF_RESOURCES   Fail to perform the operation due to lack of resource.\r
2626 \r
2627 **/\r
2628 EFI_STATUS\r
2629 NetLibStrToIp4 (\r
2630   IN CONST CHAR16                *String,\r
2631   OUT      EFI_IPv4_ADDRESS      *Ip4Address\r
2632   )\r
2633 {\r
2634   CHAR8                          *Ip4Str;\r
2635   EFI_STATUS                     Status;\r
2636   \r
2637   if ((String == NULL) || (Ip4Address == NULL)) {\r
2638     return EFI_INVALID_PARAMETER;\r
2639   }\r
2640 \r
2641   Ip4Str = (CHAR8 *) AllocatePool ((StrLen (String) + 1) * sizeof (CHAR8));\r
2642   if (Ip4Str == NULL) {\r
2643     return EFI_OUT_OF_RESOURCES;\r
2644   }\r
2645 \r
2646   UnicodeStrToAsciiStr (String, Ip4Str);\r
2647 \r
2648   Status = NetLibAsciiStrToIp4 (Ip4Str, Ip4Address);\r
2649 \r
2650   FreePool (Ip4Str);\r
2651 \r
2652   return Status;\r
2653 }\r
2654 \r
2655 \r
2656 /**\r
2657   Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS.  The format of\r
2658   the string is defined in RFC 4291 - Text Pepresentation of Addresses.\r
2659 \r
2660   @param[in]      String         The pointer to the Ascii string.\r
2661   @param[out]     Ip6Address     The pointer to the converted IPv6 address.\r
2662 \r
2663   @retval EFI_SUCCESS            Convert to IPv6 address successfully.  \r
2664   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip6Address is NULL.\r
2665   @retval EFI_OUT_OF_RESOURCES   Fail to perform the operation due to lack of resource.\r
2666 \r
2667 **/\r
2668 EFI_STATUS\r
2669 NetLibStrToIp6 (\r
2670   IN CONST CHAR16                *String,\r
2671   OUT      EFI_IPv6_ADDRESS      *Ip6Address\r
2672   ) \r
2673 {\r
2674   CHAR8                          *Ip6Str;\r
2675   EFI_STATUS                     Status;\r
2676   \r
2677   if ((String == NULL) || (Ip6Address == NULL)) {\r
2678     return EFI_INVALID_PARAMETER;\r
2679   }\r
2680 \r
2681   Ip6Str = (CHAR8 *) AllocatePool ((StrLen (String) + 1) * sizeof (CHAR8));\r
2682   if (Ip6Str == NULL) {\r
2683     return EFI_OUT_OF_RESOURCES;\r
2684   }\r
2685 \r
2686   UnicodeStrToAsciiStr (String, Ip6Str);\r
2687 \r
2688   Status = NetLibAsciiStrToIp6 (Ip6Str, Ip6Address);\r
2689 \r
2690   FreePool (Ip6Str);\r
2691 \r
2692   return Status;\r
2693 }\r
2694 \r
2695 /**\r
2696   Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS and prefix length.\r
2697   The format of the string is defined in RFC 4291 - Text Pepresentation of Addresses\r
2698   Prefixes: ipv6-address/prefix-length.\r
2699 \r
2700   @param[in]      String         The pointer to the Ascii string.\r
2701   @param[out]     Ip6Address     The pointer to the converted IPv6 address.\r
2702   @param[out]     PrefixLength   The pointer to the converted prefix length.\r
2703 \r
2704   @retval EFI_SUCCESS            Convert to IPv6 address successfully.  \r
2705   @retval EFI_INVALID_PARAMETER  The string is mal-formated or Ip6Address is NULL.\r
2706   @retval EFI_OUT_OF_RESOURCES   Fail to perform the operation due to lack of resource.\r
2707 \r
2708 **/\r
2709 EFI_STATUS\r
2710 NetLibStrToIp6andPrefix (\r
2711   IN CONST CHAR16                *String,\r
2712   OUT      EFI_IPv6_ADDRESS      *Ip6Address,\r
2713   OUT      UINT8                 *PrefixLength\r
2714   ) \r
2715 {\r
2716   CHAR8                          *Ip6Str;  \r
2717   CHAR8                          *PrefixStr;\r
2718   CHAR8                          *TempStr;\r
2719   EFI_STATUS                     Status;\r
2720   UINT8                          Length;\r
2721   \r
2722   if ((String == NULL) || (Ip6Address == NULL) || (PrefixLength == NULL)) {\r
2723     return EFI_INVALID_PARAMETER;\r
2724   }\r
2725 \r
2726   Ip6Str = (CHAR8 *) AllocatePool ((StrLen (String) + 1) * sizeof (CHAR8));\r
2727   if (Ip6Str == NULL) {\r
2728     return EFI_OUT_OF_RESOURCES;\r
2729   }\r
2730 \r
2731   UnicodeStrToAsciiStr (String, Ip6Str);\r
2732 \r
2733   //\r
2734   // Get the sub string describing prefix length.\r
2735   //\r
2736   TempStr = Ip6Str;\r
2737   while (*TempStr != '\0' && (*TempStr != '/')) {\r
2738     TempStr++;\r
2739   }\r
2740 \r
2741   if (*TempStr == '/') {\r
2742     PrefixStr = TempStr + 1;\r
2743   } else {\r
2744     PrefixStr = NULL;\r
2745   }\r
2746 \r
2747   //\r
2748   // Get the sub string describing IPv6 address and convert it.\r
2749   //\r
2750   *TempStr = '\0';\r
2751 \r
2752   Status = NetLibAsciiStrToIp6 (Ip6Str, Ip6Address);\r
2753   if (EFI_ERROR (Status)) {\r
2754     goto Exit;\r
2755   }\r
2756 \r
2757   //\r
2758   // Convert the string to prefix length\r
2759   //\r
2760   Length = 0;\r
2761   if (PrefixStr != NULL) {\r
2762 \r
2763     Status = EFI_INVALID_PARAMETER;\r
2764 \r
2765     while (*PrefixStr != '\0') {\r
2766       if (NET_IS_DIGIT (*PrefixStr)) {\r
2767         Length = (UINT8) (Length * 10 + (*PrefixStr - '0'));\r
2768         if (Length >= IP6_PREFIX_NUM) {\r
2769           goto Exit;\r
2770         }\r
2771       } else {\r
2772         goto Exit;\r
2773       }\r
2774 \r
2775       PrefixStr++;\r
2776     }\r
2777   }\r
2778 \r
2779   *PrefixLength = Length;\r
2780   Status        = EFI_SUCCESS;\r
2781 \r
2782 Exit:\r
2783 \r
2784   FreePool (Ip6Str);\r
2785   return Status;\r
2786 }\r
2787 \r