4 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include <IndustryStandard/SmBios.h>
19 #include <Protocol/DriverBinding.h>
20 #include <Protocol/ServiceBinding.h>
21 #include <Protocol/SimpleNetwork.h>
22 #include <Protocol/AdapterInformation.h>
23 #include <Protocol/ManagedNetwork.h>
24 #include <Protocol/Ip4Config2.h>
25 #include <Protocol/ComponentName.h>
26 #include <Protocol/ComponentName2.h>
28 #include <Guid/SmBios.h>
30 #include <Library/NetLib.h>
31 #include <Library/BaseLib.h>
32 #include <Library/DebugLib.h>
33 #include <Library/BaseMemoryLib.h>
34 #include <Library/UefiBootServicesTableLib.h>
35 #include <Library/UefiRuntimeServicesTableLib.h>
36 #include <Library/MemoryAllocationLib.h>
37 #include <Library/DevicePathLib.h>
38 #include <Library/PrintLib.h>
39 #include <Library/UefiLib.h>
41 #define NIC_ITEM_CONFIG_SIZE (sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE)
42 #define DEFAULT_ZERO_START ((UINTN) ~0)
45 // All the supported IP4 maskes in host byte order.
47 GLOBAL_REMOVE_IF_UNREFERENCED IP4_ADDR gIp4AllMasks
[IP4_MASK_NUM
] = {
86 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IPv4_ADDRESS mZeroIp4Addr
= {{0, 0, 0, 0}};
89 // Any error level digitally larger than mNetDebugLevelMax
90 // will be silently discarded.
92 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mNetDebugLevelMax
= NETDEBUG_LEVEL_ERROR
;
93 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogPacketSeq
= 0xDEADBEEF;
96 // You can change mSyslogDstMac mSyslogDstIp and mSyslogSrcIp
97 // here to direct the syslog packets to the syslog deamon. The
98 // default is broadcast to both the ethernet and IP.
100 GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mSyslogDstMac
[NET_ETHER_ADDR_LEN
] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
101 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogDstIp
= 0xffffffff;
102 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogSrcIp
= 0;
104 GLOBAL_REMOVE_IF_UNREFERENCED CHAR8
*mMonthName
[] = {
120 // VLAN device path node template
122 GLOBAL_REMOVE_IF_UNREFERENCED VLAN_DEVICE_PATH mNetVlanDevicePathTemplate
= {
124 MESSAGING_DEVICE_PATH
,
127 (UINT8
) (sizeof (VLAN_DEVICE_PATH
)),
128 (UINT8
) ((sizeof (VLAN_DEVICE_PATH
)) >> 8)
135 Locate the handles that support SNP, then open one of them
136 to send the syslog packets. The caller isn't required to close
137 the SNP after use because the SNP is opened by HandleProtocol.
139 @return The point to SNP if one is properly openned. Otherwise NULL
142 EFI_SIMPLE_NETWORK_PROTOCOL
*
147 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
154 // Locate the handles which has SNP installed.
157 Status
= gBS
->LocateHandleBuffer (
159 &gEfiSimpleNetworkProtocolGuid
,
165 if (EFI_ERROR (Status
) || (HandleCount
== 0)) {
170 // Try to open one of the ethernet SNP protocol to send packet
174 for (Index
= 0; Index
< HandleCount
; Index
++) {
175 Status
= gBS
->HandleProtocol (
177 &gEfiSimpleNetworkProtocolGuid
,
181 if ((Status
== EFI_SUCCESS
) && (Snp
!= NULL
) &&
182 (Snp
->Mode
->IfType
== NET_IFTYPE_ETHERNET
) &&
183 (Snp
->Mode
->MaxPacketSize
>= NET_SYSLOG_PACKET_LEN
)) {
196 Transmit a syslog packet synchronously through SNP. The Packet
197 already has the ethernet header prepended. This function should
198 fill in the source MAC because it will try to locate a SNP each
199 time it is called to avoid the problem if SNP is unloaded.
200 This code snip is copied from MNP.
201 If Packet is NULL, then ASSERT().
203 @param[in] Packet The Syslog packet
204 @param[in] Length The length of the packet
206 @retval EFI_DEVICE_ERROR Failed to locate a usable SNP protocol
207 @retval EFI_TIMEOUT Timeout happened to send the packet.
208 @retval EFI_SUCCESS Packet is sent.
217 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
220 EFI_EVENT TimeoutEvent
;
223 ASSERT (Packet
!= NULL
);
225 Snp
= SyslogLocateSnp ();
228 return EFI_DEVICE_ERROR
;
231 Ether
= (ETHER_HEAD
*) Packet
;
232 CopyMem (Ether
->SrcMac
, Snp
->Mode
->CurrentAddress
.Addr
, NET_ETHER_ADDR_LEN
);
235 // Start the timeout event.
237 Status
= gBS
->CreateEvent (
245 if (EFI_ERROR (Status
)) {
249 Status
= gBS
->SetTimer (TimeoutEvent
, TimerRelative
, NET_SYSLOG_TX_TIMEOUT
);
251 if (EFI_ERROR (Status
)) {
257 // Transmit the packet through SNP.
259 Status
= Snp
->Transmit (Snp
, 0, Length
, Packet
, NULL
, NULL
, NULL
);
261 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_READY
)) {
262 Status
= EFI_DEVICE_ERROR
;
267 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
268 // if Status is EFI_NOT_READY, the transmit engine of the network
269 // interface is busy. Both need to sync SNP.
275 // Get the recycled transmit buffer status.
277 Snp
->GetStatus (Snp
, NULL
, (VOID
**) &TxBuf
);
279 if (!EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
280 Status
= EFI_TIMEOUT
;
284 } while (TxBuf
== NULL
);
286 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_TIMEOUT
)) {
291 // Status is EFI_NOT_READY. Restart the timer event and
292 // call Snp->Transmit again.
294 gBS
->SetTimer (TimeoutEvent
, TimerRelative
, NET_SYSLOG_TX_TIMEOUT
);
297 gBS
->SetTimer (TimeoutEvent
, TimerCancel
, 0);
300 gBS
->CloseEvent (TimeoutEvent
);
305 Build a syslog packet, including the Ethernet/Ip/Udp headers
308 @param[in] Level Syslog severity level
309 @param[in] Module The module that generates the log
310 @param[in] File The file that contains the current log
311 @param[in] Line The line of code in the File that contains the current log
312 @param[in] Message The log message
313 @param[in] BufLen The lenght of the Buf
314 @param[out] Buf The buffer to put the packet data
316 @return The length of the syslog packet built, 0 represents no packet is built.
333 EFI_UDP_HEADER
*Udp4
;
339 // Fill in the Ethernet header. Leave alone the source MAC.
340 // SyslogSendPacket will fill in the address for us.
342 Ether
= (ETHER_HEAD
*) Buf
;
343 CopyMem (Ether
->DstMac
, mSyslogDstMac
, NET_ETHER_ADDR_LEN
);
344 ZeroMem (Ether
->SrcMac
, NET_ETHER_ADDR_LEN
);
346 Ether
->EtherType
= HTONS (0x0800); // IPv4 protocol
348 Buf
+= sizeof (ETHER_HEAD
);
349 BufLen
-= sizeof (ETHER_HEAD
);
352 // Fill in the IP header
354 Ip4
= (IP4_HEAD
*) Buf
;
359 Ip4
->Id
= (UINT16
) mSyslogPacketSeq
;
362 Ip4
->Protocol
= 0x11;
364 Ip4
->Src
= mSyslogSrcIp
;
365 Ip4
->Dst
= mSyslogDstIp
;
367 Buf
+= sizeof (IP4_HEAD
);
368 BufLen
-= sizeof (IP4_HEAD
);
371 // Fill in the UDP header, Udp checksum is optional. Leave it zero.
373 Udp4
= (EFI_UDP_HEADER
*) Buf
;
374 Udp4
->SrcPort
= HTONS (514);
375 Udp4
->DstPort
= HTONS (514);
379 Buf
+= sizeof (EFI_UDP_HEADER
);
380 BufLen
-= sizeof (EFI_UDP_HEADER
);
383 // Build the syslog message body with <PRI> Timestamp machine module Message
385 Pri
= ((NET_SYSLOG_FACILITY
& 31) << 3) | (Level
& 7);
386 Status
= gRT
->GetTime (&Time
, NULL
);
387 if (EFI_ERROR (Status
)) {
392 // Use %a to format the ASCII strings, %s to format UNICODE strings
395 Len
+= (UINT32
) AsciiSPrint (
398 "<%d> %a %d %d:%d:%d ",
400 mMonthName
[Time
.Month
-1],
407 Len
+= (UINT32
) AsciiSPrint (
410 "Tiano %a: %a (Line: %d File: %a)",
419 // OK, patch the IP length/checksum and UDP length fields.
421 Len
+= sizeof (EFI_UDP_HEADER
);
422 Udp4
->Length
= HTONS ((UINT16
) Len
);
424 Len
+= sizeof (IP4_HEAD
);
425 Ip4
->TotalLen
= HTONS ((UINT16
) Len
);
426 Ip4
->Checksum
= (UINT16
) (~NetblockChecksum ((UINT8
*) Ip4
, sizeof (IP4_HEAD
)));
428 return Len
+ sizeof (ETHER_HEAD
);
432 Allocate a buffer, then format the message to it. This is a
433 help function for the NET_DEBUG_XXX macros. The PrintArg of
434 these macros treats the variable length print parameters as a
435 single parameter, and pass it to the NetDebugASPrint. For
436 example, NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name))
440 NETDEBUG_LEVEL_TRACE,
444 NetDebugASPrint ("State transit to %a\n", Name)
447 If Format is NULL, then ASSERT().
449 @param Format The ASCII format string.
450 @param ... The variable length parameter whose format is determined
451 by the Format string.
453 @return The buffer containing the formatted message,
454 or NULL if failed to allocate memory.
467 ASSERT (Format
!= NULL
);
469 Buf
= (CHAR8
*) AllocatePool (NET_DEBUG_MSG_LEN
);
475 VA_START (Marker
, Format
);
476 AsciiVSPrint (Buf
, NET_DEBUG_MSG_LEN
, Format
, Marker
);
483 Builds an UDP4 syslog packet and send it using SNP.
485 This function will locate a instance of SNP then send the message through it.
486 Because it isn't open the SNP BY_DRIVER, apply caution when using it.
488 @param Level The severity level of the message.
489 @param Module The Moudle that generates the log.
490 @param File The file that contains the log.
491 @param Line The exact line that contains the log.
492 @param Message The user message to log.
494 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
495 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet.
496 @retval EFI_DEVICE_ERROR Device error occurs.
497 @retval EFI_SUCCESS The log is discard because that it is more verbose
498 than the mNetDebugLevelMax. Or, it has been sent out.
515 // Check whether the message should be sent out
517 if (Message
== NULL
|| File
== NULL
|| Module
== NULL
) {
518 return EFI_INVALID_PARAMETER
;
521 if (Level
> mNetDebugLevelMax
) {
522 Status
= EFI_SUCCESS
;
527 // Allocate a maxium of 1024 bytes, the caller should ensure
528 // that the message plus the ethernet/ip/udp header is shorter
531 Packet
= (CHAR8
*) AllocatePool (NET_SYSLOG_PACKET_LEN
);
533 if (Packet
== NULL
) {
534 Status
= EFI_OUT_OF_RESOURCES
;
539 // Build the message: Ethernet header + IP header + Udp Header + user data
541 Len
= SyslogBuildPacket (
547 NET_SYSLOG_PACKET_LEN
,
551 Status
= EFI_DEVICE_ERROR
;
554 Status
= SyslogSendPacket (Packet
, Len
);
564 Return the length of the mask.
566 Return the length of the mask, the correct value is from 0 to 32.
567 If the mask is invalid, return the invalid length 33, which is IP4_MASK_NUM.
568 NetMask is in the host byte order.
570 @param[in] NetMask The netmask to get the length from.
572 @return The length of the netmask, IP4_MASK_NUM if the mask is invalid.
583 for (Index
= 0; Index
<= IP4_MASK_MAX
; Index
++) {
584 if (NetMask
== gIp4AllMasks
[Index
]) {
595 Return the class of the IP address, such as class A, B, C.
596 Addr is in host byte order.
599 Classful addressing (IP class A/B/C) has been deprecated according to RFC4632.
600 Caller of this function could only check the returned value against
601 IP4_ADDR_CLASSD (multicast) or IP4_ADDR_CLASSE (reserved) now.
603 The address of class A starts with 0.
604 If the address belong to class A, return IP4_ADDR_CLASSA.
605 The address of class B starts with 10.
606 If the address belong to class B, return IP4_ADDR_CLASSB.
607 The address of class C starts with 110.
608 If the address belong to class C, return IP4_ADDR_CLASSC.
609 The address of class D starts with 1110.
610 If the address belong to class D, return IP4_ADDR_CLASSD.
611 The address of class E starts with 1111.
612 If the address belong to class E, return IP4_ADDR_CLASSE.
615 @param[in] Addr The address to get the class from.
617 @return IP address class, such as IP4_ADDR_CLASSA.
628 ByteOne
= (UINT8
) (Addr
>> 24);
630 if ((ByteOne
& 0x80) == 0) {
631 return IP4_ADDR_CLASSA
;
633 } else if ((ByteOne
& 0xC0) == 0x80) {
634 return IP4_ADDR_CLASSB
;
636 } else if ((ByteOne
& 0xE0) == 0xC0) {
637 return IP4_ADDR_CLASSC
;
639 } else if ((ByteOne
& 0xF0) == 0xE0) {
640 return IP4_ADDR_CLASSD
;
643 return IP4_ADDR_CLASSE
;
650 Check whether the IP is a valid unicast address according to
653 ASSERT if NetMask is zero.
655 If all bits of the host address of IP are 0 or 1, IP is also not a valid unicast address,
656 except when the originator is one of the endpoints of a point-to-point link with a 31-bit
659 @param[in] Ip The IP to check against.
660 @param[in] NetMask The mask of the IP.
662 @return TRUE if IP is a valid unicast address on the network, otherwise FALSE.
672 ASSERT (NetMask
!= 0);
674 if (Ip
== 0 || IP4_IS_LOCAL_BROADCAST (Ip
)) {
678 if (NetGetMaskLength (NetMask
) != 31) {
679 if (((Ip
&~NetMask
) == ~NetMask
) || ((Ip
&~NetMask
) == 0)) {
690 Check whether the incoming IPv6 address is a valid unicast address.
692 ASSERT if Ip6 is NULL.
694 If the address is a multicast address has binary 0xFF at the start, it is not
695 a valid unicast address. If the address is unspecified ::, it is not a valid
696 unicast address to be assigned to any node. If the address is loopback address
697 ::1, it is also not a valid unicast address to be assigned to any physical
700 @param[in] Ip6 The IPv6 address to check against.
702 @return TRUE if Ip6 is a valid unicast address on the network, otherwise FALSE.
707 NetIp6IsValidUnicast (
708 IN EFI_IPv6_ADDRESS
*Ip6
714 ASSERT (Ip6
!= NULL
);
716 if (Ip6
->Addr
[0] == 0xFF) {
720 for (Index
= 0; Index
< 15; Index
++) {
721 if (Ip6
->Addr
[Index
] != 0) {
726 Byte
= Ip6
->Addr
[Index
];
728 if (Byte
== 0x0 || Byte
== 0x1) {
736 Check whether the incoming Ipv6 address is the unspecified address or not.
738 ASSERT if Ip6 is NULL.
740 @param[in] Ip6 - Ip6 address, in network order.
742 @retval TRUE - Yes, unspecified
748 NetIp6IsUnspecifiedAddr (
749 IN EFI_IPv6_ADDRESS
*Ip6
754 ASSERT (Ip6
!= NULL
);
756 for (Index
= 0; Index
< 16; Index
++) {
757 if (Ip6
->Addr
[Index
] != 0) {
766 Check whether the incoming Ipv6 address is a link-local address.
768 ASSERT if Ip6 is NULL.
770 @param[in] Ip6 - Ip6 address, in network order.
772 @retval TRUE - Yes, link-local address
778 NetIp6IsLinkLocalAddr (
779 IN EFI_IPv6_ADDRESS
*Ip6
784 ASSERT (Ip6
!= NULL
);
786 if (Ip6
->Addr
[0] != 0xFE) {
790 if (Ip6
->Addr
[1] != 0x80) {
794 for (Index
= 2; Index
< 8; Index
++) {
795 if (Ip6
->Addr
[Index
] != 0) {
804 Check whether the Ipv6 address1 and address2 are on the connected network.
806 ASSERT if Ip1 or Ip2 is NULL.
807 ASSERT if PrefixLength exceeds IP6_PREFIX_MAX.
809 @param[in] Ip1 - Ip6 address1, in network order.
810 @param[in] Ip2 - Ip6 address2, in network order.
811 @param[in] PrefixLength - The prefix length of the checking net.
813 @retval TRUE - Yes, connected.
820 EFI_IPv6_ADDRESS
*Ip1
,
821 EFI_IPv6_ADDRESS
*Ip2
,
829 ASSERT ((Ip1
!= NULL
) && (Ip2
!= NULL
) && (PrefixLength
<= IP6_PREFIX_MAX
));
831 if (PrefixLength
== 0) {
835 Byte
= (UINT8
) (PrefixLength
/ 8);
836 Bit
= (UINT8
) (PrefixLength
% 8);
838 if (CompareMem (Ip1
, Ip2
, Byte
) != 0) {
843 Mask
= (UINT8
) (0xFF << (8 - Bit
));
845 if ((Ip1
->Addr
[Byte
] & Mask
) != (Ip2
->Addr
[Byte
] & Mask
)) {
855 Switches the endianess of an IPv6 address
857 ASSERT if Ip6 is NULL.
859 This function swaps the bytes in a 128-bit IPv6 address to switch the value
860 from little endian to big endian or vice versa. The byte swapped value is
863 @param Ip6 Points to an IPv6 address
865 @return The byte swapped IPv6 address.
871 EFI_IPv6_ADDRESS
*Ip6
877 ASSERT (Ip6
!= NULL
);
879 CopyMem (&High
, Ip6
, sizeof (UINT64
));
880 CopyMem (&Low
, &Ip6
->Addr
[8], sizeof (UINT64
));
882 High
= SwapBytes64 (High
);
883 Low
= SwapBytes64 (Low
);
885 CopyMem (Ip6
, &Low
, sizeof (UINT64
));
886 CopyMem (&Ip6
->Addr
[8], &High
, sizeof (UINT64
));
892 Initialize a random seed using current time and monotonic count.
894 Get current time and monotonic count first. Then initialize a random seed
895 based on some basic mathematics operation on the hour, day, minute, second,
896 nanosecond and year of the current time and the monotonic count value.
898 @return The random seed initialized with current time.
909 UINT64 MonotonicCount
;
911 gRT
->GetTime (&Time
, NULL
);
912 Seed
= (Time
.Hour
<< 24 | Time
.Day
<< 16 | Time
.Minute
<< 8 | Time
.Second
);
913 Seed
^= Time
.Nanosecond
;
914 Seed
^= Time
.Year
<< 7;
916 gBS
->GetNextMonotonicCount (&MonotonicCount
);
917 Seed
+= (UINT32
) MonotonicCount
;
924 Extract a UINT32 from a byte stream.
926 ASSERT if Buf is NULL.
928 Copy a UINT32 from a byte stream, then converts it from Network
929 byte order to host byte order. Use this function to avoid alignment error.
931 @param[in] Buf The buffer to extract the UINT32.
933 @return The UINT32 extracted.
944 ASSERT (Buf
!= NULL
);
946 CopyMem (&Value
, Buf
, sizeof (UINT32
));
947 return NTOHL (Value
);
952 Put a UINT32 to the byte stream in network byte order.
954 ASSERT if Buf is NULL.
956 Converts a UINT32 from host byte order to network byte order. Then copy it to the
959 @param[in, out] Buf The buffer to put the UINT32.
960 @param[in] Data The data to be converted and put into the byte stream.
970 ASSERT (Buf
!= NULL
);
973 CopyMem (Buf
, &Data
, sizeof (UINT32
));
978 Remove the first node entry on the list, and return the removed node entry.
980 Removes the first node Entry from a doubly linked list. It is up to the caller of
981 this function to release the memory used by the first node if that is required. On
982 exit, the removed node is returned.
984 If Head is NULL, then ASSERT().
985 If Head was not initialized, then ASSERT().
986 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
987 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
990 @param[in, out] Head The list header.
992 @return The first node entry that is removed from the list, NULL if the list is empty.
998 IN OUT LIST_ENTRY
*Head
1003 ASSERT (Head
!= NULL
);
1005 if (IsListEmpty (Head
)) {
1009 First
= Head
->ForwardLink
;
1010 Head
->ForwardLink
= First
->ForwardLink
;
1011 First
->ForwardLink
->BackLink
= Head
;
1014 First
->ForwardLink
= (LIST_ENTRY
*) NULL
;
1015 First
->BackLink
= (LIST_ENTRY
*) NULL
;
1023 Remove the last node entry on the list and and return the removed node entry.
1025 Removes the last node entry from a doubly linked list. It is up to the caller of
1026 this function to release the memory used by the first node if that is required. On
1027 exit, the removed node is returned.
1029 If Head is NULL, then ASSERT().
1030 If Head was not initialized, then ASSERT().
1031 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
1032 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
1035 @param[in, out] Head The list head.
1037 @return The last node entry that is removed from the list, NULL if the list is empty.
1043 IN OUT LIST_ENTRY
*Head
1048 ASSERT (Head
!= NULL
);
1050 if (IsListEmpty (Head
)) {
1054 Last
= Head
->BackLink
;
1055 Head
->BackLink
= Last
->BackLink
;
1056 Last
->BackLink
->ForwardLink
= Head
;
1059 Last
->ForwardLink
= (LIST_ENTRY
*) NULL
;
1060 Last
->BackLink
= (LIST_ENTRY
*) NULL
;
1068 Insert a new node entry after a designated node entry of a doubly linked list.
1070 ASSERT if PrevEntry or NewEntry is NULL.
1072 Inserts a new node entry donated by NewEntry after the node entry donated by PrevEntry
1073 of the doubly linked list.
1075 @param[in, out] PrevEntry The previous entry to insert after.
1076 @param[in, out] NewEntry The new entry to insert.
1081 NetListInsertAfter (
1082 IN OUT LIST_ENTRY
*PrevEntry
,
1083 IN OUT LIST_ENTRY
*NewEntry
1086 ASSERT (PrevEntry
!= NULL
&& NewEntry
!= NULL
);
1088 NewEntry
->BackLink
= PrevEntry
;
1089 NewEntry
->ForwardLink
= PrevEntry
->ForwardLink
;
1090 PrevEntry
->ForwardLink
->BackLink
= NewEntry
;
1091 PrevEntry
->ForwardLink
= NewEntry
;
1096 Insert a new node entry before a designated node entry of a doubly linked list.
1098 ASSERT if PostEntry or NewEntry is NULL.
1100 Inserts a new node entry donated by NewEntry after the node entry donated by PostEntry
1101 of the doubly linked list.
1103 @param[in, out] PostEntry The entry to insert before.
1104 @param[in, out] NewEntry The new entry to insert.
1109 NetListInsertBefore (
1110 IN OUT LIST_ENTRY
*PostEntry
,
1111 IN OUT LIST_ENTRY
*NewEntry
1114 ASSERT (PostEntry
!= NULL
&& NewEntry
!= NULL
);
1116 NewEntry
->ForwardLink
= PostEntry
;
1117 NewEntry
->BackLink
= PostEntry
->BackLink
;
1118 PostEntry
->BackLink
->ForwardLink
= NewEntry
;
1119 PostEntry
->BackLink
= NewEntry
;
1123 Safe destroy nodes in a linked list, and return the length of the list after all possible operations finished.
1125 Destroy network child instance list by list traversals is not safe due to graph dependencies between nodes.
1126 This function performs a safe traversal to destroy these nodes by checking to see if the node being destroyed
1127 has been removed from the list or not.
1128 If it has been removed, then restart the traversal from the head.
1129 If it hasn't been removed, then continue with the next node directly.
1130 This function will end the iterate and return the CallBack's last return value if error happens,
1131 or retrun EFI_SUCCESS if 2 complete passes are made with no changes in the number of children in the list.
1133 @param[in] List The head of the list.
1134 @param[in] CallBack Pointer to the callback function to destroy one node in the list.
1135 @param[in] Context Pointer to the callback function's context: corresponds to the
1136 parameter Context in NET_DESTROY_LINK_LIST_CALLBACK.
1137 @param[out] ListLength The length of the link list if the function returns successfully.
1139 @retval EFI_SUCCESS Two complete passes are made with no changes in the number of children.
1140 @retval EFI_INVALID_PARAMETER The input parameter is invalid.
1141 @retval Others Return the CallBack's last return value.
1146 NetDestroyLinkList (
1147 IN LIST_ENTRY
*List
,
1148 IN NET_DESTROY_LINK_LIST_CALLBACK CallBack
,
1149 IN VOID
*Context
, OPTIONAL
1150 OUT UINTN
*ListLength OPTIONAL
1153 UINTN PreviousLength
;
1159 if (List
== NULL
|| CallBack
== NULL
) {
1160 return EFI_INVALID_PARAMETER
;
1165 PreviousLength
= Length
;
1166 Entry
= GetFirstNode (List
);
1167 while (!IsNull (List
, Entry
)) {
1168 Status
= CallBack (Entry
, Context
);
1169 if (EFI_ERROR (Status
)) {
1173 // Walk through the list to see whether the Entry has been removed or not.
1174 // If the Entry still exists, just try to destroy the next one.
1175 // If not, go back to the start point to iterate the list again.
1177 for (Ptr
= List
->ForwardLink
; Ptr
!= List
; Ptr
= Ptr
->ForwardLink
) {
1183 Entry
= GetNextNode (List
, Entry
);
1185 Entry
= GetFirstNode (List
);
1188 for (Length
= 0, Ptr
= List
->ForwardLink
; Ptr
!= List
; Length
++, Ptr
= Ptr
->ForwardLink
);
1189 } while (Length
!= PreviousLength
);
1191 if (ListLength
!= NULL
) {
1192 *ListLength
= Length
;
1198 This function checks the input Handle to see if it's one of these handles in ChildHandleBuffer.
1200 @param[in] Handle Handle to be checked.
1201 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer.
1202 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
1203 if NumberOfChildren is 0.
1205 @retval TRUE Found the input Handle in ChildHandleBuffer.
1206 @retval FALSE Can't find the input Handle in ChildHandleBuffer.
1211 NetIsInHandleBuffer (
1212 IN EFI_HANDLE Handle
,
1213 IN UINTN NumberOfChildren
,
1214 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
1219 if (NumberOfChildren
== 0 || ChildHandleBuffer
== NULL
) {
1223 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
1224 if (Handle
== ChildHandleBuffer
[Index
]) {
1234 Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.
1236 Initialize the forward and backward links of two head nodes donated by Map->Used
1237 and Map->Recycled of two doubly linked lists.
1238 Initializes the count of the <Key, Value> pairs in the netmap to zero.
1240 If Map is NULL, then ASSERT().
1241 If the address of Map->Used is NULL, then ASSERT().
1242 If the address of Map->Recycled is NULl, then ASSERT().
1244 @param[in, out] Map The netmap to initialize.
1253 ASSERT (Map
!= NULL
);
1255 InitializeListHead (&Map
->Used
);
1256 InitializeListHead (&Map
->Recycled
);
1262 To clean up the netmap, that is, release allocated memories.
1264 Removes all nodes of the Used doubly linked list and free memory of all related netmap items.
1265 Removes all nodes of the Recycled doubly linked list and free memory of all related netmap items.
1266 The number of the <Key, Value> pairs in the netmap is set to be zero.
1268 If Map is NULL, then ASSERT().
1270 @param[in, out] Map The netmap to clean up.
1283 ASSERT (Map
!= NULL
);
1285 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &Map
->Used
) {
1286 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1288 RemoveEntryList (&Item
->Link
);
1291 gBS
->FreePool (Item
);
1294 ASSERT ((Map
->Count
== 0) && IsListEmpty (&Map
->Used
));
1296 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &Map
->Recycled
) {
1297 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1299 RemoveEntryList (&Item
->Link
);
1300 gBS
->FreePool (Item
);
1303 ASSERT (IsListEmpty (&Map
->Recycled
));
1308 Test whether the netmap is empty and return true if it is.
1310 If the number of the <Key, Value> pairs in the netmap is zero, return TRUE.
1312 If Map is NULL, then ASSERT().
1314 @param[in] Map The net map to test.
1316 @return TRUE if the netmap is empty, otherwise FALSE.
1325 ASSERT (Map
!= NULL
);
1326 return (BOOLEAN
) (Map
->Count
== 0);
1331 Return the number of the <Key, Value> pairs in the netmap.
1333 If Map is NULL, then ASSERT().
1335 @param[in] Map The netmap to get the entry number.
1337 @return The entry number in the netmap.
1346 ASSERT (Map
!= NULL
);
1352 Return one allocated item.
1354 If the Recycled doubly linked list of the netmap is empty, it will try to allocate
1355 a batch of items if there are enough resources and add corresponding nodes to the begining
1356 of the Recycled doubly linked list of the netmap. Otherwise, it will directly remove
1357 the fist node entry of the Recycled doubly linked list and return the corresponding item.
1359 If Map is NULL, then ASSERT().
1361 @param[in, out] Map The netmap to allocate item for.
1363 @return The allocated item. If NULL, the
1364 allocation failed due to resource limit.
1376 ASSERT (Map
!= NULL
);
1378 Head
= &Map
->Recycled
;
1380 if (IsListEmpty (Head
)) {
1381 for (Index
= 0; Index
< NET_MAP_INCREAMENT
; Index
++) {
1382 Item
= AllocatePool (sizeof (NET_MAP_ITEM
));
1392 InsertHeadList (Head
, &Item
->Link
);
1396 Item
= NET_LIST_HEAD (Head
, NET_MAP_ITEM
, Link
);
1397 NetListRemoveHead (Head
);
1404 Allocate an item to save the <Key, Value> pair to the head of the netmap.
1406 Allocate an item to save the <Key, Value> pair and add corresponding node entry
1407 to the beginning of the Used doubly linked list. The number of the <Key, Value>
1408 pairs in the netmap increase by 1.
1410 If Map is NULL, then ASSERT().
1411 If Key is NULL, then ASSERT().
1413 @param[in, out] Map The netmap to insert into.
1414 @param[in] Key The user's key.
1415 @param[in] Value The user's value for the key.
1417 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
1418 @retval EFI_SUCCESS The item is inserted to the head.
1424 IN OUT NET_MAP
*Map
,
1426 IN VOID
*Value OPTIONAL
1431 ASSERT (Map
!= NULL
&& Key
!= NULL
);
1433 Item
= NetMapAllocItem (Map
);
1436 return EFI_OUT_OF_RESOURCES
;
1440 Item
->Value
= Value
;
1441 InsertHeadList (&Map
->Used
, &Item
->Link
);
1449 Allocate an item to save the <Key, Value> pair to the tail of the netmap.
1451 Allocate an item to save the <Key, Value> pair and add corresponding node entry
1452 to the tail of the Used doubly linked list. The number of the <Key, Value>
1453 pairs in the netmap increase by 1.
1455 If Map is NULL, then ASSERT().
1456 If Key is NULL, then ASSERT().
1458 @param[in, out] Map The netmap to insert into.
1459 @param[in] Key The user's key.
1460 @param[in] Value The user's value for the key.
1462 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
1463 @retval EFI_SUCCESS The item is inserted to the tail.
1469 IN OUT NET_MAP
*Map
,
1471 IN VOID
*Value OPTIONAL
1476 ASSERT (Map
!= NULL
&& Key
!= NULL
);
1478 Item
= NetMapAllocItem (Map
);
1481 return EFI_OUT_OF_RESOURCES
;
1485 Item
->Value
= Value
;
1486 InsertTailList (&Map
->Used
, &Item
->Link
);
1495 Check whether the item is in the Map and return TRUE if it is.
1497 If Map is NULL, then ASSERT().
1498 If Item is NULL, then ASSERT().
1500 @param[in] Map The netmap to search within.
1501 @param[in] Item The item to search.
1503 @return TRUE if the item is in the netmap, otherwise FALSE.
1509 IN NET_MAP_ITEM
*Item
1512 LIST_ENTRY
*ListEntry
;
1514 ASSERT (Map
!= NULL
&& Item
!= NULL
);
1516 NET_LIST_FOR_EACH (ListEntry
, &Map
->Used
) {
1517 if (ListEntry
== &Item
->Link
) {
1527 Find the key in the netmap and returns the point to the item contains the Key.
1529 Iterate the Used doubly linked list of the netmap to get every item. Compare the key of every
1530 item with the key to search. It returns the point to the item contains the Key if found.
1532 If Map is NULL, then ASSERT().
1533 If Key is NULL, then ASSERT().
1535 @param[in] Map The netmap to search within.
1536 @param[in] Key The key to search.
1538 @return The point to the item contains the Key, or NULL if Key isn't in the map.
1551 ASSERT (Map
!= NULL
&& Key
!= NULL
);
1553 NET_LIST_FOR_EACH (Entry
, &Map
->Used
) {
1554 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1556 if (Item
->Key
== Key
) {
1566 Remove the node entry of the item from the netmap and return the key of the removed item.
1568 Remove the node entry of the item from the Used doubly linked list of the netmap.
1569 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1570 entry of the item to the Recycled doubly linked list of the netmap. If Value is not NULL,
1571 Value will point to the value of the item. It returns the key of the removed item.
1573 If Map is NULL, then ASSERT().
1574 If Item is NULL, then ASSERT().
1575 if item in not in the netmap, then ASSERT().
1577 @param[in, out] Map The netmap to remove the item from.
1578 @param[in, out] Item The item to remove.
1579 @param[out] Value The variable to receive the value if not NULL.
1581 @return The key of the removed item.
1587 IN OUT NET_MAP
*Map
,
1588 IN OUT NET_MAP_ITEM
*Item
,
1589 OUT VOID
**Value OPTIONAL
1592 ASSERT ((Map
!= NULL
) && (Item
!= NULL
));
1593 ASSERT (NetItemInMap (Map
, Item
));
1595 RemoveEntryList (&Item
->Link
);
1597 InsertHeadList (&Map
->Recycled
, &Item
->Link
);
1599 if (Value
!= NULL
) {
1600 *Value
= Item
->Value
;
1608 Remove the first node entry on the netmap and return the key of the removed item.
1610 Remove the first node entry from the Used doubly linked list of the netmap.
1611 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1612 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
1613 parameter Value will point to the value of the item. It returns the key of the removed item.
1615 If Map is NULL, then ASSERT().
1616 If the Used doubly linked list is empty, then ASSERT().
1618 @param[in, out] Map The netmap to remove the head from.
1619 @param[out] Value The variable to receive the value if not NULL.
1621 @return The key of the item removed.
1627 IN OUT NET_MAP
*Map
,
1628 OUT VOID
**Value OPTIONAL
1634 // Often, it indicates a programming error to remove
1635 // the first entry in an empty list
1637 ASSERT (Map
&& !IsListEmpty (&Map
->Used
));
1639 Item
= NET_LIST_HEAD (&Map
->Used
, NET_MAP_ITEM
, Link
);
1640 RemoveEntryList (&Item
->Link
);
1642 InsertHeadList (&Map
->Recycled
, &Item
->Link
);
1644 if (Value
!= NULL
) {
1645 *Value
= Item
->Value
;
1653 Remove the last node entry on the netmap and return the key of the removed item.
1655 Remove the last node entry from the Used doubly linked list of the netmap.
1656 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1657 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
1658 parameter Value will point to the value of the item. It returns the key of the removed item.
1660 If Map is NULL, then ASSERT().
1661 If the Used doubly linked list is empty, then ASSERT().
1663 @param[in, out] Map The netmap to remove the tail from.
1664 @param[out] Value The variable to receive the value if not NULL.
1666 @return The key of the item removed.
1672 IN OUT NET_MAP
*Map
,
1673 OUT VOID
**Value OPTIONAL
1679 // Often, it indicates a programming error to remove
1680 // the last entry in an empty list
1682 ASSERT (Map
&& !IsListEmpty (&Map
->Used
));
1684 Item
= NET_LIST_TAIL (&Map
->Used
, NET_MAP_ITEM
, Link
);
1685 RemoveEntryList (&Item
->Link
);
1687 InsertHeadList (&Map
->Recycled
, &Item
->Link
);
1689 if (Value
!= NULL
) {
1690 *Value
= Item
->Value
;
1698 Iterate through the netmap and call CallBack for each item.
1700 It will continue the traverse if CallBack returns EFI_SUCCESS, otherwise, break
1701 from the loop. It returns the CallBack's last return value. This function is
1702 delete safe for the current item.
1704 If Map is NULL, then ASSERT().
1705 If CallBack is NULL, then ASSERT().
1707 @param[in] Map The Map to iterate through.
1708 @param[in] CallBack The callback function to call for each item.
1709 @param[in] Arg The opaque parameter to the callback.
1711 @retval EFI_SUCCESS There is no item in the netmap or CallBack for each item
1713 @retval Others It returns the CallBack's last return value.
1720 IN NET_MAP_CALLBACK CallBack
,
1721 IN VOID
*Arg OPTIONAL
1731 ASSERT ((Map
!= NULL
) && (CallBack
!= NULL
));
1735 if (IsListEmpty (Head
)) {
1739 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, Head
) {
1740 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1741 Result
= CallBack (Map
, Item
, Arg
);
1743 if (EFI_ERROR (Result
)) {
1753 This is the default unload handle for all the network drivers.
1755 Disconnect the driver specified by ImageHandle from all the devices in the handle database.
1756 Uninstall all the protocols installed in the driver entry point.
1758 @param[in] ImageHandle The drivers' driver image.
1760 @retval EFI_SUCCESS The image is unloaded.
1761 @retval Others Failed to unload the image.
1766 NetLibDefaultUnload (
1767 IN EFI_HANDLE ImageHandle
1771 EFI_HANDLE
*DeviceHandleBuffer
;
1772 UINTN DeviceHandleCount
;
1775 EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
;
1776 EFI_COMPONENT_NAME_PROTOCOL
*ComponentName
;
1777 EFI_COMPONENT_NAME2_PROTOCOL
*ComponentName2
;
1780 // Get the list of all the handles in the handle database.
1781 // If there is an error getting the list, then the unload
1784 Status
= gBS
->LocateHandleBuffer (
1792 if (EFI_ERROR (Status
)) {
1796 for (Index
= 0; Index
< DeviceHandleCount
; Index
++) {
1797 Status
= gBS
->HandleProtocol (
1798 DeviceHandleBuffer
[Index
],
1799 &gEfiDriverBindingProtocolGuid
,
1800 (VOID
**) &DriverBinding
1802 if (EFI_ERROR (Status
)) {
1806 if (DriverBinding
->ImageHandle
!= ImageHandle
) {
1811 // Disconnect the driver specified by ImageHandle from all
1812 // the devices in the handle database.
1814 for (Index2
= 0; Index2
< DeviceHandleCount
; Index2
++) {
1815 Status
= gBS
->DisconnectController (
1816 DeviceHandleBuffer
[Index2
],
1817 DriverBinding
->DriverBindingHandle
,
1823 // Uninstall all the protocols installed in the driver entry point
1825 gBS
->UninstallProtocolInterface (
1826 DriverBinding
->DriverBindingHandle
,
1827 &gEfiDriverBindingProtocolGuid
,
1831 Status
= gBS
->HandleProtocol (
1832 DeviceHandleBuffer
[Index
],
1833 &gEfiComponentNameProtocolGuid
,
1834 (VOID
**) &ComponentName
1836 if (!EFI_ERROR (Status
)) {
1837 gBS
->UninstallProtocolInterface (
1838 DriverBinding
->DriverBindingHandle
,
1839 &gEfiComponentNameProtocolGuid
,
1844 Status
= gBS
->HandleProtocol (
1845 DeviceHandleBuffer
[Index
],
1846 &gEfiComponentName2ProtocolGuid
,
1847 (VOID
**) &ComponentName2
1849 if (!EFI_ERROR (Status
)) {
1850 gBS
->UninstallProtocolInterface (
1851 DriverBinding
->DriverBindingHandle
,
1852 &gEfiComponentName2ProtocolGuid
,
1859 // Free the buffer containing the list of handles from the handle database
1861 if (DeviceHandleBuffer
!= NULL
) {
1862 gBS
->FreePool (DeviceHandleBuffer
);
1871 Create a child of the service that is identified by ServiceBindingGuid.
1873 Get the ServiceBinding Protocol first, then use it to create a child.
1875 If ServiceBindingGuid is NULL, then ASSERT().
1876 If ChildHandle is NULL, then ASSERT().
1878 @param[in] Controller The controller which has the service installed.
1879 @param[in] Image The image handle used to open service.
1880 @param[in] ServiceBindingGuid The service's Guid.
1881 @param[in, out] ChildHandle The handle to receive the create child.
1883 @retval EFI_SUCCESS The child is successfully created.
1884 @retval Others Failed to create the child.
1889 NetLibCreateServiceChild (
1890 IN EFI_HANDLE Controller
,
1891 IN EFI_HANDLE Image
,
1892 IN EFI_GUID
*ServiceBindingGuid
,
1893 IN OUT EFI_HANDLE
*ChildHandle
1897 EFI_SERVICE_BINDING_PROTOCOL
*Service
;
1900 ASSERT ((ServiceBindingGuid
!= NULL
) && (ChildHandle
!= NULL
));
1903 // Get the ServiceBinding Protocol
1905 Status
= gBS
->OpenProtocol (
1911 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1914 if (EFI_ERROR (Status
)) {
1921 Status
= Service
->CreateChild (Service
, ChildHandle
);
1927 Destroy a child of the service that is identified by ServiceBindingGuid.
1929 Get the ServiceBinding Protocol first, then use it to destroy a child.
1931 If ServiceBindingGuid is NULL, then ASSERT().
1933 @param[in] Controller The controller which has the service installed.
1934 @param[in] Image The image handle used to open service.
1935 @param[in] ServiceBindingGuid The service's Guid.
1936 @param[in] ChildHandle The child to destroy.
1938 @retval EFI_SUCCESS The child is successfully destroyed.
1939 @retval Others Failed to destroy the child.
1944 NetLibDestroyServiceChild (
1945 IN EFI_HANDLE Controller
,
1946 IN EFI_HANDLE Image
,
1947 IN EFI_GUID
*ServiceBindingGuid
,
1948 IN EFI_HANDLE ChildHandle
1952 EFI_SERVICE_BINDING_PROTOCOL
*Service
;
1954 ASSERT (ServiceBindingGuid
!= NULL
);
1957 // Get the ServiceBinding Protocol
1959 Status
= gBS
->OpenProtocol (
1965 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1968 if (EFI_ERROR (Status
)) {
1973 // destroy the child
1975 Status
= Service
->DestroyChild (Service
, ChildHandle
);
1980 Get handle with Simple Network Protocol installed on it.
1982 There should be MNP Service Binding Protocol installed on the input ServiceHandle.
1983 If Simple Network Protocol is already installed on the ServiceHandle, the
1984 ServiceHandle will be returned. If SNP is not installed on the ServiceHandle,
1985 try to find its parent handle with SNP installed.
1987 @param[in] ServiceHandle The handle where network service binding protocols are
1989 @param[out] Snp The pointer to store the address of the SNP instance.
1990 This is an optional parameter that may be NULL.
1992 @return The SNP handle, or NULL if not found.
1997 NetLibGetSnpHandle (
1998 IN EFI_HANDLE ServiceHandle
,
1999 OUT EFI_SIMPLE_NETWORK_PROTOCOL
**Snp OPTIONAL
2003 EFI_SIMPLE_NETWORK_PROTOCOL
*SnpInstance
;
2004 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2005 EFI_HANDLE SnpHandle
;
2008 // Try to open SNP from ServiceHandle
2011 Status
= gBS
->HandleProtocol (ServiceHandle
, &gEfiSimpleNetworkProtocolGuid
, (VOID
**) &SnpInstance
);
2012 if (!EFI_ERROR (Status
)) {
2016 return ServiceHandle
;
2020 // Failed to open SNP, try to get SNP handle by LocateDevicePath()
2022 DevicePath
= DevicePathFromHandle (ServiceHandle
);
2023 if (DevicePath
== NULL
) {
2028 Status
= gBS
->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid
, &DevicePath
, &SnpHandle
);
2029 if (EFI_ERROR (Status
)) {
2031 // Failed to find SNP handle
2036 Status
= gBS
->HandleProtocol (SnpHandle
, &gEfiSimpleNetworkProtocolGuid
, (VOID
**) &SnpInstance
);
2037 if (!EFI_ERROR (Status
)) {
2048 Retrieve VLAN ID of a VLAN device handle.
2050 Search VLAN device path node in Device Path of specified ServiceHandle and
2051 return its VLAN ID. If no VLAN device path node found, then this ServiceHandle
2052 is not a VLAN device handle, and 0 will be returned.
2054 @param[in] ServiceHandle The handle where network service binding protocols are
2057 @return VLAN ID of the device handle, or 0 if not a VLAN device.
2063 IN EFI_HANDLE ServiceHandle
2066 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2067 EFI_DEVICE_PATH_PROTOCOL
*Node
;
2069 DevicePath
= DevicePathFromHandle (ServiceHandle
);
2070 if (DevicePath
== NULL
) {
2075 while (!IsDevicePathEnd (Node
)) {
2076 if (Node
->Type
== MESSAGING_DEVICE_PATH
&& Node
->SubType
== MSG_VLAN_DP
) {
2077 return ((VLAN_DEVICE_PATH
*) Node
)->VlanId
;
2079 Node
= NextDevicePathNode (Node
);
2086 Find VLAN device handle with specified VLAN ID.
2088 The VLAN child device handle is created by VLAN Config Protocol on ControllerHandle.
2089 This function will append VLAN device path node to the parent device path,
2090 and then use LocateDevicePath() to find the correct VLAN device handle.
2092 @param[in] ControllerHandle The handle where network service binding protocols are
2094 @param[in] VlanId The configured VLAN ID for the VLAN device.
2096 @return The VLAN device handle, or NULL if not found.
2101 NetLibGetVlanHandle (
2102 IN EFI_HANDLE ControllerHandle
,
2106 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
2107 EFI_DEVICE_PATH_PROTOCOL
*VlanDevicePath
;
2108 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2109 VLAN_DEVICE_PATH VlanNode
;
2112 ParentDevicePath
= DevicePathFromHandle (ControllerHandle
);
2113 if (ParentDevicePath
== NULL
) {
2118 // Construct VLAN device path
2120 CopyMem (&VlanNode
, &mNetVlanDevicePathTemplate
, sizeof (VLAN_DEVICE_PATH
));
2121 VlanNode
.VlanId
= VlanId
;
2122 VlanDevicePath
= AppendDevicePathNode (
2124 (EFI_DEVICE_PATH_PROTOCOL
*) &VlanNode
2126 if (VlanDevicePath
== NULL
) {
2131 // Find VLAN device handle
2134 DevicePath
= VlanDevicePath
;
2135 gBS
->LocateDevicePath (
2136 &gEfiDevicePathProtocolGuid
,
2140 if (!IsDevicePathEnd (DevicePath
)) {
2142 // Device path is not exactly match
2147 FreePool (VlanDevicePath
);
2152 Get MAC address associated with the network service handle.
2154 If MacAddress is NULL, then ASSERT().
2155 If AddressSize is NULL, then ASSERT().
2157 There should be MNP Service Binding Protocol installed on the input ServiceHandle.
2158 If SNP is installed on the ServiceHandle or its parent handle, MAC address will
2159 be retrieved from SNP. If no SNP found, try to get SNP mode data use MNP.
2161 @param[in] ServiceHandle The handle where network service binding protocols are
2163 @param[out] MacAddress The pointer to store the returned MAC address.
2164 @param[out] AddressSize The length of returned MAC address.
2166 @retval EFI_SUCCESS MAC address is returned successfully.
2167 @retval Others Failed to get SNP mode data.
2172 NetLibGetMacAddress (
2173 IN EFI_HANDLE ServiceHandle
,
2174 OUT EFI_MAC_ADDRESS
*MacAddress
,
2175 OUT UINTN
*AddressSize
2179 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2180 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
2181 EFI_SIMPLE_NETWORK_MODE SnpModeData
;
2182 EFI_MANAGED_NETWORK_PROTOCOL
*Mnp
;
2183 EFI_SERVICE_BINDING_PROTOCOL
*MnpSb
;
2184 EFI_HANDLE
*SnpHandle
;
2185 EFI_HANDLE MnpChildHandle
;
2187 ASSERT (MacAddress
!= NULL
);
2188 ASSERT (AddressSize
!= NULL
);
2191 // Try to get SNP handle
2194 SnpHandle
= NetLibGetSnpHandle (ServiceHandle
, &Snp
);
2195 if (SnpHandle
!= NULL
) {
2197 // SNP found, use it directly
2199 SnpMode
= Snp
->Mode
;
2202 // Failed to get SNP handle, try to get MAC address from MNP
2204 MnpChildHandle
= NULL
;
2205 Status
= gBS
->HandleProtocol (
2207 &gEfiManagedNetworkServiceBindingProtocolGuid
,
2210 if (EFI_ERROR (Status
)) {
2215 // Create a MNP child
2217 Status
= MnpSb
->CreateChild (MnpSb
, &MnpChildHandle
);
2218 if (EFI_ERROR (Status
)) {
2223 // Open MNP protocol
2225 Status
= gBS
->HandleProtocol (
2227 &gEfiManagedNetworkProtocolGuid
,
2230 if (EFI_ERROR (Status
)) {
2231 MnpSb
->DestroyChild (MnpSb
, MnpChildHandle
);
2236 // Try to get SNP mode from MNP
2238 Status
= Mnp
->GetModeData (Mnp
, NULL
, &SnpModeData
);
2239 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_STARTED
)) {
2240 MnpSb
->DestroyChild (MnpSb
, MnpChildHandle
);
2243 SnpMode
= &SnpModeData
;
2246 // Destroy the MNP child
2248 MnpSb
->DestroyChild (MnpSb
, MnpChildHandle
);
2251 *AddressSize
= SnpMode
->HwAddressSize
;
2252 CopyMem (MacAddress
->Addr
, SnpMode
->CurrentAddress
.Addr
, SnpMode
->HwAddressSize
);
2258 Convert MAC address of the NIC associated with specified Service Binding Handle
2259 to a unicode string. Callers are responsible for freeing the string storage.
2261 If MacString is NULL, then ASSERT().
2263 Locate simple network protocol associated with the Service Binding Handle and
2264 get the mac address from SNP. Then convert the mac address into a unicode
2265 string. It takes 2 unicode characters to represent a 1 byte binary buffer.
2266 Plus one unicode character for the null-terminator.
2268 @param[in] ServiceHandle The handle where network service binding protocol is
2270 @param[in] ImageHandle The image handle used to act as the agent handle to
2271 get the simple network protocol. This parameter is
2272 optional and may be NULL.
2273 @param[out] MacString The pointer to store the address of the string
2274 representation of the mac address.
2276 @retval EFI_SUCCESS Convert the mac address a unicode string successfully.
2277 @retval EFI_OUT_OF_RESOURCES There are not enough memory resource.
2278 @retval Others Failed to open the simple network protocol.
2283 NetLibGetMacString (
2284 IN EFI_HANDLE ServiceHandle
,
2285 IN EFI_HANDLE ImageHandle
, OPTIONAL
2286 OUT CHAR16
**MacString
2290 EFI_MAC_ADDRESS MacAddress
;
2292 UINTN HwAddressSize
;
2298 ASSERT (MacString
!= NULL
);
2301 // Get MAC address of the network device
2303 Status
= NetLibGetMacAddress (ServiceHandle
, &MacAddress
, &HwAddressSize
);
2304 if (EFI_ERROR (Status
)) {
2309 // It takes 2 unicode characters to represent a 1 byte binary buffer.
2310 // If VLAN is configured, it will need extra 5 characters like "\0005".
2311 // Plus one unicode character for the null-terminator.
2313 BufferSize
= (2 * HwAddressSize
+ 5 + 1) * sizeof (CHAR16
);
2314 String
= AllocateZeroPool (BufferSize
);
2315 if (String
== NULL
) {
2316 return EFI_OUT_OF_RESOURCES
;
2318 *MacString
= String
;
2321 // Convert the MAC address into a unicode string.
2323 HwAddress
= &MacAddress
.Addr
[0];
2324 for (Index
= 0; Index
< HwAddressSize
; Index
++) {
2325 UnicodeValueToStringS (
2327 BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
),
2328 PREFIX_ZERO
| RADIX_HEX
,
2332 String
+= StrnLenS (String
, (BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
)) / sizeof (CHAR16
));
2336 // Append VLAN ID if any
2338 VlanId
= NetLibGetVlanId (ServiceHandle
);
2341 UnicodeValueToStringS (
2343 BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
),
2344 PREFIX_ZERO
| RADIX_HEX
,
2348 String
+= StrnLenS (String
, (BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
)) / sizeof (CHAR16
));
2352 // Null terminate the Unicode string
2360 Detect media status for specified network device.
2362 If MediaPresent is NULL, then ASSERT().
2364 The underlying UNDI driver may or may not support reporting media status from
2365 GET_STATUS command (PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED). This routine
2366 will try to invoke Snp->GetStatus() to get the media status: if media already
2367 present, it return directly; if media not present, it will stop SNP and then
2368 restart SNP to get the latest media status, this give chance to get the correct
2369 media status for old UNDI driver which doesn't support reporting media status
2370 from GET_STATUS command.
2371 Note: there will be two limitations for current algorithm:
2372 1) for UNDI with this capability, in case of cable is not attached, there will
2373 be an redundant Stop/Start() process;
2374 2) for UNDI without this capability, in case that network cable is attached when
2375 Snp->Initialize() is invoked while network cable is unattached later,
2376 NetLibDetectMedia() will report MediaPresent as TRUE, causing upper layer
2377 apps to wait for timeout time.
2379 @param[in] ServiceHandle The handle where network service binding protocols are
2381 @param[out] MediaPresent The pointer to store the media status.
2383 @retval EFI_SUCCESS Media detection success.
2384 @retval EFI_INVALID_PARAMETER ServiceHandle is not valid network device handle.
2385 @retval EFI_UNSUPPORTED Network device does not support media detection.
2386 @retval EFI_DEVICE_ERROR SNP is in unknown state.
2392 IN EFI_HANDLE ServiceHandle
,
2393 OUT BOOLEAN
*MediaPresent
2397 EFI_HANDLE SnpHandle
;
2398 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2399 UINT32 InterruptStatus
;
2401 EFI_MAC_ADDRESS
*MCastFilter
;
2402 UINT32 MCastFilterCount
;
2403 UINT32 EnableFilterBits
;
2404 UINT32 DisableFilterBits
;
2405 BOOLEAN ResetMCastFilters
;
2407 ASSERT (MediaPresent
!= NULL
);
2413 SnpHandle
= NetLibGetSnpHandle (ServiceHandle
, &Snp
);
2414 if (SnpHandle
== NULL
) {
2415 return EFI_INVALID_PARAMETER
;
2419 // Check whether SNP support media detection
2421 if (!Snp
->Mode
->MediaPresentSupported
) {
2422 return EFI_UNSUPPORTED
;
2426 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
2428 Status
= Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
2429 if (EFI_ERROR (Status
)) {
2433 if (Snp
->Mode
->MediaPresent
) {
2435 // Media is present, return directly
2437 *MediaPresent
= TRUE
;
2442 // Till now, GetStatus() report no media; while, in case UNDI not support
2443 // reporting media status from GetStatus(), this media status may be incorrect.
2444 // So, we will stop SNP and then restart it to get the correct media status.
2446 OldState
= Snp
->Mode
->State
;
2447 if (OldState
>= EfiSimpleNetworkMaxState
) {
2448 return EFI_DEVICE_ERROR
;
2453 if (OldState
== EfiSimpleNetworkInitialized
) {
2455 // SNP is already in use, need Shutdown/Stop and then Start/Initialize
2459 // Backup current SNP receive filter settings
2461 EnableFilterBits
= Snp
->Mode
->ReceiveFilterSetting
;
2462 DisableFilterBits
= Snp
->Mode
->ReceiveFilterMask
^ EnableFilterBits
;
2464 ResetMCastFilters
= TRUE
;
2465 MCastFilterCount
= Snp
->Mode
->MCastFilterCount
;
2466 if (MCastFilterCount
!= 0) {
2467 MCastFilter
= AllocateCopyPool (
2468 MCastFilterCount
* sizeof (EFI_MAC_ADDRESS
),
2469 Snp
->Mode
->MCastFilter
2471 ASSERT (MCastFilter
!= NULL
);
2472 if (MCastFilter
== NULL
) {
2473 Status
= EFI_OUT_OF_RESOURCES
;
2477 ResetMCastFilters
= FALSE
;
2481 // Shutdown/Stop the simple network
2483 Status
= Snp
->Shutdown (Snp
);
2484 if (!EFI_ERROR (Status
)) {
2485 Status
= Snp
->Stop (Snp
);
2487 if (EFI_ERROR (Status
)) {
2492 // Start/Initialize the simple network
2494 Status
= Snp
->Start (Snp
);
2495 if (!EFI_ERROR (Status
)) {
2496 Status
= Snp
->Initialize (Snp
, 0, 0);
2498 if (EFI_ERROR (Status
)) {
2503 // Here we get the correct media status
2505 *MediaPresent
= Snp
->Mode
->MediaPresent
;
2508 // Restore SNP receive filter settings
2510 Status
= Snp
->ReceiveFilters (
2519 if (MCastFilter
!= NULL
) {
2520 FreePool (MCastFilter
);
2527 // SNP is not in use, it's in state of EfiSimpleNetworkStopped or EfiSimpleNetworkStarted
2529 if (OldState
== EfiSimpleNetworkStopped
) {
2531 // SNP not start yet, start it
2533 Status
= Snp
->Start (Snp
);
2534 if (EFI_ERROR (Status
)) {
2540 // Initialize the simple network
2542 Status
= Snp
->Initialize (Snp
, 0, 0);
2543 if (EFI_ERROR (Status
)) {
2544 Status
= EFI_DEVICE_ERROR
;
2549 // Here we get the correct media status
2551 *MediaPresent
= Snp
->Mode
->MediaPresent
;
2554 // Shut down the simple network
2556 Snp
->Shutdown (Snp
);
2559 if (OldState
== EfiSimpleNetworkStopped
) {
2561 // Original SNP sate is Stopped, restore to original state
2566 if (MCastFilter
!= NULL
) {
2567 FreePool (MCastFilter
);
2575 Detect media state for a network device. This routine will wait for a period of time at
2576 a specified checking interval when a certain network is under connecting until connection
2577 process finishs or timeout. If Aip protocol is supported by low layer drivers, three kinds
2578 of media states can be detected: EFI_SUCCESS, EFI_NOT_READY and EFI_NO_MEDIA, represents
2579 connected state, connecting state and no media state respectively. When function detects
2580 the current state is EFI_NOT_READY, it will loop to wait for next time's check until state
2581 turns to be EFI_SUCCESS or EFI_NO_MEDIA. If Aip protocol is not supported, function will
2582 call NetLibDetectMedia() and return state directly.
2584 @param[in] ServiceHandle The handle where network service binding protocols are
2586 @param[in] Timeout The maximum number of 100ns units to wait when network
2587 is connecting. Zero value means detect once and return
2589 @param[out] MediaState The pointer to the detected media state.
2591 @retval EFI_SUCCESS Media detection success.
2592 @retval EFI_INVALID_PARAMETER ServiceHandle is not a valid network device handle or
2593 MediaState pointer is NULL.
2594 @retval EFI_DEVICE_ERROR A device error occurred.
2595 @retval EFI_TIMEOUT Network is connecting but timeout.
2600 NetLibDetectMediaWaitTimeout (
2601 IN EFI_HANDLE ServiceHandle
,
2603 OUT EFI_STATUS
*MediaState
2607 EFI_HANDLE SnpHandle
;
2608 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2609 EFI_ADAPTER_INFORMATION_PROTOCOL
*Aip
;
2610 EFI_ADAPTER_INFO_MEDIA_STATE
*MediaInfo
;
2611 BOOLEAN MediaPresent
;
2613 EFI_STATUS TimerStatus
;
2615 UINT64 TimeRemained
;
2617 if (MediaState
== NULL
) {
2618 return EFI_INVALID_PARAMETER
;
2620 *MediaState
= EFI_SUCCESS
;
2627 SnpHandle
= NetLibGetSnpHandle (ServiceHandle
, &Snp
);
2628 if (SnpHandle
== NULL
) {
2629 return EFI_INVALID_PARAMETER
;
2632 Status
= gBS
->HandleProtocol (
2634 &gEfiAdapterInformationProtocolGuid
,
2637 if (EFI_ERROR (Status
)) {
2639 MediaPresent
= TRUE
;
2640 Status
= NetLibDetectMedia (ServiceHandle
, &MediaPresent
);
2641 if (!EFI_ERROR (Status
)) {
2643 *MediaState
= EFI_SUCCESS
;
2645 *MediaState
= EFI_NO_MEDIA
;
2650 // NetLibDetectMedia doesn't support EFI_NOT_READY status, return now!
2655 Status
= Aip
->GetInformation (
2657 &gEfiAdapterInfoMediaStateGuid
,
2658 (VOID
**) &MediaInfo
,
2661 if (!EFI_ERROR (Status
)) {
2663 *MediaState
= MediaInfo
->MediaState
;
2664 FreePool (MediaInfo
);
2665 if (*MediaState
!= EFI_NOT_READY
|| Timeout
< MEDIA_STATE_DETECT_TIME_INTERVAL
) {
2671 if (MediaInfo
!= NULL
) {
2672 FreePool (MediaInfo
);
2675 if (Status
== EFI_UNSUPPORTED
) {
2678 // If gEfiAdapterInfoMediaStateGuid is not supported, call NetLibDetectMedia to get media state!
2680 MediaPresent
= TRUE
;
2681 Status
= NetLibDetectMedia (ServiceHandle
, &MediaPresent
);
2682 if (!EFI_ERROR (Status
)) {
2684 *MediaState
= EFI_SUCCESS
;
2686 *MediaState
= EFI_NO_MEDIA
;
2696 // Loop to check media state
2700 TimeRemained
= Timeout
;
2701 Status
= gBS
->CreateEvent (EVT_TIMER
, TPL_CALLBACK
, NULL
, NULL
, &Timer
);
2702 if (EFI_ERROR (Status
)) {
2703 return EFI_DEVICE_ERROR
;
2707 Status
= gBS
->SetTimer (
2710 MEDIA_STATE_DETECT_TIME_INTERVAL
2712 if (EFI_ERROR (Status
)) {
2713 gBS
->CloseEvent(Timer
);
2714 return EFI_DEVICE_ERROR
;
2718 TimerStatus
= gBS
->CheckEvent (Timer
);
2719 if (!EFI_ERROR (TimerStatus
)) {
2721 TimeRemained
-= MEDIA_STATE_DETECT_TIME_INTERVAL
;
2722 Status
= Aip
->GetInformation (
2724 &gEfiAdapterInfoMediaStateGuid
,
2725 (VOID
**) &MediaInfo
,
2728 if (!EFI_ERROR (Status
)) {
2730 *MediaState
= MediaInfo
->MediaState
;
2731 FreePool (MediaInfo
);
2734 if (MediaInfo
!= NULL
) {
2735 FreePool (MediaInfo
);
2737 gBS
->CloseEvent(Timer
);
2741 } while (TimerStatus
== EFI_NOT_READY
);
2742 } while (*MediaState
== EFI_NOT_READY
&& TimeRemained
>= MEDIA_STATE_DETECT_TIME_INTERVAL
);
2744 gBS
->CloseEvent(Timer
);
2745 if (*MediaState
== EFI_NOT_READY
&& TimeRemained
< MEDIA_STATE_DETECT_TIME_INTERVAL
) {
2753 Check the default address used by the IPv4 driver is static or dynamic (acquired
2756 If the controller handle does not have the EFI_IP4_CONFIG2_PROTOCOL installed, the
2757 default address is static. If failed to get the policy from Ip4 Config2 Protocol,
2758 the default address is static. Otherwise, get the result from Ip4 Config2 Protocol.
2760 @param[in] Controller The controller handle which has the EFI_IP4_CONFIG2_PROTOCOL
2761 relative with the default address to judge.
2763 @retval TRUE If the default address is static.
2764 @retval FALSE If the default address is acquired from DHCP.
2768 NetLibDefaultAddressIsStatic (
2769 IN EFI_HANDLE Controller
2773 EFI_IP4_CONFIG2_PROTOCOL
*Ip4Config2
;
2775 EFI_IP4_CONFIG2_POLICY Policy
;
2780 DataSize
= sizeof (EFI_IP4_CONFIG2_POLICY
);
2785 // Get Ip4Config2 policy.
2787 Status
= gBS
->HandleProtocol (Controller
, &gEfiIp4Config2ProtocolGuid
, (VOID
**) &Ip4Config2
);
2788 if (EFI_ERROR (Status
)) {
2792 Status
= Ip4Config2
->GetData (Ip4Config2
, Ip4Config2DataTypePolicy
, &DataSize
, &Policy
);
2793 if (EFI_ERROR (Status
)) {
2797 IsStatic
= (BOOLEAN
) (Policy
== Ip4Config2PolicyStatic
);
2805 Create an IPv4 device path node.
2807 If Node is NULL, then ASSERT().
2809 The header type of IPv4 device path node is MESSAGING_DEVICE_PATH.
2810 The header subtype of IPv4 device path node is MSG_IPv4_DP.
2811 Get other info from parameters to make up the whole IPv4 device path node.
2813 @param[in, out] Node Pointer to the IPv4 device path node.
2814 @param[in] Controller The controller handle.
2815 @param[in] LocalIp The local IPv4 address.
2816 @param[in] LocalPort The local port.
2817 @param[in] RemoteIp The remote IPv4 address.
2818 @param[in] RemotePort The remote port.
2819 @param[in] Protocol The protocol type in the IP header.
2820 @param[in] UseDefaultAddress Whether this instance is using default address or not.
2825 NetLibCreateIPv4DPathNode (
2826 IN OUT IPv4_DEVICE_PATH
*Node
,
2827 IN EFI_HANDLE Controller
,
2828 IN IP4_ADDR LocalIp
,
2829 IN UINT16 LocalPort
,
2830 IN IP4_ADDR RemoteIp
,
2831 IN UINT16 RemotePort
,
2833 IN BOOLEAN UseDefaultAddress
2836 ASSERT (Node
!= NULL
);
2838 Node
->Header
.Type
= MESSAGING_DEVICE_PATH
;
2839 Node
->Header
.SubType
= MSG_IPv4_DP
;
2840 SetDevicePathNodeLength (&Node
->Header
, sizeof (IPv4_DEVICE_PATH
));
2842 CopyMem (&Node
->LocalIpAddress
, &LocalIp
, sizeof (EFI_IPv4_ADDRESS
));
2843 CopyMem (&Node
->RemoteIpAddress
, &RemoteIp
, sizeof (EFI_IPv4_ADDRESS
));
2845 Node
->LocalPort
= LocalPort
;
2846 Node
->RemotePort
= RemotePort
;
2848 Node
->Protocol
= Protocol
;
2850 if (!UseDefaultAddress
) {
2851 Node
->StaticIpAddress
= TRUE
;
2853 Node
->StaticIpAddress
= NetLibDefaultAddressIsStatic (Controller
);
2857 // Set the Gateway IP address to default value 0:0:0:0.
2858 // Set the Subnet mask to default value 255:255:255:0.
2860 ZeroMem (&Node
->GatewayIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
2861 SetMem (&Node
->SubnetMask
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
2862 Node
->SubnetMask
.Addr
[3] = 0;
2866 Create an IPv6 device path node.
2868 If Node is NULL, then ASSERT().
2869 If LocalIp is NULL, then ASSERT().
2870 If RemoteIp is NULL, then ASSERT().
2872 The header type of IPv6 device path node is MESSAGING_DEVICE_PATH.
2873 The header subtype of IPv6 device path node is MSG_IPv6_DP.
2874 Get other info from parameters to make up the whole IPv6 device path node.
2876 @param[in, out] Node Pointer to the IPv6 device path node.
2877 @param[in] Controller The controller handle.
2878 @param[in] LocalIp The local IPv6 address.
2879 @param[in] LocalPort The local port.
2880 @param[in] RemoteIp The remote IPv6 address.
2881 @param[in] RemotePort The remote port.
2882 @param[in] Protocol The protocol type in the IP header.
2887 NetLibCreateIPv6DPathNode (
2888 IN OUT IPv6_DEVICE_PATH
*Node
,
2889 IN EFI_HANDLE Controller
,
2890 IN EFI_IPv6_ADDRESS
*LocalIp
,
2891 IN UINT16 LocalPort
,
2892 IN EFI_IPv6_ADDRESS
*RemoteIp
,
2893 IN UINT16 RemotePort
,
2897 ASSERT (Node
!= NULL
&& LocalIp
!= NULL
&& RemoteIp
!= NULL
);
2899 Node
->Header
.Type
= MESSAGING_DEVICE_PATH
;
2900 Node
->Header
.SubType
= MSG_IPv6_DP
;
2901 SetDevicePathNodeLength (&Node
->Header
, sizeof (IPv6_DEVICE_PATH
));
2903 CopyMem (&Node
->LocalIpAddress
, LocalIp
, sizeof (EFI_IPv6_ADDRESS
));
2904 CopyMem (&Node
->RemoteIpAddress
, RemoteIp
, sizeof (EFI_IPv6_ADDRESS
));
2906 Node
->LocalPort
= LocalPort
;
2907 Node
->RemotePort
= RemotePort
;
2909 Node
->Protocol
= Protocol
;
2912 // Set default value to IPAddressOrigin, PrefixLength.
2913 // Set the Gateway IP address to unspecified address.
2915 Node
->IpAddressOrigin
= 0;
2916 Node
->PrefixLength
= IP6_PREFIX_LENGTH
;
2917 ZeroMem (&Node
->GatewayIpAddress
, sizeof (EFI_IPv6_ADDRESS
));
2921 Find the UNDI/SNP handle from controller and protocol GUID.
2923 If ProtocolGuid is NULL, then ASSERT().
2925 For example, IP will open a MNP child to transmit/receive
2926 packets, when MNP is stopped, IP should also be stopped. IP
2927 needs to find its own private data which is related the IP's
2928 service binding instance that is install on UNDI/SNP handle.
2929 Now, the controller is either a MNP or ARP child handle. But
2930 IP opens these handle BY_DRIVER, use that info, we can get the
2933 @param[in] Controller Then protocol handle to check.
2934 @param[in] ProtocolGuid The protocol that is related with the handle.
2936 @return The UNDI/SNP handle or NULL for errors.
2941 NetLibGetNicHandle (
2942 IN EFI_HANDLE Controller
,
2943 IN EFI_GUID
*ProtocolGuid
2946 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenBuffer
;
2952 ASSERT (ProtocolGuid
!= NULL
);
2954 Status
= gBS
->OpenProtocolInformation (
2961 if (EFI_ERROR (Status
)) {
2967 for (Index
= 0; Index
< OpenCount
; Index
++) {
2968 if ((OpenBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_DRIVER
) != 0) {
2969 Handle
= OpenBuffer
[Index
].ControllerHandle
;
2974 gBS
->FreePool (OpenBuffer
);
2979 Convert one Null-terminated ASCII string (decimal dotted) to EFI_IPv4_ADDRESS.
2981 @param[in] String The pointer to the Ascii string.
2982 @param[out] Ip4Address The pointer to the converted IPv4 address.
2984 @retval EFI_SUCCESS Convert to IPv4 address successfully.
2985 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip4Address is NULL.
2990 NetLibAsciiStrToIp4 (
2991 IN CONST CHAR8
*String
,
2992 OUT EFI_IPv4_ADDRESS
*Ip4Address
2995 RETURN_STATUS Status
;
2998 Status
= AsciiStrToIpv4Address (String
, &EndPointer
, Ip4Address
, NULL
);
2999 if (RETURN_ERROR (Status
) || (*EndPointer
!= '\0')) {
3000 return EFI_INVALID_PARAMETER
;
3008 Convert one Null-terminated ASCII string to EFI_IPv6_ADDRESS. The format of the
3009 string is defined in RFC 4291 - Text Representation of Addresses.
3011 @param[in] String The pointer to the Ascii string.
3012 @param[out] Ip6Address The pointer to the converted IPv6 address.
3014 @retval EFI_SUCCESS Convert to IPv6 address successfully.
3015 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.
3020 NetLibAsciiStrToIp6 (
3021 IN CONST CHAR8
*String
,
3022 OUT EFI_IPv6_ADDRESS
*Ip6Address
3025 RETURN_STATUS Status
;
3028 Status
= AsciiStrToIpv6Address (String
, &EndPointer
, Ip6Address
, NULL
);
3029 if (RETURN_ERROR (Status
) || (*EndPointer
!= '\0')) {
3030 return EFI_INVALID_PARAMETER
;
3038 Convert one Null-terminated Unicode string (decimal dotted) to EFI_IPv4_ADDRESS.
3040 @param[in] String The pointer to the Ascii string.
3041 @param[out] Ip4Address The pointer to the converted IPv4 address.
3043 @retval EFI_SUCCESS Convert to IPv4 address successfully.
3044 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip4Address is NULL.
3050 IN CONST CHAR16
*String
,
3051 OUT EFI_IPv4_ADDRESS
*Ip4Address
3054 RETURN_STATUS Status
;
3057 Status
= StrToIpv4Address (String
, &EndPointer
, Ip4Address
, NULL
);
3058 if (RETURN_ERROR (Status
) || (*EndPointer
!= L
'\0')) {
3059 return EFI_INVALID_PARAMETER
;
3067 Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS. The format of
3068 the string is defined in RFC 4291 - Text Representation of Addresses.
3070 @param[in] String The pointer to the Ascii string.
3071 @param[out] Ip6Address The pointer to the converted IPv6 address.
3073 @retval EFI_SUCCESS Convert to IPv6 address successfully.
3074 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.
3080 IN CONST CHAR16
*String
,
3081 OUT EFI_IPv6_ADDRESS
*Ip6Address
3084 RETURN_STATUS Status
;
3087 Status
= StrToIpv6Address (String
, &EndPointer
, Ip6Address
, NULL
);
3088 if (RETURN_ERROR (Status
) || (*EndPointer
!= L
'\0')) {
3089 return EFI_INVALID_PARAMETER
;
3096 Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS and prefix length.
3097 The format of the string is defined in RFC 4291 - Text Representation of Addresses
3098 Prefixes: ipv6-address/prefix-length.
3100 @param[in] String The pointer to the Ascii string.
3101 @param[out] Ip6Address The pointer to the converted IPv6 address.
3102 @param[out] PrefixLength The pointer to the converted prefix length.
3104 @retval EFI_SUCCESS Convert to IPv6 address successfully.
3105 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.
3110 NetLibStrToIp6andPrefix (
3111 IN CONST CHAR16
*String
,
3112 OUT EFI_IPv6_ADDRESS
*Ip6Address
,
3113 OUT UINT8
*PrefixLength
3116 RETURN_STATUS Status
;
3119 Status
= StrToIpv6Address (String
, &EndPointer
, Ip6Address
, PrefixLength
);
3120 if (RETURN_ERROR (Status
) || (*EndPointer
!= L
'\0')) {
3121 return EFI_INVALID_PARAMETER
;
3129 Convert one EFI_IPv6_ADDRESS to Null-terminated Unicode string.
3130 The text representation of address is defined in RFC 4291.
3132 @param[in] Ip6Address The pointer to the IPv6 address.
3133 @param[out] String The buffer to return the converted string.
3134 @param[in] StringSize The length in bytes of the input String.
3136 @retval EFI_SUCCESS Convert to string successfully.
3137 @retval EFI_INVALID_PARAMETER The input parameter is invalid.
3138 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. BufferSize has been
3139 updated with the size needed to complete the request.
3144 IN EFI_IPv6_ADDRESS
*Ip6Address
,
3151 UINTN LongestZerosStart
;
3152 UINTN LongestZerosLength
;
3153 UINTN CurrentZerosStart
;
3154 UINTN CurrentZerosLength
;
3155 CHAR16 Buffer
[sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
3158 if (Ip6Address
== NULL
|| String
== NULL
|| StringSize
== 0) {
3159 return EFI_INVALID_PARAMETER
;
3163 // Convert the UINT8 array to an UINT16 array for easy handling.
3165 ZeroMem (Ip6Addr
, sizeof (Ip6Addr
));
3166 for (Index
= 0; Index
< 16; Index
++) {
3167 Ip6Addr
[Index
/ 2] |= (Ip6Address
->Addr
[Index
] << ((1 - (Index
% 2)) << 3));
3171 // Find the longest zeros and mark it.
3173 CurrentZerosStart
= DEFAULT_ZERO_START
;
3174 CurrentZerosLength
= 0;
3175 LongestZerosStart
= DEFAULT_ZERO_START
;
3176 LongestZerosLength
= 0;
3177 for (Index
= 0; Index
< 8; Index
++) {
3178 if (Ip6Addr
[Index
] == 0) {
3179 if (CurrentZerosStart
== DEFAULT_ZERO_START
) {
3180 CurrentZerosStart
= Index
;
3181 CurrentZerosLength
= 1;
3183 CurrentZerosLength
++;
3186 if (CurrentZerosStart
!= DEFAULT_ZERO_START
) {
3187 if (CurrentZerosLength
> 2 && (LongestZerosStart
== (DEFAULT_ZERO_START
) || CurrentZerosLength
> LongestZerosLength
)) {
3188 LongestZerosStart
= CurrentZerosStart
;
3189 LongestZerosLength
= CurrentZerosLength
;
3191 CurrentZerosStart
= DEFAULT_ZERO_START
;
3192 CurrentZerosLength
= 0;
3197 if (CurrentZerosStart
!= DEFAULT_ZERO_START
&& CurrentZerosLength
> 2) {
3198 if (LongestZerosStart
== DEFAULT_ZERO_START
|| LongestZerosLength
< CurrentZerosLength
) {
3199 LongestZerosStart
= CurrentZerosStart
;
3200 LongestZerosLength
= CurrentZerosLength
;
3205 for (Index
= 0; Index
< 8; Index
++) {
3206 if (LongestZerosStart
!= DEFAULT_ZERO_START
&& Index
>= LongestZerosStart
&& Index
< LongestZerosStart
+ LongestZerosLength
) {
3207 if (Index
== LongestZerosStart
) {
3215 Ptr
+= UnicodeSPrint(Ptr
, 10, L
"%x", Ip6Addr
[Index
]);
3218 if (LongestZerosStart
!= DEFAULT_ZERO_START
&& LongestZerosStart
+ LongestZerosLength
== 8) {
3223 if ((UINTN
)Ptr
- (UINTN
)Buffer
> StringSize
) {
3224 return EFI_BUFFER_TOO_SMALL
;
3227 StrCpyS (String
, StringSize
/ sizeof (CHAR16
), Buffer
);
3233 This function obtains the system guid from the smbios table.
3235 If SystemGuid is NULL, then ASSERT().
3237 @param[out] SystemGuid The pointer of the returned system guid.
3239 @retval EFI_SUCCESS Successfully obtained the system guid.
3240 @retval EFI_NOT_FOUND Did not find the SMBIOS table.
3245 NetLibGetSystemGuid (
3246 OUT EFI_GUID
*SystemGuid
3250 SMBIOS_TABLE_ENTRY_POINT
*SmbiosTable
;
3251 SMBIOS_TABLE_3_0_ENTRY_POINT
*Smbios30Table
;
3252 SMBIOS_STRUCTURE_POINTER Smbios
;
3253 SMBIOS_STRUCTURE_POINTER SmbiosEnd
;
3256 ASSERT (SystemGuid
!= NULL
);
3259 Status
= EfiGetSystemConfigurationTable (&gEfiSmbios3TableGuid
, (VOID
**) &Smbios30Table
);
3260 if (!(EFI_ERROR (Status
) || Smbios30Table
== NULL
)) {
3261 Smbios
.Hdr
= (SMBIOS_STRUCTURE
*) (UINTN
) Smbios30Table
->TableAddress
;
3262 SmbiosEnd
.Raw
= (UINT8
*) (UINTN
) (Smbios30Table
->TableAddress
+ Smbios30Table
->TableMaximumSize
);
3264 Status
= EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid
, (VOID
**) &SmbiosTable
);
3265 if (EFI_ERROR (Status
) || SmbiosTable
== NULL
) {
3266 return EFI_NOT_FOUND
;
3268 Smbios
.Hdr
= (SMBIOS_STRUCTURE
*) (UINTN
) SmbiosTable
->TableAddress
;
3269 SmbiosEnd
.Raw
= (UINT8
*) ((UINTN
) SmbiosTable
->TableAddress
+ SmbiosTable
->TableLength
);
3273 if (Smbios
.Hdr
->Type
== 1) {
3274 if (Smbios
.Hdr
->Length
< 0x19) {
3276 // Older version did not support UUID.
3278 return EFI_NOT_FOUND
;
3282 // SMBIOS tables are byte packed so we need to do a byte copy to
3283 // prevend alignment faults on Itanium-based platform.
3285 CopyMem (SystemGuid
, &Smbios
.Type1
->Uuid
, sizeof (EFI_GUID
));
3290 // Go to the next SMBIOS structure. Each SMBIOS structure may include 2 parts:
3291 // 1. Formatted section; 2. Unformatted string section. So, 2 steps are needed
3292 // to skip one SMBIOS structure.
3296 // Step 1: Skip over formatted section.
3298 String
= (CHAR8
*) (Smbios
.Raw
+ Smbios
.Hdr
->Length
);
3301 // Step 2: Skip over unformated string section.
3305 // Each string is terminated with a NULL(00h) BYTE and the sets of strings
3306 // is terminated with an additional NULL(00h) BYTE.
3308 for ( ; *String
!= 0; String
++) {
3311 if (*(UINT8
*)++String
== 0) {
3313 // Pointer to the next SMBIOS structure.
3315 Smbios
.Raw
= (UINT8
*)++String
;
3319 } while (Smbios
.Raw
< SmbiosEnd
.Raw
);
3320 return EFI_NOT_FOUND
;
3324 Create Dns QName according the queried domain name.
3326 If DomainName is NULL, then ASSERT().
3328 QName is a domain name represented as a sequence of labels,
3329 where each label consists of a length octet followed by that
3330 number of octets. The QName terminates with the zero
3331 length octet for the null label of the root. Caller should
3332 take responsibility to free the buffer in returned pointer.
3334 @param DomainName The pointer to the queried domain name string.
3336 @retval NULL Failed to fill QName.
3337 @return QName filled successfully.
3342 NetLibCreateDnsQName (
3343 IN CHAR16
*DomainName
3347 UINTN QueryNameSize
;
3353 ASSERT (DomainName
!= NULL
);
3361 // One byte for first label length, one byte for terminated length zero.
3363 QueryNameSize
= StrLen (DomainName
) + 2;
3365 if (QueryNameSize
> DNS_MAX_NAME_SIZE
) {
3369 QueryName
= AllocateZeroPool (QueryNameSize
);
3370 if (QueryName
== NULL
) {
3377 for (Index
= 0; DomainName
[Index
] != 0; Index
++) {
3378 *Tail
= (CHAR8
) DomainName
[Index
];
3380 *Header
= (CHAR8
) Len
;
3389 *Header
= (CHAR8
) Len
;