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