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