4 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <IndustryStandard/SmBios.h>
13 #include <Protocol/DriverBinding.h>
14 #include <Protocol/ServiceBinding.h>
15 #include <Protocol/SimpleNetwork.h>
16 #include <Protocol/AdapterInformation.h>
17 #include <Protocol/ManagedNetwork.h>
18 #include <Protocol/Ip4Config2.h>
19 #include <Protocol/ComponentName.h>
20 #include <Protocol/ComponentName2.h>
22 #include <Guid/SmBios.h>
24 #include <Library/NetLib.h>
25 #include <Library/BaseLib.h>
26 #include <Library/DebugLib.h>
27 #include <Library/BaseMemoryLib.h>
28 #include <Library/UefiBootServicesTableLib.h>
29 #include <Library/UefiRuntimeServicesTableLib.h>
30 #include <Library/MemoryAllocationLib.h>
31 #include <Library/DevicePathLib.h>
32 #include <Library/PrintLib.h>
33 #include <Library/UefiLib.h>
35 #define NIC_ITEM_CONFIG_SIZE (sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE)
36 #define DEFAULT_ZERO_START ((UINTN) ~0)
39 // All the supported IP4 masks in host byte order.
41 GLOBAL_REMOVE_IF_UNREFERENCED IP4_ADDR gIp4AllMasks
[IP4_MASK_NUM
] = {
80 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IPv4_ADDRESS mZeroIp4Addr
= {
85 // Any error level digitally larger than mNetDebugLevelMax
86 // will be silently discarded.
88 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mNetDebugLevelMax
= NETDEBUG_LEVEL_ERROR
;
89 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogPacketSeq
= 0xDEADBEEF;
92 // You can change mSyslogDstMac mSyslogDstIp and mSyslogSrcIp
93 // here to direct the syslog packets to the syslog deamon. The
94 // default is broadcast to both the ethernet and IP.
96 GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mSyslogDstMac
[NET_ETHER_ADDR_LEN
] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
97 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogDstIp
= 0xffffffff;
98 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogSrcIp
= 0;
100 GLOBAL_REMOVE_IF_UNREFERENCED CHAR8
*mMonthName
[] = {
116 // VLAN device path node template
118 GLOBAL_REMOVE_IF_UNREFERENCED VLAN_DEVICE_PATH mNetVlanDevicePathTemplate
= {
120 MESSAGING_DEVICE_PATH
,
123 (UINT8
)(sizeof (VLAN_DEVICE_PATH
)),
124 (UINT8
)((sizeof (VLAN_DEVICE_PATH
)) >> 8)
131 Locate the handles that support SNP, then open one of them
132 to send the syslog packets. The caller isn't required to close
133 the SNP after use because the SNP is opened by HandleProtocol.
135 @return The point to SNP if one is properly opened. Otherwise NULL
138 EFI_SIMPLE_NETWORK_PROTOCOL
*
143 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
150 // Locate the handles which has SNP installed.
153 Status
= gBS
->LocateHandleBuffer (
155 &gEfiSimpleNetworkProtocolGuid
,
161 if (EFI_ERROR (Status
) || (HandleCount
== 0)) {
166 // Try to open one of the ethernet SNP protocol to send packet
170 for (Index
= 0; Index
< HandleCount
; Index
++) {
171 Status
= gBS
->HandleProtocol (
173 &gEfiSimpleNetworkProtocolGuid
,
177 if ((Status
== EFI_SUCCESS
) && (Snp
!= NULL
) &&
178 (Snp
->Mode
->IfType
== NET_IFTYPE_ETHERNET
) &&
179 (Snp
->Mode
->MaxPacketSize
>= NET_SYSLOG_PACKET_LEN
))
192 Transmit a syslog packet synchronously through SNP. The Packet
193 already has the ethernet header prepended. This function should
194 fill in the source MAC because it will try to locate a SNP each
195 time it is called to avoid the problem if SNP is unloaded.
196 This code snip is copied from MNP.
197 If Packet is NULL, then ASSERT().
199 @param[in] Packet The Syslog packet
200 @param[in] Length The length of the packet
202 @retval EFI_DEVICE_ERROR Failed to locate a usable SNP protocol
203 @retval EFI_TIMEOUT Timeout happened to send the packet.
204 @retval EFI_SUCCESS Packet is sent.
213 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
216 EFI_EVENT TimeoutEvent
;
219 ASSERT (Packet
!= NULL
);
221 Snp
= SyslogLocateSnp ();
224 return EFI_DEVICE_ERROR
;
227 Ether
= (ETHER_HEAD
*)Packet
;
228 CopyMem (Ether
->SrcMac
, Snp
->Mode
->CurrentAddress
.Addr
, NET_ETHER_ADDR_LEN
);
231 // Start the timeout event.
233 Status
= gBS
->CreateEvent (
241 if (EFI_ERROR (Status
)) {
245 Status
= gBS
->SetTimer (TimeoutEvent
, TimerRelative
, NET_SYSLOG_TX_TIMEOUT
);
247 if (EFI_ERROR (Status
)) {
253 // Transmit the packet through SNP.
255 Status
= Snp
->Transmit (Snp
, 0, Length
, Packet
, NULL
, NULL
, NULL
);
257 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_READY
)) {
258 Status
= EFI_DEVICE_ERROR
;
263 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
264 // if Status is EFI_NOT_READY, the transmit engine of the network
265 // interface is busy. Both need to sync SNP.
271 // Get the recycled transmit buffer status.
273 Snp
->GetStatus (Snp
, NULL
, (VOID
**)&TxBuf
);
275 if (!EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
276 Status
= EFI_TIMEOUT
;
279 } while (TxBuf
== NULL
);
281 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_TIMEOUT
)) {
286 // Status is EFI_NOT_READY. Restart the timer event and
287 // call Snp->Transmit again.
289 gBS
->SetTimer (TimeoutEvent
, TimerRelative
, NET_SYSLOG_TX_TIMEOUT
);
292 gBS
->SetTimer (TimeoutEvent
, TimerCancel
, 0);
295 gBS
->CloseEvent (TimeoutEvent
);
300 Build a syslog packet, including the Ethernet/Ip/Udp headers
303 @param[in] Level Syslog severity level
304 @param[in] Module The module that generates the log
305 @param[in] File The file that contains the current log
306 @param[in] Line The line of code in the File that contains the current log
307 @param[in] Message The log message
308 @param[in] BufLen The length of the Buf
309 @param[out] Buf The buffer to put the packet data
311 @return The length of the syslog packet built, 0 represents no packet is built.
328 EFI_UDP_HEADER
*Udp4
;
334 // Fill in the Ethernet header. Leave alone the source MAC.
335 // SyslogSendPacket will fill in the address for us.
337 Ether
= (ETHER_HEAD
*)Buf
;
338 CopyMem (Ether
->DstMac
, mSyslogDstMac
, NET_ETHER_ADDR_LEN
);
339 ZeroMem (Ether
->SrcMac
, NET_ETHER_ADDR_LEN
);
341 Ether
->EtherType
= HTONS (0x0800); // IPv4 protocol
343 Buf
+= sizeof (ETHER_HEAD
);
344 BufLen
-= sizeof (ETHER_HEAD
);
347 // Fill in the IP header
349 Ip4
= (IP4_HEAD
*)Buf
;
354 Ip4
->Id
= (UINT16
)mSyslogPacketSeq
;
357 Ip4
->Protocol
= 0x11;
359 Ip4
->Src
= mSyslogSrcIp
;
360 Ip4
->Dst
= mSyslogDstIp
;
362 Buf
+= sizeof (IP4_HEAD
);
363 BufLen
-= sizeof (IP4_HEAD
);
366 // Fill in the UDP header, Udp checksum is optional. Leave it zero.
368 Udp4
= (EFI_UDP_HEADER
*)Buf
;
369 Udp4
->SrcPort
= HTONS (514);
370 Udp4
->DstPort
= HTONS (514);
374 Buf
+= sizeof (EFI_UDP_HEADER
);
375 BufLen
-= sizeof (EFI_UDP_HEADER
);
378 // Build the syslog message body with <PRI> Timestamp machine module Message
380 Pri
= ((NET_SYSLOG_FACILITY
& 31) << 3) | (Level
& 7);
381 Status
= gRT
->GetTime (&Time
, NULL
);
382 if (EFI_ERROR (Status
)) {
387 // Use %a to format the ASCII strings, %s to format UNICODE strings
390 Len
+= (UINT32
)AsciiSPrint (
393 "<%d> %a %d %d:%d:%d ",
395 mMonthName
[Time
.Month
-1],
402 Len
+= (UINT32
)AsciiSPrint (
405 "Tiano %a: %a (Line: %d File: %a)",
414 // OK, patch the IP length/checksum and UDP length fields.
416 Len
+= sizeof (EFI_UDP_HEADER
);
417 Udp4
->Length
= HTONS ((UINT16
)Len
);
419 Len
+= sizeof (IP4_HEAD
);
420 Ip4
->TotalLen
= HTONS ((UINT16
)Len
);
421 Ip4
->Checksum
= (UINT16
)(~NetblockChecksum ((UINT8
*)Ip4
, sizeof (IP4_HEAD
)));
423 return Len
+ sizeof (ETHER_HEAD
);
427 Allocate a buffer, then format the message to it. This is a
428 help function for the NET_DEBUG_XXX macros. The PrintArg of
429 these macros treats the variable length print parameters as a
430 single parameter, and pass it to the NetDebugASPrint. For
431 example, NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name))
435 NETDEBUG_LEVEL_TRACE,
439 NetDebugASPrint ("State transit to %a\n", Name)
442 If Format is NULL, then ASSERT().
444 @param Format The ASCII format string.
445 @param ... The variable length parameter whose format is determined
446 by the Format string.
448 @return The buffer containing the formatted message,
449 or NULL if failed to allocate memory.
462 ASSERT (Format
!= NULL
);
464 Buf
= (CHAR8
*)AllocatePool (NET_DEBUG_MSG_LEN
);
470 VA_START (Marker
, Format
);
471 AsciiVSPrint (Buf
, NET_DEBUG_MSG_LEN
, Format
, Marker
);
478 Builds an UDP4 syslog packet and send it using SNP.
480 This function will locate a instance of SNP then send the message through it.
481 Because it isn't open the SNP BY_DRIVER, apply caution when using it.
483 @param Level The severity level of the message.
484 @param Module The Module that generates the log.
485 @param File The file that contains the log.
486 @param Line The exact line that contains the log.
487 @param Message The user message to log.
489 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
490 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet.
491 @retval EFI_DEVICE_ERROR Device error occurs.
492 @retval EFI_SUCCESS The log is discard because that it is more verbose
493 than the mNetDebugLevelMax. Or, it has been sent out.
510 // Check whether the message should be sent out
512 if ((Message
== NULL
) || (File
== NULL
) || (Module
== NULL
)) {
513 return EFI_INVALID_PARAMETER
;
516 if (Level
> mNetDebugLevelMax
) {
517 Status
= EFI_SUCCESS
;
522 // Allocate a maximum of 1024 bytes, the caller should ensure
523 // that the message plus the ethernet/ip/udp header is shorter
526 Packet
= (CHAR8
*)AllocatePool (NET_SYSLOG_PACKET_LEN
);
528 if (Packet
== NULL
) {
529 Status
= EFI_OUT_OF_RESOURCES
;
534 // Build the message: Ethernet header + IP header + Udp Header + user data
536 Len
= SyslogBuildPacket (
542 NET_SYSLOG_PACKET_LEN
,
546 Status
= EFI_DEVICE_ERROR
;
549 Status
= SyslogSendPacket (Packet
, Len
);
560 Return the length of the mask.
562 Return the length of the mask, the correct value is from 0 to 32.
563 If the mask is invalid, return the invalid length 33, which is IP4_MASK_NUM.
564 NetMask is in the host byte order.
566 @param[in] NetMask The netmask to get the length from.
568 @return The length of the netmask, IP4_MASK_NUM if the mask is invalid.
579 for (Index
= 0; Index
<= IP4_MASK_MAX
; Index
++) {
580 if (NetMask
== gIp4AllMasks
[Index
]) {
589 Return the class of the IP address, such as class A, B, C.
590 Addr is in host byte order.
593 Classful addressing (IP class A/B/C) has been deprecated according to RFC4632.
594 Caller of this function could only check the returned value against
595 IP4_ADDR_CLASSD (multicast) or IP4_ADDR_CLASSE (reserved) now.
597 The address of class A starts with 0.
598 If the address belong to class A, return IP4_ADDR_CLASSA.
599 The address of class B starts with 10.
600 If the address belong to class B, return IP4_ADDR_CLASSB.
601 The address of class C starts with 110.
602 If the address belong to class C, return IP4_ADDR_CLASSC.
603 The address of class D starts with 1110.
604 If the address belong to class D, return IP4_ADDR_CLASSD.
605 The address of class E starts with 1111.
606 If the address belong to class E, return IP4_ADDR_CLASSE.
609 @param[in] Addr The address to get the class from.
611 @return IP address class, such as IP4_ADDR_CLASSA.
622 ByteOne
= (UINT8
)(Addr
>> 24);
624 if ((ByteOne
& 0x80) == 0) {
625 return IP4_ADDR_CLASSA
;
626 } else if ((ByteOne
& 0xC0) == 0x80) {
627 return IP4_ADDR_CLASSB
;
628 } else if ((ByteOne
& 0xE0) == 0xC0) {
629 return IP4_ADDR_CLASSC
;
630 } else if ((ByteOne
& 0xF0) == 0xE0) {
631 return IP4_ADDR_CLASSD
;
633 return IP4_ADDR_CLASSE
;
638 Check whether the IP is a valid unicast address according to
641 ASSERT if NetMask is zero.
643 If all bits of the host address of IP are 0 or 1, IP is also not a valid unicast address,
644 except when the originator is one of the endpoints of a point-to-point link with a 31-bit
645 mask (RFC3021), or a 32bit NetMask (all 0xFF) is used for special network environment (e.g.
648 @param[in] Ip The IP to check against.
649 @param[in] NetMask The mask of the IP.
651 @return TRUE if IP is a valid unicast address on the network, otherwise FALSE.
663 ASSERT (NetMask
!= 0);
665 if ((Ip
== 0) || IP4_IS_LOCAL_BROADCAST (Ip
)) {
669 MaskLength
= NetGetMaskLength (NetMask
);
670 ASSERT ((MaskLength
>= 0) && (MaskLength
<= IP4_MASK_NUM
));
671 if (MaskLength
< 31) {
672 if (((Ip
&~NetMask
) == ~NetMask
) || ((Ip
&~NetMask
) == 0)) {
681 Check whether the incoming IPv6 address is a valid unicast address.
683 ASSERT if Ip6 is NULL.
685 If the address is a multicast address has binary 0xFF at the start, it is not
686 a valid unicast address. If the address is unspecified ::, it is not a valid
687 unicast address to be assigned to any node. If the address is loopback address
688 ::1, it is also not a valid unicast address to be assigned to any physical
691 @param[in] Ip6 The IPv6 address to check against.
693 @return TRUE if Ip6 is a valid unicast address on the network, otherwise FALSE.
698 NetIp6IsValidUnicast (
699 IN EFI_IPv6_ADDRESS
*Ip6
705 ASSERT (Ip6
!= NULL
);
707 if (Ip6
->Addr
[0] == 0xFF) {
711 for (Index
= 0; Index
< 15; Index
++) {
712 if (Ip6
->Addr
[Index
] != 0) {
717 Byte
= Ip6
->Addr
[Index
];
719 if ((Byte
== 0x0) || (Byte
== 0x1)) {
727 Check whether the incoming Ipv6 address is the unspecified address or not.
729 ASSERT if Ip6 is NULL.
731 @param[in] Ip6 - Ip6 address, in network order.
733 @retval TRUE - Yes, unspecified
739 NetIp6IsUnspecifiedAddr (
740 IN EFI_IPv6_ADDRESS
*Ip6
745 ASSERT (Ip6
!= NULL
);
747 for (Index
= 0; Index
< 16; Index
++) {
748 if (Ip6
->Addr
[Index
] != 0) {
757 Check whether the incoming Ipv6 address is a link-local address.
759 ASSERT if Ip6 is NULL.
761 @param[in] Ip6 - Ip6 address, in network order.
763 @retval TRUE - Yes, link-local address
769 NetIp6IsLinkLocalAddr (
770 IN EFI_IPv6_ADDRESS
*Ip6
775 ASSERT (Ip6
!= NULL
);
777 if (Ip6
->Addr
[0] != 0xFE) {
781 if (Ip6
->Addr
[1] != 0x80) {
785 for (Index
= 2; Index
< 8; Index
++) {
786 if (Ip6
->Addr
[Index
] != 0) {
795 Check whether the Ipv6 address1 and address2 are on the connected network.
797 ASSERT if Ip1 or Ip2 is NULL.
798 ASSERT if PrefixLength exceeds or equals to IP6_PREFIX_MAX.
800 @param[in] Ip1 - Ip6 address1, in network order.
801 @param[in] Ip2 - Ip6 address2, in network order.
802 @param[in] PrefixLength - The prefix length of the checking net.
804 @retval TRUE - Yes, connected.
811 EFI_IPv6_ADDRESS
*Ip1
,
812 EFI_IPv6_ADDRESS
*Ip2
,
820 ASSERT ((Ip1
!= NULL
) && (Ip2
!= NULL
) && (PrefixLength
< IP6_PREFIX_MAX
));
822 if (PrefixLength
== 0) {
826 Byte
= (UINT8
)(PrefixLength
/ 8);
827 Bit
= (UINT8
)(PrefixLength
% 8);
829 if (CompareMem (Ip1
, Ip2
, Byte
) != 0) {
834 Mask
= (UINT8
)(0xFF << (8 - Bit
));
841 if ((Ip1
->Addr
[Byte
] & Mask
) != (Ip2
->Addr
[Byte
] & Mask
)) {
850 Switches the endianess of an IPv6 address
852 ASSERT if Ip6 is NULL.
854 This function swaps the bytes in a 128-bit IPv6 address to switch the value
855 from little endian to big endian or vice versa. The byte swapped value is
858 @param Ip6 Points to an IPv6 address
860 @return The byte swapped IPv6 address.
866 EFI_IPv6_ADDRESS
*Ip6
872 ASSERT (Ip6
!= NULL
);
874 CopyMem (&High
, Ip6
, sizeof (UINT64
));
875 CopyMem (&Low
, &Ip6
->Addr
[8], sizeof (UINT64
));
877 High
= SwapBytes64 (High
);
878 Low
= SwapBytes64 (Low
);
880 CopyMem (Ip6
, &Low
, sizeof (UINT64
));
881 CopyMem (&Ip6
->Addr
[8], &High
, sizeof (UINT64
));
887 Initialize a random seed using current time and monotonic count.
889 Get current time and monotonic count first. Then initialize a random seed
890 based on some basic mathematics operation on the hour, day, minute, second,
891 nanosecond and year of the current time and the monotonic count value.
893 @return The random seed initialized with current time.
904 UINT64 MonotonicCount
;
906 gRT
->GetTime (&Time
, NULL
);
907 Seed
= (Time
.Hour
<< 24 | Time
.Day
<< 16 | Time
.Minute
<< 8 | Time
.Second
);
908 Seed
^= Time
.Nanosecond
;
909 Seed
^= Time
.Year
<< 7;
911 gBS
->GetNextMonotonicCount (&MonotonicCount
);
912 Seed
+= (UINT32
)MonotonicCount
;
918 Extract a UINT32 from a byte stream.
920 ASSERT if Buf is NULL.
922 Copy a UINT32 from a byte stream, then converts it from Network
923 byte order to host byte order. Use this function to avoid alignment error.
925 @param[in] Buf The buffer to extract the UINT32.
927 @return The UINT32 extracted.
938 ASSERT (Buf
!= NULL
);
940 CopyMem (&Value
, Buf
, sizeof (UINT32
));
941 return NTOHL (Value
);
945 Put a UINT32 to the byte stream in network byte order.
947 ASSERT if Buf is NULL.
949 Converts a UINT32 from host byte order to network byte order. Then copy it to the
952 @param[in, out] Buf The buffer to put the UINT32.
953 @param[in] Data The data to be converted and put into the byte stream.
963 ASSERT (Buf
!= NULL
);
966 CopyMem (Buf
, &Data
, sizeof (UINT32
));
970 Remove the first node entry on the list, and return the removed node entry.
972 Removes the first node Entry from a doubly linked list. It is up to the caller of
973 this function to release the memory used by the first node if that is required. On
974 exit, the removed node is returned.
976 If Head is NULL, then ASSERT().
977 If Head was not initialized, then ASSERT().
978 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
979 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
982 @param[in, out] Head The list header.
984 @return The first node entry that is removed from the list, NULL if the list is empty.
990 IN OUT LIST_ENTRY
*Head
995 ASSERT (Head
!= NULL
);
997 if (IsListEmpty (Head
)) {
1001 First
= Head
->ForwardLink
;
1002 Head
->ForwardLink
= First
->ForwardLink
;
1003 First
->ForwardLink
->BackLink
= Head
;
1006 First
->ForwardLink
= (LIST_ENTRY
*)NULL
;
1007 First
->BackLink
= (LIST_ENTRY
*)NULL
;
1014 Remove the last node entry on the list and and return the removed node entry.
1016 Removes the last node entry from a doubly linked list. It is up to the caller of
1017 this function to release the memory used by the first node if that is required. On
1018 exit, the removed node is returned.
1020 If Head is NULL, then ASSERT().
1021 If Head was not initialized, then ASSERT().
1022 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
1023 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
1026 @param[in, out] Head The list head.
1028 @return The last node entry that is removed from the list, NULL if the list is empty.
1034 IN OUT LIST_ENTRY
*Head
1039 ASSERT (Head
!= NULL
);
1041 if (IsListEmpty (Head
)) {
1045 Last
= Head
->BackLink
;
1046 Head
->BackLink
= Last
->BackLink
;
1047 Last
->BackLink
->ForwardLink
= Head
;
1050 Last
->ForwardLink
= (LIST_ENTRY
*)NULL
;
1051 Last
->BackLink
= (LIST_ENTRY
*)NULL
;
1058 Insert a new node entry after a designated node entry of a doubly linked list.
1060 ASSERT if PrevEntry or NewEntry is NULL.
1062 Inserts a new node entry donated by NewEntry after the node entry donated by PrevEntry
1063 of the doubly linked list.
1065 @param[in, out] PrevEntry The previous entry to insert after.
1066 @param[in, out] NewEntry The new entry to insert.
1071 NetListInsertAfter (
1072 IN OUT LIST_ENTRY
*PrevEntry
,
1073 IN OUT LIST_ENTRY
*NewEntry
1076 ASSERT (PrevEntry
!= NULL
&& NewEntry
!= NULL
);
1078 NewEntry
->BackLink
= PrevEntry
;
1079 NewEntry
->ForwardLink
= PrevEntry
->ForwardLink
;
1080 PrevEntry
->ForwardLink
->BackLink
= NewEntry
;
1081 PrevEntry
->ForwardLink
= NewEntry
;
1085 Insert a new node entry before a designated node entry of a doubly linked list.
1087 ASSERT if PostEntry or NewEntry is NULL.
1089 Inserts a new node entry donated by NewEntry after the node entry donated by PostEntry
1090 of the doubly linked list.
1092 @param[in, out] PostEntry The entry to insert before.
1093 @param[in, out] NewEntry The new entry to insert.
1098 NetListInsertBefore (
1099 IN OUT LIST_ENTRY
*PostEntry
,
1100 IN OUT LIST_ENTRY
*NewEntry
1103 ASSERT (PostEntry
!= NULL
&& NewEntry
!= NULL
);
1105 NewEntry
->ForwardLink
= PostEntry
;
1106 NewEntry
->BackLink
= PostEntry
->BackLink
;
1107 PostEntry
->BackLink
->ForwardLink
= NewEntry
;
1108 PostEntry
->BackLink
= NewEntry
;
1112 Safe destroy nodes in a linked list, and return the length of the list after all possible operations finished.
1114 Destroy network child instance list by list traversals is not safe due to graph dependencies between nodes.
1115 This function performs a safe traversal to destroy these nodes by checking to see if the node being destroyed
1116 has been removed from the list or not.
1117 If it has been removed, then restart the traversal from the head.
1118 If it hasn't been removed, then continue with the next node directly.
1119 This function will end the iterate and return the CallBack's last return value if error happens,
1120 or return EFI_SUCCESS if 2 complete passes are made with no changes in the number of children in the list.
1122 @param[in] List The head of the list.
1123 @param[in] CallBack Pointer to the callback function to destroy one node in the list.
1124 @param[in] Context Pointer to the callback function's context: corresponds to the
1125 parameter Context in NET_DESTROY_LINK_LIST_CALLBACK.
1126 @param[out] ListLength The length of the link list if the function returns successfully.
1128 @retval EFI_SUCCESS Two complete passes are made with no changes in the number of children.
1129 @retval EFI_INVALID_PARAMETER The input parameter is invalid.
1130 @retval Others Return the CallBack's last return value.
1135 NetDestroyLinkList (
1136 IN LIST_ENTRY
*List
,
1137 IN NET_DESTROY_LINK_LIST_CALLBACK CallBack
,
1138 IN VOID
*Context OPTIONAL
,
1139 OUT UINTN
*ListLength OPTIONAL
1142 UINTN PreviousLength
;
1148 if ((List
== NULL
) || (CallBack
== NULL
)) {
1149 return EFI_INVALID_PARAMETER
;
1154 PreviousLength
= Length
;
1155 Entry
= GetFirstNode (List
);
1156 while (!IsNull (List
, Entry
)) {
1157 Status
= CallBack (Entry
, Context
);
1158 if (EFI_ERROR (Status
)) {
1163 // Walk through the list to see whether the Entry has been removed or not.
1164 // If the Entry still exists, just try to destroy the next one.
1165 // If not, go back to the start point to iterate the list again.
1167 for (Ptr
= List
->ForwardLink
; Ptr
!= List
; Ptr
= Ptr
->ForwardLink
) {
1174 Entry
= GetNextNode (List
, Entry
);
1176 Entry
= GetFirstNode (List
);
1180 for (Length
= 0, Ptr
= List
->ForwardLink
; Ptr
!= List
; Length
++, Ptr
= Ptr
->ForwardLink
) {
1182 } while (Length
!= PreviousLength
);
1184 if (ListLength
!= NULL
) {
1185 *ListLength
= Length
;
1192 This function checks the input Handle to see if it's one of these handles in ChildHandleBuffer.
1194 @param[in] Handle Handle to be checked.
1195 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer.
1196 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
1197 if NumberOfChildren is 0.
1199 @retval TRUE Found the input Handle in ChildHandleBuffer.
1200 @retval FALSE Can't find the input Handle in ChildHandleBuffer.
1205 NetIsInHandleBuffer (
1206 IN EFI_HANDLE Handle
,
1207 IN UINTN NumberOfChildren
,
1208 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
1213 if ((NumberOfChildren
== 0) || (ChildHandleBuffer
== NULL
)) {
1217 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
1218 if (Handle
== ChildHandleBuffer
[Index
]) {
1227 Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.
1229 Initialize the forward and backward links of two head nodes donated by Map->Used
1230 and Map->Recycled of two doubly linked lists.
1231 Initializes the count of the <Key, Value> pairs in the netmap to zero.
1233 If Map is NULL, then ASSERT().
1234 If the address of Map->Used is NULL, then ASSERT().
1235 If the address of Map->Recycled is NULl, then ASSERT().
1237 @param[in, out] Map The netmap to initialize.
1246 ASSERT (Map
!= NULL
);
1248 InitializeListHead (&Map
->Used
);
1249 InitializeListHead (&Map
->Recycled
);
1254 To clean up the netmap, that is, release allocated memories.
1256 Removes all nodes of the Used doubly linked list and free memory of all related netmap items.
1257 Removes all nodes of the Recycled doubly linked list and free memory of all related netmap items.
1258 The number of the <Key, Value> pairs in the netmap is set to be zero.
1260 If Map is NULL, then ASSERT().
1262 @param[in, out] Map The netmap to clean up.
1275 ASSERT (Map
!= NULL
);
1277 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &Map
->Used
) {
1278 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1280 RemoveEntryList (&Item
->Link
);
1283 gBS
->FreePool (Item
);
1286 ASSERT ((Map
->Count
== 0) && IsListEmpty (&Map
->Used
));
1288 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &Map
->Recycled
) {
1289 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1291 RemoveEntryList (&Item
->Link
);
1292 gBS
->FreePool (Item
);
1295 ASSERT (IsListEmpty (&Map
->Recycled
));
1299 Test whether the netmap is empty and return true if it is.
1301 If the number of the <Key, Value> pairs in the netmap is zero, return TRUE.
1303 If Map is NULL, then ASSERT().
1305 @param[in] Map The net map to test.
1307 @return TRUE if the netmap is empty, otherwise FALSE.
1316 ASSERT (Map
!= NULL
);
1317 return (BOOLEAN
)(Map
->Count
== 0);
1321 Return the number of the <Key, Value> pairs in the netmap.
1323 If Map is NULL, then ASSERT().
1325 @param[in] Map The netmap to get the entry number.
1327 @return The entry number in the netmap.
1336 ASSERT (Map
!= NULL
);
1341 Return one allocated item.
1343 If the Recycled doubly linked list of the netmap is empty, it will try to allocate
1344 a batch of items if there are enough resources and add corresponding nodes to the beginning
1345 of the Recycled doubly linked list of the netmap. Otherwise, it will directly remove
1346 the fist node entry of the Recycled doubly linked list and return the corresponding item.
1348 If Map is NULL, then ASSERT().
1350 @param[in, out] Map The netmap to allocate item for.
1352 @return The allocated item. If NULL, the
1353 allocation failed due to resource limit.
1365 ASSERT (Map
!= NULL
);
1367 Head
= &Map
->Recycled
;
1369 if (IsListEmpty (Head
)) {
1370 for (Index
= 0; Index
< NET_MAP_INCREAMENT
; Index
++) {
1371 Item
= AllocatePool (sizeof (NET_MAP_ITEM
));
1381 InsertHeadList (Head
, &Item
->Link
);
1385 Item
= NET_LIST_HEAD (Head
, NET_MAP_ITEM
, Link
);
1386 NetListRemoveHead (Head
);
1392 Allocate an item to save the <Key, Value> pair to the head of the netmap.
1394 Allocate an item to save the <Key, Value> pair and add corresponding node entry
1395 to the beginning of the Used doubly linked list. The number of the <Key, Value>
1396 pairs in the netmap increase by 1.
1398 If Map is NULL, then ASSERT().
1399 If Key is NULL, then ASSERT().
1401 @param[in, out] Map The netmap to insert into.
1402 @param[in] Key The user's key.
1403 @param[in] Value The user's value for the key.
1405 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
1406 @retval EFI_SUCCESS The item is inserted to the head.
1412 IN OUT NET_MAP
*Map
,
1414 IN VOID
*Value OPTIONAL
1419 ASSERT (Map
!= NULL
&& Key
!= NULL
);
1421 Item
= NetMapAllocItem (Map
);
1424 return EFI_OUT_OF_RESOURCES
;
1428 Item
->Value
= Value
;
1429 InsertHeadList (&Map
->Used
, &Item
->Link
);
1436 Allocate an item to save the <Key, Value> pair to the tail of the netmap.
1438 Allocate an item to save the <Key, Value> pair and add corresponding node entry
1439 to the tail of the Used doubly linked list. The number of the <Key, Value>
1440 pairs in the netmap increase by 1.
1442 If Map is NULL, then ASSERT().
1443 If Key is NULL, then ASSERT().
1445 @param[in, out] Map The netmap to insert into.
1446 @param[in] Key The user's key.
1447 @param[in] Value The user's value for the key.
1449 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
1450 @retval EFI_SUCCESS The item is inserted to the tail.
1456 IN OUT NET_MAP
*Map
,
1458 IN VOID
*Value OPTIONAL
1463 ASSERT (Map
!= NULL
&& Key
!= NULL
);
1465 Item
= NetMapAllocItem (Map
);
1468 return EFI_OUT_OF_RESOURCES
;
1472 Item
->Value
= Value
;
1473 InsertTailList (&Map
->Used
, &Item
->Link
);
1481 Check whether the item is in the Map and return TRUE if it is.
1483 If Map is NULL, then ASSERT().
1484 If Item is NULL, then ASSERT().
1486 @param[in] Map The netmap to search within.
1487 @param[in] Item The item to search.
1489 @return TRUE if the item is in the netmap, otherwise FALSE.
1495 IN NET_MAP_ITEM
*Item
1498 LIST_ENTRY
*ListEntry
;
1500 ASSERT (Map
!= NULL
&& Item
!= NULL
);
1502 NET_LIST_FOR_EACH (ListEntry
, &Map
->Used
) {
1503 if (ListEntry
== &Item
->Link
) {
1512 Find the key in the netmap and returns the point to the item contains the Key.
1514 Iterate the Used doubly linked list of the netmap to get every item. Compare the key of every
1515 item with the key to search. It returns the point to the item contains the Key if found.
1517 If Map is NULL, then ASSERT().
1518 If Key is NULL, then ASSERT().
1520 @param[in] Map The netmap to search within.
1521 @param[in] Key The key to search.
1523 @return The point to the item contains the Key, or NULL if Key isn't in the map.
1536 ASSERT (Map
!= NULL
&& Key
!= NULL
);
1538 NET_LIST_FOR_EACH (Entry
, &Map
->Used
) {
1539 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1541 if (Item
->Key
== Key
) {
1550 Remove the node entry of the item from the netmap and return the key of the removed item.
1552 Remove the node entry of the item from the Used doubly linked list of the netmap.
1553 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1554 entry of the item to the Recycled doubly linked list of the netmap. If Value is not NULL,
1555 Value will point to the value of the item. It returns the key of the removed item.
1557 If Map is NULL, then ASSERT().
1558 If Item is NULL, then ASSERT().
1559 if item in not in the netmap, then ASSERT().
1561 @param[in, out] Map The netmap to remove the item from.
1562 @param[in, out] Item The item to remove.
1563 @param[out] Value The variable to receive the value if not NULL.
1565 @return The key of the removed item.
1571 IN OUT NET_MAP
*Map
,
1572 IN OUT NET_MAP_ITEM
*Item
,
1573 OUT VOID
**Value OPTIONAL
1576 ASSERT ((Map
!= NULL
) && (Item
!= NULL
));
1577 ASSERT (NetItemInMap (Map
, Item
));
1579 RemoveEntryList (&Item
->Link
);
1581 InsertHeadList (&Map
->Recycled
, &Item
->Link
);
1583 if (Value
!= NULL
) {
1584 *Value
= Item
->Value
;
1591 Remove the first node entry on the netmap and return the key of the removed item.
1593 Remove the first node entry from the Used doubly linked list of the netmap.
1594 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1595 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
1596 parameter Value will point to the value of the item. It returns the key of the removed item.
1598 If Map is NULL, then ASSERT().
1599 If the Used doubly linked list is empty, then ASSERT().
1601 @param[in, out] Map The netmap to remove the head from.
1602 @param[out] Value The variable to receive the value if not NULL.
1604 @return The key of the item removed.
1610 IN OUT NET_MAP
*Map
,
1611 OUT VOID
**Value OPTIONAL
1617 // Often, it indicates a programming error to remove
1618 // the first entry in an empty list
1620 ASSERT (Map
&& !IsListEmpty (&Map
->Used
));
1622 Item
= NET_LIST_HEAD (&Map
->Used
, NET_MAP_ITEM
, Link
);
1623 RemoveEntryList (&Item
->Link
);
1625 InsertHeadList (&Map
->Recycled
, &Item
->Link
);
1627 if (Value
!= NULL
) {
1628 *Value
= Item
->Value
;
1635 Remove the last node entry on the netmap and return the key of the removed item.
1637 Remove the last node entry from the Used doubly linked list of the netmap.
1638 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1639 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
1640 parameter Value will point to the value of the item. It returns the key of the removed item.
1642 If Map is NULL, then ASSERT().
1643 If the Used doubly linked list is empty, then ASSERT().
1645 @param[in, out] Map The netmap to remove the tail from.
1646 @param[out] Value The variable to receive the value if not NULL.
1648 @return The key of the item removed.
1654 IN OUT NET_MAP
*Map
,
1655 OUT VOID
**Value OPTIONAL
1661 // Often, it indicates a programming error to remove
1662 // the last entry in an empty list
1664 ASSERT (Map
&& !IsListEmpty (&Map
->Used
));
1666 Item
= NET_LIST_TAIL (&Map
->Used
, NET_MAP_ITEM
, Link
);
1667 RemoveEntryList (&Item
->Link
);
1669 InsertHeadList (&Map
->Recycled
, &Item
->Link
);
1671 if (Value
!= NULL
) {
1672 *Value
= Item
->Value
;
1679 Iterate through the netmap and call CallBack for each item.
1681 It will continue the traverse if CallBack returns EFI_SUCCESS, otherwise, break
1682 from the loop. It returns the CallBack's last return value. This function is
1683 delete safe for the current item.
1685 If Map is NULL, then ASSERT().
1686 If CallBack is NULL, then ASSERT().
1688 @param[in] Map The Map to iterate through.
1689 @param[in] CallBack The callback function to call for each item.
1690 @param[in] Arg The opaque parameter to the callback.
1692 @retval EFI_SUCCESS There is no item in the netmap or CallBack for each item
1694 @retval Others It returns the CallBack's last return value.
1701 IN NET_MAP_CALLBACK CallBack
,
1702 IN VOID
*Arg OPTIONAL
1711 ASSERT ((Map
!= NULL
) && (CallBack
!= NULL
));
1715 if (IsListEmpty (Head
)) {
1719 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, Head
) {
1720 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1721 Result
= CallBack (Map
, Item
, Arg
);
1723 if (EFI_ERROR (Result
)) {
1732 This is the default unload handle for all the network drivers.
1734 Disconnect the driver specified by ImageHandle from all the devices in the handle database.
1735 Uninstall all the protocols installed in the driver entry point.
1737 @param[in] ImageHandle The drivers' driver image.
1739 @retval EFI_SUCCESS The image is unloaded.
1740 @retval Others Failed to unload the image.
1745 NetLibDefaultUnload (
1746 IN EFI_HANDLE ImageHandle
1750 EFI_HANDLE
*DeviceHandleBuffer
;
1751 UINTN DeviceHandleCount
;
1754 EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
;
1755 EFI_COMPONENT_NAME_PROTOCOL
*ComponentName
;
1756 EFI_COMPONENT_NAME2_PROTOCOL
*ComponentName2
;
1759 // Get the list of all the handles in the handle database.
1760 // If there is an error getting the list, then the unload
1763 Status
= gBS
->LocateHandleBuffer (
1771 if (EFI_ERROR (Status
)) {
1775 for (Index
= 0; Index
< DeviceHandleCount
; Index
++) {
1776 Status
= gBS
->HandleProtocol (
1777 DeviceHandleBuffer
[Index
],
1778 &gEfiDriverBindingProtocolGuid
,
1779 (VOID
**)&DriverBinding
1781 if (EFI_ERROR (Status
)) {
1785 if (DriverBinding
->ImageHandle
!= ImageHandle
) {
1790 // Disconnect the driver specified by ImageHandle from all
1791 // the devices in the handle database.
1793 for (Index2
= 0; Index2
< DeviceHandleCount
; Index2
++) {
1794 Status
= gBS
->DisconnectController (
1795 DeviceHandleBuffer
[Index2
],
1796 DriverBinding
->DriverBindingHandle
,
1802 // Uninstall all the protocols installed in the driver entry point
1804 gBS
->UninstallProtocolInterface (
1805 DriverBinding
->DriverBindingHandle
,
1806 &gEfiDriverBindingProtocolGuid
,
1810 Status
= gBS
->HandleProtocol (
1811 DeviceHandleBuffer
[Index
],
1812 &gEfiComponentNameProtocolGuid
,
1813 (VOID
**)&ComponentName
1815 if (!EFI_ERROR (Status
)) {
1816 gBS
->UninstallProtocolInterface (
1817 DriverBinding
->DriverBindingHandle
,
1818 &gEfiComponentNameProtocolGuid
,
1823 Status
= gBS
->HandleProtocol (
1824 DeviceHandleBuffer
[Index
],
1825 &gEfiComponentName2ProtocolGuid
,
1826 (VOID
**)&ComponentName2
1828 if (!EFI_ERROR (Status
)) {
1829 gBS
->UninstallProtocolInterface (
1830 DriverBinding
->DriverBindingHandle
,
1831 &gEfiComponentName2ProtocolGuid
,
1838 // Free the buffer containing the list of handles from the handle database
1840 if (DeviceHandleBuffer
!= NULL
) {
1841 gBS
->FreePool (DeviceHandleBuffer
);
1848 Create a child of the service that is identified by ServiceBindingGuid.
1850 Get the ServiceBinding Protocol first, then use it to create a child.
1852 If ServiceBindingGuid is NULL, then ASSERT().
1853 If ChildHandle is NULL, then ASSERT().
1855 @param[in] Controller The controller which has the service installed.
1856 @param[in] Image The image handle used to open service.
1857 @param[in] ServiceBindingGuid The service's Guid.
1858 @param[in, out] ChildHandle The handle to receive the create child.
1860 @retval EFI_SUCCESS The child is successfully created.
1861 @retval Others Failed to create the child.
1866 NetLibCreateServiceChild (
1867 IN EFI_HANDLE Controller
,
1868 IN EFI_HANDLE Image
,
1869 IN EFI_GUID
*ServiceBindingGuid
,
1870 IN OUT EFI_HANDLE
*ChildHandle
1874 EFI_SERVICE_BINDING_PROTOCOL
*Service
;
1876 ASSERT ((ServiceBindingGuid
!= NULL
) && (ChildHandle
!= NULL
));
1879 // Get the ServiceBinding Protocol
1881 Status
= gBS
->OpenProtocol (
1887 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1890 if (EFI_ERROR (Status
)) {
1897 Status
= Service
->CreateChild (Service
, ChildHandle
);
1902 Destroy a child of the service that is identified by ServiceBindingGuid.
1904 Get the ServiceBinding Protocol first, then use it to destroy a child.
1906 If ServiceBindingGuid is NULL, then ASSERT().
1908 @param[in] Controller The controller which has the service installed.
1909 @param[in] Image The image handle used to open service.
1910 @param[in] ServiceBindingGuid The service's Guid.
1911 @param[in] ChildHandle The child to destroy.
1913 @retval EFI_SUCCESS The child is successfully destroyed.
1914 @retval Others Failed to destroy the child.
1919 NetLibDestroyServiceChild (
1920 IN EFI_HANDLE Controller
,
1921 IN EFI_HANDLE Image
,
1922 IN EFI_GUID
*ServiceBindingGuid
,
1923 IN EFI_HANDLE ChildHandle
1927 EFI_SERVICE_BINDING_PROTOCOL
*Service
;
1929 ASSERT (ServiceBindingGuid
!= NULL
);
1932 // Get the ServiceBinding Protocol
1934 Status
= gBS
->OpenProtocol (
1940 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1943 if (EFI_ERROR (Status
)) {
1948 // destroy the child
1950 Status
= Service
->DestroyChild (Service
, ChildHandle
);
1955 Get handle with Simple Network Protocol installed on it.
1957 There should be MNP Service Binding Protocol installed on the input ServiceHandle.
1958 If Simple Network Protocol is already installed on the ServiceHandle, the
1959 ServiceHandle will be returned. If SNP is not installed on the ServiceHandle,
1960 try to find its parent handle with SNP installed.
1962 @param[in] ServiceHandle The handle where network service binding protocols are
1964 @param[out] Snp The pointer to store the address of the SNP instance.
1965 This is an optional parameter that may be NULL.
1967 @return The SNP handle, or NULL if not found.
1972 NetLibGetSnpHandle (
1973 IN EFI_HANDLE ServiceHandle
,
1974 OUT EFI_SIMPLE_NETWORK_PROTOCOL
**Snp OPTIONAL
1978 EFI_SIMPLE_NETWORK_PROTOCOL
*SnpInstance
;
1979 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1980 EFI_HANDLE SnpHandle
;
1983 // Try to open SNP from ServiceHandle
1986 Status
= gBS
->HandleProtocol (ServiceHandle
, &gEfiSimpleNetworkProtocolGuid
, (VOID
**)&SnpInstance
);
1987 if (!EFI_ERROR (Status
)) {
1992 return ServiceHandle
;
1996 // Failed to open SNP, try to get SNP handle by LocateDevicePath()
1998 DevicePath
= DevicePathFromHandle (ServiceHandle
);
1999 if (DevicePath
== NULL
) {
2004 Status
= gBS
->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid
, &DevicePath
, &SnpHandle
);
2005 if (EFI_ERROR (Status
)) {
2007 // Failed to find SNP handle
2012 Status
= gBS
->HandleProtocol (SnpHandle
, &gEfiSimpleNetworkProtocolGuid
, (VOID
**)&SnpInstance
);
2013 if (!EFI_ERROR (Status
)) {
2025 Retrieve VLAN ID of a VLAN device handle.
2027 Search VLAN device path node in Device Path of specified ServiceHandle and
2028 return its VLAN ID. If no VLAN device path node found, then this ServiceHandle
2029 is not a VLAN device handle, and 0 will be returned.
2031 @param[in] ServiceHandle The handle where network service binding protocols are
2034 @return VLAN ID of the device handle, or 0 if not a VLAN device.
2040 IN EFI_HANDLE ServiceHandle
2043 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2044 EFI_DEVICE_PATH_PROTOCOL
*Node
;
2046 DevicePath
= DevicePathFromHandle (ServiceHandle
);
2047 if (DevicePath
== NULL
) {
2052 while (!IsDevicePathEnd (Node
)) {
2053 if ((Node
->Type
== MESSAGING_DEVICE_PATH
) && (Node
->SubType
== MSG_VLAN_DP
)) {
2054 return ((VLAN_DEVICE_PATH
*)Node
)->VlanId
;
2057 Node
= NextDevicePathNode (Node
);
2064 Find VLAN device handle with specified VLAN ID.
2066 The VLAN child device handle is created by VLAN Config Protocol on ControllerHandle.
2067 This function will append VLAN device path node to the parent device path,
2068 and then use LocateDevicePath() to find the correct VLAN device handle.
2070 @param[in] ControllerHandle The handle where network service binding protocols are
2072 @param[in] VlanId The configured VLAN ID for the VLAN device.
2074 @return The VLAN device handle, or NULL if not found.
2079 NetLibGetVlanHandle (
2080 IN EFI_HANDLE ControllerHandle
,
2084 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
2085 EFI_DEVICE_PATH_PROTOCOL
*VlanDevicePath
;
2086 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2087 VLAN_DEVICE_PATH VlanNode
;
2090 ParentDevicePath
= DevicePathFromHandle (ControllerHandle
);
2091 if (ParentDevicePath
== NULL
) {
2096 // Construct VLAN device path
2098 CopyMem (&VlanNode
, &mNetVlanDevicePathTemplate
, sizeof (VLAN_DEVICE_PATH
));
2099 VlanNode
.VlanId
= VlanId
;
2100 VlanDevicePath
= AppendDevicePathNode (
2102 (EFI_DEVICE_PATH_PROTOCOL
*)&VlanNode
2104 if (VlanDevicePath
== NULL
) {
2109 // Find VLAN device handle
2112 DevicePath
= VlanDevicePath
;
2113 gBS
->LocateDevicePath (
2114 &gEfiDevicePathProtocolGuid
,
2118 if (!IsDevicePathEnd (DevicePath
)) {
2120 // Device path is not exactly match
2125 FreePool (VlanDevicePath
);
2130 Get MAC address associated with the network service handle.
2132 If MacAddress is NULL, then ASSERT().
2133 If AddressSize is NULL, then ASSERT().
2135 There should be MNP Service Binding Protocol installed on the input ServiceHandle.
2136 If SNP is installed on the ServiceHandle or its parent handle, MAC address will
2137 be retrieved from SNP. If no SNP found, try to get SNP mode data use MNP.
2139 @param[in] ServiceHandle The handle where network service binding protocols are
2141 @param[out] MacAddress The pointer to store the returned MAC address.
2142 @param[out] AddressSize The length of returned MAC address.
2144 @retval EFI_SUCCESS MAC address is returned successfully.
2145 @retval Others Failed to get SNP mode data.
2150 NetLibGetMacAddress (
2151 IN EFI_HANDLE ServiceHandle
,
2152 OUT EFI_MAC_ADDRESS
*MacAddress
,
2153 OUT UINTN
*AddressSize
2157 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2158 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
2159 EFI_SIMPLE_NETWORK_MODE SnpModeData
;
2160 EFI_MANAGED_NETWORK_PROTOCOL
*Mnp
;
2161 EFI_SERVICE_BINDING_PROTOCOL
*MnpSb
;
2162 EFI_HANDLE SnpHandle
;
2163 EFI_HANDLE MnpChildHandle
;
2165 ASSERT (MacAddress
!= NULL
);
2166 ASSERT (AddressSize
!= NULL
);
2169 // Try to get SNP handle
2172 SnpHandle
= NetLibGetSnpHandle (ServiceHandle
, &Snp
);
2173 if (SnpHandle
!= NULL
) {
2175 // SNP found, use it directly
2177 SnpMode
= Snp
->Mode
;
2180 // Failed to get SNP handle, try to get MAC address from MNP
2182 MnpChildHandle
= NULL
;
2183 Status
= gBS
->HandleProtocol (
2185 &gEfiManagedNetworkServiceBindingProtocolGuid
,
2188 if (EFI_ERROR (Status
)) {
2193 // Create a MNP child
2195 Status
= MnpSb
->CreateChild (MnpSb
, &MnpChildHandle
);
2196 if (EFI_ERROR (Status
)) {
2201 // Open MNP protocol
2203 Status
= gBS
->HandleProtocol (
2205 &gEfiManagedNetworkProtocolGuid
,
2208 if (EFI_ERROR (Status
)) {
2209 MnpSb
->DestroyChild (MnpSb
, MnpChildHandle
);
2214 // Try to get SNP mode from MNP
2216 Status
= Mnp
->GetModeData (Mnp
, NULL
, &SnpModeData
);
2217 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_STARTED
)) {
2218 MnpSb
->DestroyChild (MnpSb
, MnpChildHandle
);
2222 SnpMode
= &SnpModeData
;
2225 // Destroy the MNP child
2227 MnpSb
->DestroyChild (MnpSb
, MnpChildHandle
);
2230 *AddressSize
= SnpMode
->HwAddressSize
;
2231 CopyMem (MacAddress
->Addr
, SnpMode
->CurrentAddress
.Addr
, SnpMode
->HwAddressSize
);
2237 Convert MAC address of the NIC associated with specified Service Binding Handle
2238 to a unicode string. Callers are responsible for freeing the string storage.
2240 If MacString is NULL, then ASSERT().
2242 Locate simple network protocol associated with the Service Binding Handle and
2243 get the mac address from SNP. Then convert the mac address into a unicode
2244 string. It takes 2 unicode characters to represent a 1 byte binary buffer.
2245 Plus one unicode character for the null-terminator.
2247 @param[in] ServiceHandle The handle where network service binding protocol is
2249 @param[in] ImageHandle The image handle used to act as the agent handle to
2250 get the simple network protocol. This parameter is
2251 optional and may be NULL.
2252 @param[out] MacString The pointer to store the address of the string
2253 representation of the mac address.
2255 @retval EFI_SUCCESS Convert the mac address a unicode string successfully.
2256 @retval EFI_OUT_OF_RESOURCES There are not enough memory resource.
2257 @retval Others Failed to open the simple network protocol.
2262 NetLibGetMacString (
2263 IN EFI_HANDLE ServiceHandle
,
2264 IN EFI_HANDLE ImageHandle OPTIONAL
,
2265 OUT CHAR16
**MacString
2269 EFI_MAC_ADDRESS MacAddress
;
2271 UINTN HwAddressSize
;
2277 ASSERT (MacString
!= NULL
);
2280 // Get MAC address of the network device
2282 Status
= NetLibGetMacAddress (ServiceHandle
, &MacAddress
, &HwAddressSize
);
2283 if (EFI_ERROR (Status
)) {
2288 // It takes 2 unicode characters to represent a 1 byte binary buffer.
2289 // If VLAN is configured, it will need extra 5 characters like "\0005".
2290 // Plus one unicode character for the null-terminator.
2292 BufferSize
= (2 * HwAddressSize
+ 5 + 1) * sizeof (CHAR16
);
2293 String
= AllocateZeroPool (BufferSize
);
2294 if (String
== NULL
) {
2295 return EFI_OUT_OF_RESOURCES
;
2298 *MacString
= String
;
2301 // Convert the MAC address into a unicode string.
2303 HwAddress
= &MacAddress
.Addr
[0];
2304 for (Index
= 0; Index
< HwAddressSize
; Index
++) {
2305 UnicodeValueToStringS (
2307 BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
),
2308 PREFIX_ZERO
| RADIX_HEX
,
2312 String
+= StrnLenS (String
, (BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
)) / sizeof (CHAR16
));
2316 // Append VLAN ID if any
2318 VlanId
= NetLibGetVlanId (ServiceHandle
);
2321 UnicodeValueToStringS (
2323 BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
),
2324 PREFIX_ZERO
| RADIX_HEX
,
2328 String
+= StrnLenS (String
, (BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
)) / sizeof (CHAR16
));
2332 // Null terminate the Unicode string
2340 Detect media status for specified network device.
2342 If MediaPresent is NULL, then ASSERT().
2344 The underlying UNDI driver may or may not support reporting media status from
2345 GET_STATUS command (PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED). This routine
2346 will try to invoke Snp->GetStatus() to get the media status: if media already
2347 present, it return directly; if media not present, it will stop SNP and then
2348 restart SNP to get the latest media status, this give chance to get the correct
2349 media status for old UNDI driver which doesn't support reporting media status
2350 from GET_STATUS command.
2351 Note: there will be two limitations for current algorithm:
2352 1) for UNDI with this capability, in case of cable is not attached, there will
2353 be an redundant Stop/Start() process;
2354 2) for UNDI without this capability, in case that network cable is attached when
2355 Snp->Initialize() is invoked while network cable is unattached later,
2356 NetLibDetectMedia() will report MediaPresent as TRUE, causing upper layer
2357 apps to wait for timeout time.
2359 @param[in] ServiceHandle The handle where network service binding protocols are
2361 @param[out] MediaPresent The pointer to store the media status.
2363 @retval EFI_SUCCESS Media detection success.
2364 @retval EFI_INVALID_PARAMETER ServiceHandle is not valid network device handle.
2365 @retval EFI_UNSUPPORTED Network device does not support media detection.
2366 @retval EFI_DEVICE_ERROR SNP is in unknown state.
2372 IN EFI_HANDLE ServiceHandle
,
2373 OUT BOOLEAN
*MediaPresent
2377 EFI_HANDLE SnpHandle
;
2378 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2379 UINT32 InterruptStatus
;
2381 EFI_MAC_ADDRESS
*MCastFilter
;
2382 UINT32 MCastFilterCount
;
2383 UINT32 EnableFilterBits
;
2384 UINT32 DisableFilterBits
;
2385 BOOLEAN ResetMCastFilters
;
2387 ASSERT (MediaPresent
!= NULL
);
2393 SnpHandle
= NetLibGetSnpHandle (ServiceHandle
, &Snp
);
2394 if (SnpHandle
== NULL
) {
2395 return EFI_INVALID_PARAMETER
;
2399 // Check whether SNP support media detection
2401 if (!Snp
->Mode
->MediaPresentSupported
) {
2402 return EFI_UNSUPPORTED
;
2406 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
2408 Status
= Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
2409 if (EFI_ERROR (Status
)) {
2413 if (Snp
->Mode
->MediaPresent
) {
2415 // Media is present, return directly
2417 *MediaPresent
= TRUE
;
2422 // Till now, GetStatus() report no media; while, in case UNDI not support
2423 // reporting media status from GetStatus(), this media status may be incorrect.
2424 // So, we will stop SNP and then restart it to get the correct media status.
2426 OldState
= Snp
->Mode
->State
;
2427 if (OldState
>= EfiSimpleNetworkMaxState
) {
2428 return EFI_DEVICE_ERROR
;
2433 if (OldState
== EfiSimpleNetworkInitialized
) {
2435 // SNP is already in use, need Shutdown/Stop and then Start/Initialize
2439 // Backup current SNP receive filter settings
2441 EnableFilterBits
= Snp
->Mode
->ReceiveFilterSetting
;
2442 DisableFilterBits
= Snp
->Mode
->ReceiveFilterMask
^ EnableFilterBits
;
2444 ResetMCastFilters
= TRUE
;
2445 MCastFilterCount
= Snp
->Mode
->MCastFilterCount
;
2446 if (MCastFilterCount
!= 0) {
2447 MCastFilter
= AllocateCopyPool (
2448 MCastFilterCount
* sizeof (EFI_MAC_ADDRESS
),
2449 Snp
->Mode
->MCastFilter
2451 ASSERT (MCastFilter
!= NULL
);
2452 if (MCastFilter
== NULL
) {
2453 Status
= EFI_OUT_OF_RESOURCES
;
2457 ResetMCastFilters
= FALSE
;
2461 // Shutdown/Stop the simple network
2463 Status
= Snp
->Shutdown (Snp
);
2464 if (!EFI_ERROR (Status
)) {
2465 Status
= Snp
->Stop (Snp
);
2468 if (EFI_ERROR (Status
)) {
2473 // Start/Initialize the simple network
2475 Status
= Snp
->Start (Snp
);
2476 if (!EFI_ERROR (Status
)) {
2477 Status
= Snp
->Initialize (Snp
, 0, 0);
2480 if (EFI_ERROR (Status
)) {
2485 // Here we get the correct media status
2487 *MediaPresent
= Snp
->Mode
->MediaPresent
;
2490 // Restore SNP receive filter settings
2492 Status
= Snp
->ReceiveFilters (
2501 if (MCastFilter
!= NULL
) {
2502 FreePool (MCastFilter
);
2509 // SNP is not in use, it's in state of EfiSimpleNetworkStopped or EfiSimpleNetworkStarted
2511 if (OldState
== EfiSimpleNetworkStopped
) {
2513 // SNP not start yet, start it
2515 Status
= Snp
->Start (Snp
);
2516 if (EFI_ERROR (Status
)) {
2522 // Initialize the simple network
2524 Status
= Snp
->Initialize (Snp
, 0, 0);
2525 if (EFI_ERROR (Status
)) {
2526 Status
= EFI_DEVICE_ERROR
;
2531 // Here we get the correct media status
2533 *MediaPresent
= Snp
->Mode
->MediaPresent
;
2536 // Shut down the simple network
2538 Snp
->Shutdown (Snp
);
2541 if (OldState
== EfiSimpleNetworkStopped
) {
2543 // Original SNP sate is Stopped, restore to original state
2548 if (MCastFilter
!= NULL
) {
2549 FreePool (MCastFilter
);
2557 Detect media state for a network device. This routine will wait for a period of time at
2558 a specified checking interval when a certain network is under connecting until connection
2559 process finishs or timeout. If Aip protocol is supported by low layer drivers, three kinds
2560 of media states can be detected: EFI_SUCCESS, EFI_NOT_READY and EFI_NO_MEDIA, represents
2561 connected state, connecting state and no media state respectively. When function detects
2562 the current state is EFI_NOT_READY, it will loop to wait for next time's check until state
2563 turns to be EFI_SUCCESS or EFI_NO_MEDIA. If Aip protocol is not supported, function will
2564 call NetLibDetectMedia() and return state directly.
2566 @param[in] ServiceHandle The handle where network service binding protocols are
2568 @param[in] Timeout The maximum number of 100ns units to wait when network
2569 is connecting. Zero value means detect once and return
2571 @param[out] MediaState The pointer to the detected media state.
2573 @retval EFI_SUCCESS Media detection success.
2574 @retval EFI_INVALID_PARAMETER ServiceHandle is not a valid network device handle or
2575 MediaState pointer is NULL.
2576 @retval EFI_DEVICE_ERROR A device error occurred.
2577 @retval EFI_TIMEOUT Network is connecting but timeout.
2582 NetLibDetectMediaWaitTimeout (
2583 IN EFI_HANDLE ServiceHandle
,
2585 OUT EFI_STATUS
*MediaState
2589 EFI_HANDLE SnpHandle
;
2590 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2591 EFI_ADAPTER_INFORMATION_PROTOCOL
*Aip
;
2592 EFI_ADAPTER_INFO_MEDIA_STATE
*MediaInfo
;
2593 BOOLEAN MediaPresent
;
2595 EFI_STATUS TimerStatus
;
2597 UINT64 TimeRemained
;
2599 if (MediaState
== NULL
) {
2600 return EFI_INVALID_PARAMETER
;
2603 *MediaState
= EFI_SUCCESS
;
2610 SnpHandle
= NetLibGetSnpHandle (ServiceHandle
, &Snp
);
2611 if (SnpHandle
== NULL
) {
2612 return EFI_INVALID_PARAMETER
;
2615 Status
= gBS
->HandleProtocol (
2617 &gEfiAdapterInformationProtocolGuid
,
2620 if (EFI_ERROR (Status
)) {
2621 MediaPresent
= TRUE
;
2622 Status
= NetLibDetectMedia (ServiceHandle
, &MediaPresent
);
2623 if (!EFI_ERROR (Status
)) {
2625 *MediaState
= EFI_SUCCESS
;
2627 *MediaState
= EFI_NO_MEDIA
;
2632 // NetLibDetectMedia doesn't support EFI_NOT_READY status, return now!
2637 Status
= Aip
->GetInformation (
2639 &gEfiAdapterInfoMediaStateGuid
,
2640 (VOID
**)&MediaInfo
,
2643 if (!EFI_ERROR (Status
)) {
2644 *MediaState
= MediaInfo
->MediaState
;
2645 FreePool (MediaInfo
);
2646 if ((*MediaState
!= EFI_NOT_READY
) || (Timeout
< MEDIA_STATE_DETECT_TIME_INTERVAL
)) {
2650 if (MediaInfo
!= NULL
) {
2651 FreePool (MediaInfo
);
2654 if (Status
== EFI_UNSUPPORTED
) {
2656 // If gEfiAdapterInfoMediaStateGuid is not supported, call NetLibDetectMedia to get media state!
2658 MediaPresent
= TRUE
;
2659 Status
= NetLibDetectMedia (ServiceHandle
, &MediaPresent
);
2660 if (!EFI_ERROR (Status
)) {
2662 *MediaState
= EFI_SUCCESS
;
2664 *MediaState
= EFI_NO_MEDIA
;
2675 // Loop to check media state
2679 TimeRemained
= Timeout
;
2680 Status
= gBS
->CreateEvent (EVT_TIMER
, TPL_CALLBACK
, NULL
, NULL
, &Timer
);
2681 if (EFI_ERROR (Status
)) {
2682 return EFI_DEVICE_ERROR
;
2686 Status
= gBS
->SetTimer (
2689 MEDIA_STATE_DETECT_TIME_INTERVAL
2691 if (EFI_ERROR (Status
)) {
2692 gBS
->CloseEvent (Timer
);
2693 return EFI_DEVICE_ERROR
;
2697 TimerStatus
= gBS
->CheckEvent (Timer
);
2698 if (!EFI_ERROR (TimerStatus
)) {
2699 TimeRemained
-= MEDIA_STATE_DETECT_TIME_INTERVAL
;
2700 Status
= Aip
->GetInformation (
2702 &gEfiAdapterInfoMediaStateGuid
,
2703 (VOID
**)&MediaInfo
,
2706 if (!EFI_ERROR (Status
)) {
2707 *MediaState
= MediaInfo
->MediaState
;
2708 FreePool (MediaInfo
);
2710 if (MediaInfo
!= NULL
) {
2711 FreePool (MediaInfo
);
2714 gBS
->CloseEvent (Timer
);
2718 } while (TimerStatus
== EFI_NOT_READY
);
2719 } while (*MediaState
== EFI_NOT_READY
&& TimeRemained
>= MEDIA_STATE_DETECT_TIME_INTERVAL
);
2721 gBS
->CloseEvent (Timer
);
2722 if ((*MediaState
== EFI_NOT_READY
) && (TimeRemained
< MEDIA_STATE_DETECT_TIME_INTERVAL
)) {
2730 Check the default address used by the IPv4 driver is static or dynamic (acquired
2733 If the controller handle does not have the EFI_IP4_CONFIG2_PROTOCOL installed, the
2734 default address is static. If failed to get the policy from Ip4 Config2 Protocol,
2735 the default address is static. Otherwise, get the result from Ip4 Config2 Protocol.
2737 @param[in] Controller The controller handle which has the EFI_IP4_CONFIG2_PROTOCOL
2738 relative with the default address to judge.
2740 @retval TRUE If the default address is static.
2741 @retval FALSE If the default address is acquired from DHCP.
2745 NetLibDefaultAddressIsStatic (
2746 IN EFI_HANDLE Controller
2750 EFI_IP4_CONFIG2_PROTOCOL
*Ip4Config2
;
2752 EFI_IP4_CONFIG2_POLICY Policy
;
2757 DataSize
= sizeof (EFI_IP4_CONFIG2_POLICY
);
2762 // Get Ip4Config2 policy.
2764 Status
= gBS
->HandleProtocol (Controller
, &gEfiIp4Config2ProtocolGuid
, (VOID
**)&Ip4Config2
);
2765 if (EFI_ERROR (Status
)) {
2769 Status
= Ip4Config2
->GetData (Ip4Config2
, Ip4Config2DataTypePolicy
, &DataSize
, &Policy
);
2770 if (EFI_ERROR (Status
)) {
2774 IsStatic
= (BOOLEAN
)(Policy
== Ip4Config2PolicyStatic
);
2782 Create an IPv4 device path node.
2784 If Node is NULL, then ASSERT().
2786 The header type of IPv4 device path node is MESSAGING_DEVICE_PATH.
2787 The header subtype of IPv4 device path node is MSG_IPv4_DP.
2788 Get other info from parameters to make up the whole IPv4 device path node.
2790 @param[in, out] Node Pointer to the IPv4 device path node.
2791 @param[in] Controller The controller handle.
2792 @param[in] LocalIp The local IPv4 address.
2793 @param[in] LocalPort The local port.
2794 @param[in] RemoteIp The remote IPv4 address.
2795 @param[in] RemotePort The remote port.
2796 @param[in] Protocol The protocol type in the IP header.
2797 @param[in] UseDefaultAddress Whether this instance is using default address or not.
2802 NetLibCreateIPv4DPathNode (
2803 IN OUT IPv4_DEVICE_PATH
*Node
,
2804 IN EFI_HANDLE Controller
,
2805 IN IP4_ADDR LocalIp
,
2806 IN UINT16 LocalPort
,
2807 IN IP4_ADDR RemoteIp
,
2808 IN UINT16 RemotePort
,
2810 IN BOOLEAN UseDefaultAddress
2813 ASSERT (Node
!= NULL
);
2815 Node
->Header
.Type
= MESSAGING_DEVICE_PATH
;
2816 Node
->Header
.SubType
= MSG_IPv4_DP
;
2817 SetDevicePathNodeLength (&Node
->Header
, sizeof (IPv4_DEVICE_PATH
));
2819 CopyMem (&Node
->LocalIpAddress
, &LocalIp
, sizeof (EFI_IPv4_ADDRESS
));
2820 CopyMem (&Node
->RemoteIpAddress
, &RemoteIp
, sizeof (EFI_IPv4_ADDRESS
));
2822 Node
->LocalPort
= LocalPort
;
2823 Node
->RemotePort
= RemotePort
;
2825 Node
->Protocol
= Protocol
;
2827 if (!UseDefaultAddress
) {
2828 Node
->StaticIpAddress
= TRUE
;
2830 Node
->StaticIpAddress
= NetLibDefaultAddressIsStatic (Controller
);
2834 // Set the Gateway IP address to default value 0:0:0:0.
2835 // Set the Subnet mask to default value 255:255:255:0.
2837 ZeroMem (&Node
->GatewayIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
2838 SetMem (&Node
->SubnetMask
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
2839 Node
->SubnetMask
.Addr
[3] = 0;
2843 Create an IPv6 device path node.
2845 If Node is NULL, then ASSERT().
2846 If LocalIp is NULL, then ASSERT().
2847 If RemoteIp is NULL, then ASSERT().
2849 The header type of IPv6 device path node is MESSAGING_DEVICE_PATH.
2850 The header subtype of IPv6 device path node is MSG_IPv6_DP.
2851 Get other info from parameters to make up the whole IPv6 device path node.
2853 @param[in, out] Node Pointer to the IPv6 device path node.
2854 @param[in] Controller The controller handle.
2855 @param[in] LocalIp The local IPv6 address.
2856 @param[in] LocalPort The local port.
2857 @param[in] RemoteIp The remote IPv6 address.
2858 @param[in] RemotePort The remote port.
2859 @param[in] Protocol The protocol type in the IP header.
2864 NetLibCreateIPv6DPathNode (
2865 IN OUT IPv6_DEVICE_PATH
*Node
,
2866 IN EFI_HANDLE Controller
,
2867 IN EFI_IPv6_ADDRESS
*LocalIp
,
2868 IN UINT16 LocalPort
,
2869 IN EFI_IPv6_ADDRESS
*RemoteIp
,
2870 IN UINT16 RemotePort
,
2874 ASSERT (Node
!= NULL
&& LocalIp
!= NULL
&& RemoteIp
!= NULL
);
2876 Node
->Header
.Type
= MESSAGING_DEVICE_PATH
;
2877 Node
->Header
.SubType
= MSG_IPv6_DP
;
2878 SetDevicePathNodeLength (&Node
->Header
, sizeof (IPv6_DEVICE_PATH
));
2880 CopyMem (&Node
->LocalIpAddress
, LocalIp
, sizeof (EFI_IPv6_ADDRESS
));
2881 CopyMem (&Node
->RemoteIpAddress
, RemoteIp
, sizeof (EFI_IPv6_ADDRESS
));
2883 Node
->LocalPort
= LocalPort
;
2884 Node
->RemotePort
= RemotePort
;
2886 Node
->Protocol
= Protocol
;
2889 // Set default value to IPAddressOrigin, PrefixLength.
2890 // Set the Gateway IP address to unspecified address.
2892 Node
->IpAddressOrigin
= 0;
2893 Node
->PrefixLength
= IP6_PREFIX_LENGTH
;
2894 ZeroMem (&Node
->GatewayIpAddress
, sizeof (EFI_IPv6_ADDRESS
));
2898 Find the UNDI/SNP handle from controller and protocol GUID.
2900 If ProtocolGuid is NULL, then ASSERT().
2902 For example, IP will open a MNP child to transmit/receive
2903 packets, when MNP is stopped, IP should also be stopped. IP
2904 needs to find its own private data which is related the IP's
2905 service binding instance that is install on UNDI/SNP handle.
2906 Now, the controller is either a MNP or ARP child handle. But
2907 IP opens these handle BY_DRIVER, use that info, we can get the
2910 @param[in] Controller Then protocol handle to check.
2911 @param[in] ProtocolGuid The protocol that is related with the handle.
2913 @return The UNDI/SNP handle or NULL for errors.
2918 NetLibGetNicHandle (
2919 IN EFI_HANDLE Controller
,
2920 IN EFI_GUID
*ProtocolGuid
2923 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenBuffer
;
2929 ASSERT (ProtocolGuid
!= NULL
);
2931 Status
= gBS
->OpenProtocolInformation (
2938 if (EFI_ERROR (Status
)) {
2944 for (Index
= 0; Index
< OpenCount
; Index
++) {
2945 if ((OpenBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_DRIVER
) != 0) {
2946 Handle
= OpenBuffer
[Index
].ControllerHandle
;
2951 gBS
->FreePool (OpenBuffer
);
2956 Convert one Null-terminated ASCII string (decimal dotted) to EFI_IPv4_ADDRESS.
2958 @param[in] String The pointer to the Ascii string.
2959 @param[out] Ip4Address The pointer to the converted IPv4 address.
2961 @retval EFI_SUCCESS Convert to IPv4 address successfully.
2962 @retval EFI_INVALID_PARAMETER The string is malformatted or Ip4Address is NULL.
2967 NetLibAsciiStrToIp4 (
2968 IN CONST CHAR8
*String
,
2969 OUT EFI_IPv4_ADDRESS
*Ip4Address
2972 RETURN_STATUS Status
;
2975 Status
= AsciiStrToIpv4Address (String
, &EndPointer
, Ip4Address
, NULL
);
2976 if (RETURN_ERROR (Status
) || (*EndPointer
!= '\0')) {
2977 return EFI_INVALID_PARAMETER
;
2984 Convert one Null-terminated ASCII string to EFI_IPv6_ADDRESS. The format of the
2985 string is defined in RFC 4291 - Text Representation of Addresses.
2987 @param[in] String The pointer to the Ascii string.
2988 @param[out] Ip6Address The pointer to the converted IPv6 address.
2990 @retval EFI_SUCCESS Convert to IPv6 address successfully.
2991 @retval EFI_INVALID_PARAMETER The string is malformatted or Ip6Address is NULL.
2996 NetLibAsciiStrToIp6 (
2997 IN CONST CHAR8
*String
,
2998 OUT EFI_IPv6_ADDRESS
*Ip6Address
3001 RETURN_STATUS Status
;
3004 Status
= AsciiStrToIpv6Address (String
, &EndPointer
, Ip6Address
, NULL
);
3005 if (RETURN_ERROR (Status
) || (*EndPointer
!= '\0')) {
3006 return EFI_INVALID_PARAMETER
;
3013 Convert one Null-terminated Unicode string (decimal dotted) to EFI_IPv4_ADDRESS.
3015 @param[in] String The pointer to the Ascii string.
3016 @param[out] Ip4Address The pointer to the converted IPv4 address.
3018 @retval EFI_SUCCESS Convert to IPv4 address successfully.
3019 @retval EFI_INVALID_PARAMETER The string is malformatted or Ip4Address is NULL.
3025 IN CONST CHAR16
*String
,
3026 OUT EFI_IPv4_ADDRESS
*Ip4Address
3029 RETURN_STATUS Status
;
3032 Status
= StrToIpv4Address (String
, &EndPointer
, Ip4Address
, NULL
);
3033 if (RETURN_ERROR (Status
) || (*EndPointer
!= L
'\0')) {
3034 return EFI_INVALID_PARAMETER
;
3041 Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS. The format of
3042 the string is defined in RFC 4291 - Text Representation of Addresses.
3044 @param[in] String The pointer to the Ascii string.
3045 @param[out] Ip6Address The pointer to the converted IPv6 address.
3047 @retval EFI_SUCCESS Convert to IPv6 address successfully.
3048 @retval EFI_INVALID_PARAMETER The string is malformatted or Ip6Address is NULL.
3054 IN CONST CHAR16
*String
,
3055 OUT EFI_IPv6_ADDRESS
*Ip6Address
3058 RETURN_STATUS Status
;
3061 Status
= StrToIpv6Address (String
, &EndPointer
, Ip6Address
, NULL
);
3062 if (RETURN_ERROR (Status
) || (*EndPointer
!= L
'\0')) {
3063 return EFI_INVALID_PARAMETER
;
3070 Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS and prefix length.
3071 The format of the string is defined in RFC 4291 - Text Representation of Addresses
3072 Prefixes: ipv6-address/prefix-length.
3074 @param[in] String The pointer to the Ascii string.
3075 @param[out] Ip6Address The pointer to the converted IPv6 address.
3076 @param[out] PrefixLength The pointer to the converted prefix length.
3078 @retval EFI_SUCCESS Convert to IPv6 address successfully.
3079 @retval EFI_INVALID_PARAMETER The string is malformatted or Ip6Address is NULL.
3084 NetLibStrToIp6andPrefix (
3085 IN CONST CHAR16
*String
,
3086 OUT EFI_IPv6_ADDRESS
*Ip6Address
,
3087 OUT UINT8
*PrefixLength
3090 RETURN_STATUS Status
;
3093 Status
= StrToIpv6Address (String
, &EndPointer
, Ip6Address
, PrefixLength
);
3094 if (RETURN_ERROR (Status
) || (*EndPointer
!= L
'\0')) {
3095 return EFI_INVALID_PARAMETER
;
3103 Convert one EFI_IPv6_ADDRESS to Null-terminated Unicode string.
3104 The text representation of address is defined in RFC 4291.
3106 @param[in] Ip6Address The pointer to the IPv6 address.
3107 @param[out] String The buffer to return the converted string.
3108 @param[in] StringSize The length in bytes of the input String.
3110 @retval EFI_SUCCESS Convert to string successfully.
3111 @retval EFI_INVALID_PARAMETER The input parameter is invalid.
3112 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. BufferSize has been
3113 updated with the size needed to complete the request.
3118 IN EFI_IPv6_ADDRESS
*Ip6Address
,
3125 UINTN LongestZerosStart
;
3126 UINTN LongestZerosLength
;
3127 UINTN CurrentZerosStart
;
3128 UINTN CurrentZerosLength
;
3129 CHAR16 Buffer
[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
3132 if ((Ip6Address
== NULL
) || (String
== NULL
) || (StringSize
== 0)) {
3133 return EFI_INVALID_PARAMETER
;
3137 // Convert the UINT8 array to an UINT16 array for easy handling.
3139 ZeroMem (Ip6Addr
, sizeof (Ip6Addr
));
3140 for (Index
= 0; Index
< 16; Index
++) {
3141 Ip6Addr
[Index
/ 2] |= (Ip6Address
->Addr
[Index
] << ((1 - (Index
% 2)) << 3));
3145 // Find the longest zeros and mark it.
3147 CurrentZerosStart
= DEFAULT_ZERO_START
;
3148 CurrentZerosLength
= 0;
3149 LongestZerosStart
= DEFAULT_ZERO_START
;
3150 LongestZerosLength
= 0;
3151 for (Index
= 0; Index
< 8; Index
++) {
3152 if (Ip6Addr
[Index
] == 0) {
3153 if (CurrentZerosStart
== DEFAULT_ZERO_START
) {
3154 CurrentZerosStart
= Index
;
3155 CurrentZerosLength
= 1;
3157 CurrentZerosLength
++;
3160 if (CurrentZerosStart
!= DEFAULT_ZERO_START
) {
3161 if ((CurrentZerosLength
> 2) && ((LongestZerosStart
== (DEFAULT_ZERO_START
)) || (CurrentZerosLength
> LongestZerosLength
))) {
3162 LongestZerosStart
= CurrentZerosStart
;
3163 LongestZerosLength
= CurrentZerosLength
;
3166 CurrentZerosStart
= DEFAULT_ZERO_START
;
3167 CurrentZerosLength
= 0;
3172 if ((CurrentZerosStart
!= DEFAULT_ZERO_START
) && (CurrentZerosLength
> 2)) {
3173 if ((LongestZerosStart
== DEFAULT_ZERO_START
) || (LongestZerosLength
< CurrentZerosLength
)) {
3174 LongestZerosStart
= CurrentZerosStart
;
3175 LongestZerosLength
= CurrentZerosLength
;
3180 for (Index
= 0; Index
< 8; Index
++) {
3181 if ((LongestZerosStart
!= DEFAULT_ZERO_START
) && (Index
>= LongestZerosStart
) && (Index
< LongestZerosStart
+ LongestZerosLength
)) {
3182 if (Index
== LongestZerosStart
) {
3193 Ptr
+= UnicodeSPrint (Ptr
, 10, L
"%x", Ip6Addr
[Index
]);
3196 if ((LongestZerosStart
!= DEFAULT_ZERO_START
) && (LongestZerosStart
+ LongestZerosLength
== 8)) {
3202 if ((UINTN
)Ptr
- (UINTN
)Buffer
> StringSize
) {
3203 return EFI_BUFFER_TOO_SMALL
;
3206 StrCpyS (String
, StringSize
/ sizeof (CHAR16
), Buffer
);
3212 This function obtains the system guid from the smbios table.
3214 If SystemGuid is NULL, then ASSERT().
3216 @param[out] SystemGuid The pointer of the returned system guid.
3218 @retval EFI_SUCCESS Successfully obtained the system guid.
3219 @retval EFI_NOT_FOUND Did not find the SMBIOS table.
3224 NetLibGetSystemGuid (
3225 OUT EFI_GUID
*SystemGuid
3229 SMBIOS_TABLE_ENTRY_POINT
*SmbiosTable
;
3230 SMBIOS_TABLE_3_0_ENTRY_POINT
*Smbios30Table
;
3231 SMBIOS_STRUCTURE_POINTER Smbios
;
3232 SMBIOS_STRUCTURE_POINTER SmbiosEnd
;
3235 ASSERT (SystemGuid
!= NULL
);
3238 Status
= EfiGetSystemConfigurationTable (&gEfiSmbios3TableGuid
, (VOID
**)&Smbios30Table
);
3239 if (!(EFI_ERROR (Status
) || (Smbios30Table
== NULL
))) {
3240 Smbios
.Hdr
= (SMBIOS_STRUCTURE
*)(UINTN
)Smbios30Table
->TableAddress
;
3241 SmbiosEnd
.Raw
= (UINT8
*)(UINTN
)(Smbios30Table
->TableAddress
+ Smbios30Table
->TableMaximumSize
);
3243 Status
= EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid
, (VOID
**)&SmbiosTable
);
3244 if (EFI_ERROR (Status
) || (SmbiosTable
== NULL
)) {
3245 return EFI_NOT_FOUND
;
3248 Smbios
.Hdr
= (SMBIOS_STRUCTURE
*)(UINTN
)SmbiosTable
->TableAddress
;
3249 SmbiosEnd
.Raw
= (UINT8
*)((UINTN
)SmbiosTable
->TableAddress
+ SmbiosTable
->TableLength
);
3253 if (Smbios
.Hdr
->Type
== 1) {
3254 if (Smbios
.Hdr
->Length
< 0x19) {
3256 // Older version did not support UUID.
3258 return EFI_NOT_FOUND
;
3262 // SMBIOS tables are byte packed so we need to do a byte copy to
3263 // prevend alignment faults on Itanium-based platform.
3265 CopyMem (SystemGuid
, &Smbios
.Type1
->Uuid
, sizeof (EFI_GUID
));
3270 // Go to the next SMBIOS structure. Each SMBIOS structure may include 2 parts:
3271 // 1. Formatted section; 2. Unformatted string section. So, 2 steps are needed
3272 // to skip one SMBIOS structure.
3276 // Step 1: Skip over formatted section.
3278 String
= (CHAR8
*)(Smbios
.Raw
+ Smbios
.Hdr
->Length
);
3281 // Step 2: Skip over unformatted string section.
3285 // Each string is terminated with a NULL(00h) BYTE and the sets of strings
3286 // is terminated with an additional NULL(00h) BYTE.
3288 for ( ; *String
!= 0; String
++) {
3291 if (*(UINT8
*)++String
== 0) {
3293 // Pointer to the next SMBIOS structure.
3295 Smbios
.Raw
= (UINT8
*)++String
;
3299 } while (Smbios
.Raw
< SmbiosEnd
.Raw
);
3301 return EFI_NOT_FOUND
;
3305 Create Dns QName according the queried domain name.
3307 If DomainName is NULL, then ASSERT().
3309 QName is a domain name represented as a sequence of labels,
3310 where each label consists of a length octet followed by that
3311 number of octets. The QName terminates with the zero
3312 length octet for the null label of the root. Caller should
3313 take responsibility to free the buffer in returned pointer.
3315 @param DomainName The pointer to the queried domain name string.
3317 @retval NULL Failed to fill QName.
3318 @return QName filled successfully.
3323 NetLibCreateDnsQName (
3324 IN CHAR16
*DomainName
3328 UINTN QueryNameSize
;
3334 ASSERT (DomainName
!= NULL
);
3342 // One byte for first label length, one byte for terminated length zero.
3344 QueryNameSize
= StrLen (DomainName
) + 2;
3346 if (QueryNameSize
> DNS_MAX_NAME_SIZE
) {
3350 QueryName
= AllocateZeroPool (QueryNameSize
);
3351 if (QueryName
== NULL
) {
3358 for (Index
= 0; DomainName
[Index
] != 0; Index
++) {
3359 *Tail
= (CHAR8
)DomainName
[Index
];
3361 *Header
= (CHAR8
)Len
;
3371 *Header
= (CHAR8
)Len
;