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