VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/NetworkPkg/Library/DxeNetLib/DxeNetLib.c

最後變更 在這個檔案是 105670,由 vboxsync 提交於 7 月 前

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette