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