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 maskes in host byte order.
41 GLOBAL_REMOVE_IF_UNREFERENCED IP4_ADDR gIp4AllMasks
[IP4_MASK_NUM
] = {
80 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IPv4_ADDRESS mZeroIp4Addr
= {{0, 0, 0, 0}};
83 // Any error level digitally larger than mNetDebugLevelMax
84 // will be silently discarded.
86 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mNetDebugLevelMax
= NETDEBUG_LEVEL_ERROR
;
87 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogPacketSeq
= 0xDEADBEEF;
90 // You can change mSyslogDstMac mSyslogDstIp and mSyslogSrcIp
91 // here to direct the syslog packets to the syslog deamon. The
92 // default is broadcast to both the ethernet and IP.
94 GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mSyslogDstMac
[NET_ETHER_ADDR_LEN
] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
95 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogDstIp
= 0xffffffff;
96 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogSrcIp
= 0;
98 GLOBAL_REMOVE_IF_UNREFERENCED CHAR8
*mMonthName
[] = {
114 // VLAN device path node template
116 GLOBAL_REMOVE_IF_UNREFERENCED VLAN_DEVICE_PATH mNetVlanDevicePathTemplate
= {
118 MESSAGING_DEVICE_PATH
,
121 (UINT8
) (sizeof (VLAN_DEVICE_PATH
)),
122 (UINT8
) ((sizeof (VLAN_DEVICE_PATH
)) >> 8)
129 Locate the handles that support SNP, then open one of them
130 to send the syslog packets. The caller isn't required to close
131 the SNP after use because the SNP is opened by HandleProtocol.
133 @return The point to SNP if one is properly openned. Otherwise NULL
136 EFI_SIMPLE_NETWORK_PROTOCOL
*
141 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
148 // Locate the handles which has SNP installed.
151 Status
= gBS
->LocateHandleBuffer (
153 &gEfiSimpleNetworkProtocolGuid
,
159 if (EFI_ERROR (Status
) || (HandleCount
== 0)) {
164 // Try to open one of the ethernet SNP protocol to send packet
168 for (Index
= 0; Index
< HandleCount
; Index
++) {
169 Status
= gBS
->HandleProtocol (
171 &gEfiSimpleNetworkProtocolGuid
,
175 if ((Status
== EFI_SUCCESS
) && (Snp
!= NULL
) &&
176 (Snp
->Mode
->IfType
== NET_IFTYPE_ETHERNET
) &&
177 (Snp
->Mode
->MaxPacketSize
>= NET_SYSLOG_PACKET_LEN
)) {
190 Transmit a syslog packet synchronously through SNP. The Packet
191 already has the ethernet header prepended. This function should
192 fill in the source MAC because it will try to locate a SNP each
193 time it is called to avoid the problem if SNP is unloaded.
194 This code snip is copied from MNP.
195 If Packet is NULL, then ASSERT().
197 @param[in] Packet The Syslog packet
198 @param[in] Length The length of the packet
200 @retval EFI_DEVICE_ERROR Failed to locate a usable SNP protocol
201 @retval EFI_TIMEOUT Timeout happened to send the packet.
202 @retval EFI_SUCCESS Packet is sent.
211 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
214 EFI_EVENT TimeoutEvent
;
217 ASSERT (Packet
!= NULL
);
219 Snp
= SyslogLocateSnp ();
222 return EFI_DEVICE_ERROR
;
225 Ether
= (ETHER_HEAD
*) Packet
;
226 CopyMem (Ether
->SrcMac
, Snp
->Mode
->CurrentAddress
.Addr
, NET_ETHER_ADDR_LEN
);
229 // Start the timeout event.
231 Status
= gBS
->CreateEvent (
239 if (EFI_ERROR (Status
)) {
243 Status
= gBS
->SetTimer (TimeoutEvent
, TimerRelative
, NET_SYSLOG_TX_TIMEOUT
);
245 if (EFI_ERROR (Status
)) {
251 // Transmit the packet through SNP.
253 Status
= Snp
->Transmit (Snp
, 0, Length
, Packet
, NULL
, NULL
, NULL
);
255 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_READY
)) {
256 Status
= EFI_DEVICE_ERROR
;
261 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
262 // if Status is EFI_NOT_READY, the transmit engine of the network
263 // interface is busy. Both need to sync SNP.
269 // Get the recycled transmit buffer status.
271 Snp
->GetStatus (Snp
, NULL
, (VOID
**) &TxBuf
);
273 if (!EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
274 Status
= EFI_TIMEOUT
;
278 } while (TxBuf
== NULL
);
280 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_TIMEOUT
)) {
285 // Status is EFI_NOT_READY. Restart the timer event and
286 // call Snp->Transmit again.
288 gBS
->SetTimer (TimeoutEvent
, TimerRelative
, NET_SYSLOG_TX_TIMEOUT
);
291 gBS
->SetTimer (TimeoutEvent
, TimerCancel
, 0);
294 gBS
->CloseEvent (TimeoutEvent
);
299 Build a syslog packet, including the Ethernet/Ip/Udp headers
302 @param[in] Level Syslog severity level
303 @param[in] Module The module that generates the log
304 @param[in] File The file that contains the current log
305 @param[in] Line The line of code in the File that contains the current log
306 @param[in] Message The log message
307 @param[in] BufLen The lenght of the Buf
308 @param[out] Buf The buffer to put the packet data
310 @return The length of the syslog packet built, 0 represents no packet is built.
327 EFI_UDP_HEADER
*Udp4
;
333 // Fill in the Ethernet header. Leave alone the source MAC.
334 // SyslogSendPacket will fill in the address for us.
336 Ether
= (ETHER_HEAD
*) Buf
;
337 CopyMem (Ether
->DstMac
, mSyslogDstMac
, NET_ETHER_ADDR_LEN
);
338 ZeroMem (Ether
->SrcMac
, NET_ETHER_ADDR_LEN
);
340 Ether
->EtherType
= HTONS (0x0800); // IPv4 protocol
342 Buf
+= sizeof (ETHER_HEAD
);
343 BufLen
-= sizeof (ETHER_HEAD
);
346 // Fill in the IP header
348 Ip4
= (IP4_HEAD
*) Buf
;
353 Ip4
->Id
= (UINT16
) mSyslogPacketSeq
;
356 Ip4
->Protocol
= 0x11;
358 Ip4
->Src
= mSyslogSrcIp
;
359 Ip4
->Dst
= mSyslogDstIp
;
361 Buf
+= sizeof (IP4_HEAD
);
362 BufLen
-= sizeof (IP4_HEAD
);
365 // Fill in the UDP header, Udp checksum is optional. Leave it zero.
367 Udp4
= (EFI_UDP_HEADER
*) Buf
;
368 Udp4
->SrcPort
= HTONS (514);
369 Udp4
->DstPort
= HTONS (514);
373 Buf
+= sizeof (EFI_UDP_HEADER
);
374 BufLen
-= sizeof (EFI_UDP_HEADER
);
377 // Build the syslog message body with <PRI> Timestamp machine module Message
379 Pri
= ((NET_SYSLOG_FACILITY
& 31) << 3) | (Level
& 7);
380 Status
= gRT
->GetTime (&Time
, NULL
);
381 if (EFI_ERROR (Status
)) {
386 // Use %a to format the ASCII strings, %s to format UNICODE strings
389 Len
+= (UINT32
) AsciiSPrint (
392 "<%d> %a %d %d:%d:%d ",
394 mMonthName
[Time
.Month
-1],
401 Len
+= (UINT32
) AsciiSPrint (
404 "Tiano %a: %a (Line: %d File: %a)",
413 // OK, patch the IP length/checksum and UDP length fields.
415 Len
+= sizeof (EFI_UDP_HEADER
);
416 Udp4
->Length
= HTONS ((UINT16
) Len
);
418 Len
+= sizeof (IP4_HEAD
);
419 Ip4
->TotalLen
= HTONS ((UINT16
) Len
);
420 Ip4
->Checksum
= (UINT16
) (~NetblockChecksum ((UINT8
*) Ip4
, sizeof (IP4_HEAD
)));
422 return Len
+ sizeof (ETHER_HEAD
);
426 Allocate a buffer, then format the message to it. This is a
427 help function for the NET_DEBUG_XXX macros. The PrintArg of
428 these macros treats the variable length print parameters as a
429 single parameter, and pass it to the NetDebugASPrint. For
430 example, NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name))
434 NETDEBUG_LEVEL_TRACE,
438 NetDebugASPrint ("State transit to %a\n", Name)
441 If Format is NULL, then ASSERT().
443 @param Format The ASCII format string.
444 @param ... The variable length parameter whose format is determined
445 by the Format string.
447 @return The buffer containing the formatted message,
448 or NULL if failed to allocate memory.
461 ASSERT (Format
!= NULL
);
463 Buf
= (CHAR8
*) AllocatePool (NET_DEBUG_MSG_LEN
);
469 VA_START (Marker
, Format
);
470 AsciiVSPrint (Buf
, NET_DEBUG_MSG_LEN
, Format
, Marker
);
477 Builds an UDP4 syslog packet and send it using SNP.
479 This function will locate a instance of SNP then send the message through it.
480 Because it isn't open the SNP BY_DRIVER, apply caution when using it.
482 @param Level The severity level of the message.
483 @param Module The Moudle that generates the log.
484 @param File The file that contains the log.
485 @param Line The exact line that contains the log.
486 @param Message The user message to log.
488 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
489 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet.
490 @retval EFI_DEVICE_ERROR Device error occurs.
491 @retval EFI_SUCCESS The log is discard because that it is more verbose
492 than the mNetDebugLevelMax. Or, it has been sent out.
509 // Check whether the message should be sent out
511 if (Message
== NULL
|| File
== NULL
|| Module
== NULL
) {
512 return EFI_INVALID_PARAMETER
;
515 if (Level
> mNetDebugLevelMax
) {
516 Status
= EFI_SUCCESS
;
521 // Allocate a maxium of 1024 bytes, the caller should ensure
522 // that the message plus the ethernet/ip/udp header is shorter
525 Packet
= (CHAR8
*) AllocatePool (NET_SYSLOG_PACKET_LEN
);
527 if (Packet
== NULL
) {
528 Status
= EFI_OUT_OF_RESOURCES
;
533 // Build the message: Ethernet header + IP header + Udp Header + user data
535 Len
= SyslogBuildPacket (
541 NET_SYSLOG_PACKET_LEN
,
545 Status
= EFI_DEVICE_ERROR
;
548 Status
= SyslogSendPacket (Packet
, Len
);
558 Return the length of the mask.
560 Return the length of the mask, the correct value is from 0 to 32.
561 If the mask is invalid, return the invalid length 33, which is IP4_MASK_NUM.
562 NetMask is in the host byte order.
564 @param[in] NetMask The netmask to get the length from.
566 @return The length of the netmask, IP4_MASK_NUM if the mask is invalid.
577 for (Index
= 0; Index
<= IP4_MASK_MAX
; Index
++) {
578 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
;
627 } else if ((ByteOne
& 0xC0) == 0x80) {
628 return IP4_ADDR_CLASSB
;
630 } else if ((ByteOne
& 0xE0) == 0xC0) {
631 return IP4_ADDR_CLASSC
;
633 } else if ((ByteOne
& 0xF0) == 0xE0) {
634 return IP4_ADDR_CLASSD
;
637 return IP4_ADDR_CLASSE
;
644 Check whether the IP is a valid unicast address according to
647 ASSERT if NetMask is zero.
649 If all bits of the host address of IP are 0 or 1, IP is also not a valid unicast address,
650 except when the originator is one of the endpoints of a point-to-point link with a 31-bit
651 mask (RFC3021), or a 32bit NetMask (all 0xFF) is used for special network environment (e.g.
654 @param[in] Ip The IP to check against.
655 @param[in] NetMask The mask of the IP.
657 @return TRUE if IP is a valid unicast address on the network, otherwise FALSE.
669 ASSERT (NetMask
!= 0);
671 if (Ip
== 0 || IP4_IS_LOCAL_BROADCAST (Ip
)) {
675 MaskLength
= NetGetMaskLength (NetMask
);
676 ASSERT ((MaskLength
>= 0) && (MaskLength
<= IP4_MASK_NUM
));
677 if (MaskLength
< 31) {
678 if (((Ip
&~NetMask
) == ~NetMask
) || ((Ip
&~NetMask
) == 0)) {
687 Check whether the incoming IPv6 address is a valid unicast address.
689 ASSERT if Ip6 is NULL.
691 If the address is a multicast address has binary 0xFF at the start, it is not
692 a valid unicast address. If the address is unspecified ::, it is not a valid
693 unicast address to be assigned to any node. If the address is loopback address
694 ::1, it is also not a valid unicast address to be assigned to any physical
697 @param[in] Ip6 The IPv6 address to check against.
699 @return TRUE if Ip6 is a valid unicast address on the network, otherwise FALSE.
704 NetIp6IsValidUnicast (
705 IN EFI_IPv6_ADDRESS
*Ip6
711 ASSERT (Ip6
!= NULL
);
713 if (Ip6
->Addr
[0] == 0xFF) {
717 for (Index
= 0; Index
< 15; Index
++) {
718 if (Ip6
->Addr
[Index
] != 0) {
723 Byte
= Ip6
->Addr
[Index
];
725 if (Byte
== 0x0 || Byte
== 0x1) {
733 Check whether the incoming Ipv6 address is the unspecified address or not.
735 ASSERT if Ip6 is NULL.
737 @param[in] Ip6 - Ip6 address, in network order.
739 @retval TRUE - Yes, unspecified
745 NetIp6IsUnspecifiedAddr (
746 IN EFI_IPv6_ADDRESS
*Ip6
751 ASSERT (Ip6
!= NULL
);
753 for (Index
= 0; Index
< 16; Index
++) {
754 if (Ip6
->Addr
[Index
] != 0) {
763 Check whether the incoming Ipv6 address is a link-local address.
765 ASSERT if Ip6 is NULL.
767 @param[in] Ip6 - Ip6 address, in network order.
769 @retval TRUE - Yes, link-local address
775 NetIp6IsLinkLocalAddr (
776 IN EFI_IPv6_ADDRESS
*Ip6
781 ASSERT (Ip6
!= NULL
);
783 if (Ip6
->Addr
[0] != 0xFE) {
787 if (Ip6
->Addr
[1] != 0x80) {
791 for (Index
= 2; Index
< 8; Index
++) {
792 if (Ip6
->Addr
[Index
] != 0) {
801 Check whether the Ipv6 address1 and address2 are on the connected network.
803 ASSERT if Ip1 or Ip2 is NULL.
804 ASSERT if PrefixLength exceeds or equals to IP6_PREFIX_MAX.
806 @param[in] Ip1 - Ip6 address1, in network order.
807 @param[in] Ip2 - Ip6 address2, in network order.
808 @param[in] PrefixLength - The prefix length of the checking net.
810 @retval TRUE - Yes, connected.
817 EFI_IPv6_ADDRESS
*Ip1
,
818 EFI_IPv6_ADDRESS
*Ip2
,
826 ASSERT ((Ip1
!= NULL
) && (Ip2
!= NULL
) && (PrefixLength
< IP6_PREFIX_MAX
));
828 if (PrefixLength
== 0) {
832 Byte
= (UINT8
) (PrefixLength
/ 8);
833 Bit
= (UINT8
) (PrefixLength
% 8);
835 if (CompareMem (Ip1
, Ip2
, Byte
) != 0) {
840 Mask
= (UINT8
) (0xFF << (8 - Bit
));
846 if ((Ip1
->Addr
[Byte
] & Mask
) != (Ip2
->Addr
[Byte
] & Mask
)) {
856 Switches the endianess of an IPv6 address
858 ASSERT if Ip6 is NULL.
860 This function swaps the bytes in a 128-bit IPv6 address to switch the value
861 from little endian to big endian or vice versa. The byte swapped value is
864 @param Ip6 Points to an IPv6 address
866 @return The byte swapped IPv6 address.
872 EFI_IPv6_ADDRESS
*Ip6
878 ASSERT (Ip6
!= NULL
);
880 CopyMem (&High
, Ip6
, sizeof (UINT64
));
881 CopyMem (&Low
, &Ip6
->Addr
[8], sizeof (UINT64
));
883 High
= SwapBytes64 (High
);
884 Low
= SwapBytes64 (Low
);
886 CopyMem (Ip6
, &Low
, sizeof (UINT64
));
887 CopyMem (&Ip6
->Addr
[8], &High
, sizeof (UINT64
));
893 Initialize a random seed using current time and monotonic count.
895 Get current time and monotonic count first. Then initialize a random seed
896 based on some basic mathematics operation on the hour, day, minute, second,
897 nanosecond and year of the current time and the monotonic count value.
899 @return The random seed initialized with current time.
910 UINT64 MonotonicCount
;
912 gRT
->GetTime (&Time
, NULL
);
913 Seed
= (Time
.Hour
<< 24 | Time
.Day
<< 16 | Time
.Minute
<< 8 | Time
.Second
);
914 Seed
^= Time
.Nanosecond
;
915 Seed
^= Time
.Year
<< 7;
917 gBS
->GetNextMonotonicCount (&MonotonicCount
);
918 Seed
+= (UINT32
) MonotonicCount
;
925 Extract a UINT32 from a byte stream.
927 ASSERT if Buf is NULL.
929 Copy a UINT32 from a byte stream, then converts it from Network
930 byte order to host byte order. Use this function to avoid alignment error.
932 @param[in] Buf The buffer to extract the UINT32.
934 @return The UINT32 extracted.
945 ASSERT (Buf
!= NULL
);
947 CopyMem (&Value
, Buf
, sizeof (UINT32
));
948 return NTOHL (Value
);
953 Put a UINT32 to the byte stream in network byte order.
955 ASSERT if Buf is NULL.
957 Converts a UINT32 from host byte order to network byte order. Then copy it to the
960 @param[in, out] Buf The buffer to put the UINT32.
961 @param[in] Data The data to be converted and put into the byte stream.
971 ASSERT (Buf
!= NULL
);
974 CopyMem (Buf
, &Data
, sizeof (UINT32
));
979 Remove the first node entry on the list, and return the removed node entry.
981 Removes the first node Entry from a doubly linked list. It is up to the caller of
982 this function to release the memory used by the first node if that is required. On
983 exit, the removed node is returned.
985 If Head is NULL, then ASSERT().
986 If Head was not initialized, then ASSERT().
987 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
988 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
991 @param[in, out] Head The list header.
993 @return The first node entry that is removed from the list, NULL if the list is empty.
999 IN OUT LIST_ENTRY
*Head
1004 ASSERT (Head
!= NULL
);
1006 if (IsListEmpty (Head
)) {
1010 First
= Head
->ForwardLink
;
1011 Head
->ForwardLink
= First
->ForwardLink
;
1012 First
->ForwardLink
->BackLink
= Head
;
1015 First
->ForwardLink
= (LIST_ENTRY
*) NULL
;
1016 First
->BackLink
= (LIST_ENTRY
*) NULL
;
1024 Remove the last node entry on the list and and return the removed node entry.
1026 Removes the last node entry from a doubly linked list. It is up to the caller of
1027 this function to release the memory used by the first node if that is required. On
1028 exit, the removed node is returned.
1030 If Head is NULL, then ASSERT().
1031 If Head was not initialized, then ASSERT().
1032 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
1033 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
1036 @param[in, out] Head The list head.
1038 @return The last node entry that is removed from the list, NULL if the list is empty.
1044 IN OUT LIST_ENTRY
*Head
1049 ASSERT (Head
!= NULL
);
1051 if (IsListEmpty (Head
)) {
1055 Last
= Head
->BackLink
;
1056 Head
->BackLink
= Last
->BackLink
;
1057 Last
->BackLink
->ForwardLink
= Head
;
1060 Last
->ForwardLink
= (LIST_ENTRY
*) NULL
;
1061 Last
->BackLink
= (LIST_ENTRY
*) NULL
;
1069 Insert a new node entry after a designated node entry of a doubly linked list.
1071 ASSERT if PrevEntry or NewEntry is NULL.
1073 Inserts a new node entry donated by NewEntry after the node entry donated by PrevEntry
1074 of the doubly linked list.
1076 @param[in, out] PrevEntry The previous entry to insert after.
1077 @param[in, out] NewEntry The new entry to insert.
1082 NetListInsertAfter (
1083 IN OUT LIST_ENTRY
*PrevEntry
,
1084 IN OUT LIST_ENTRY
*NewEntry
1087 ASSERT (PrevEntry
!= NULL
&& NewEntry
!= NULL
);
1089 NewEntry
->BackLink
= PrevEntry
;
1090 NewEntry
->ForwardLink
= PrevEntry
->ForwardLink
;
1091 PrevEntry
->ForwardLink
->BackLink
= NewEntry
;
1092 PrevEntry
->ForwardLink
= NewEntry
;
1097 Insert a new node entry before a designated node entry of a doubly linked list.
1099 ASSERT if PostEntry or NewEntry is NULL.
1101 Inserts a new node entry donated by NewEntry after the node entry donated by PostEntry
1102 of the doubly linked list.
1104 @param[in, out] PostEntry The entry to insert before.
1105 @param[in, out] NewEntry The new entry to insert.
1110 NetListInsertBefore (
1111 IN OUT LIST_ENTRY
*PostEntry
,
1112 IN OUT LIST_ENTRY
*NewEntry
1115 ASSERT (PostEntry
!= NULL
&& NewEntry
!= NULL
);
1117 NewEntry
->ForwardLink
= PostEntry
;
1118 NewEntry
->BackLink
= PostEntry
->BackLink
;
1119 PostEntry
->BackLink
->ForwardLink
= NewEntry
;
1120 PostEntry
->BackLink
= NewEntry
;
1124 Safe destroy nodes in a linked list, and return the length of the list after all possible operations finished.
1126 Destroy network child instance list by list traversals is not safe due to graph dependencies between nodes.
1127 This function performs a safe traversal to destroy these nodes by checking to see if the node being destroyed
1128 has been removed from the list or not.
1129 If it has been removed, then restart the traversal from the head.
1130 If it hasn't been removed, then continue with the next node directly.
1131 This function will end the iterate and return the CallBack's last return value if error happens,
1132 or retrun EFI_SUCCESS if 2 complete passes are made with no changes in the number of children in the list.
1134 @param[in] List The head of the list.
1135 @param[in] CallBack Pointer to the callback function to destroy one node in the list.
1136 @param[in] Context Pointer to the callback function's context: corresponds to the
1137 parameter Context in NET_DESTROY_LINK_LIST_CALLBACK.
1138 @param[out] ListLength The length of the link list if the function returns successfully.
1140 @retval EFI_SUCCESS Two complete passes are made with no changes in the number of children.
1141 @retval EFI_INVALID_PARAMETER The input parameter is invalid.
1142 @retval Others Return the CallBack's last return value.
1147 NetDestroyLinkList (
1148 IN LIST_ENTRY
*List
,
1149 IN NET_DESTROY_LINK_LIST_CALLBACK CallBack
,
1150 IN VOID
*Context
, OPTIONAL
1151 OUT UINTN
*ListLength OPTIONAL
1154 UINTN PreviousLength
;
1160 if (List
== NULL
|| CallBack
== NULL
) {
1161 return EFI_INVALID_PARAMETER
;
1166 PreviousLength
= Length
;
1167 Entry
= GetFirstNode (List
);
1168 while (!IsNull (List
, Entry
)) {
1169 Status
= CallBack (Entry
, Context
);
1170 if (EFI_ERROR (Status
)) {
1174 // Walk through the list to see whether the Entry has been removed or not.
1175 // If the Entry still exists, just try to destroy the next one.
1176 // If not, go back to the start point to iterate the list again.
1178 for (Ptr
= List
->ForwardLink
; Ptr
!= List
; Ptr
= Ptr
->ForwardLink
) {
1184 Entry
= GetNextNode (List
, Entry
);
1186 Entry
= GetFirstNode (List
);
1189 for (Length
= 0, Ptr
= List
->ForwardLink
; Ptr
!= List
; Length
++, Ptr
= Ptr
->ForwardLink
);
1190 } while (Length
!= PreviousLength
);
1192 if (ListLength
!= NULL
) {
1193 *ListLength
= Length
;
1199 This function checks the input Handle to see if it's one of these handles in ChildHandleBuffer.
1201 @param[in] Handle Handle to be checked.
1202 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer.
1203 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
1204 if NumberOfChildren is 0.
1206 @retval TRUE Found the input Handle in ChildHandleBuffer.
1207 @retval FALSE Can't find the input Handle in ChildHandleBuffer.
1212 NetIsInHandleBuffer (
1213 IN EFI_HANDLE Handle
,
1214 IN UINTN NumberOfChildren
,
1215 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
1220 if (NumberOfChildren
== 0 || ChildHandleBuffer
== NULL
) {
1224 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
1225 if (Handle
== ChildHandleBuffer
[Index
]) {
1235 Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.
1237 Initialize the forward and backward links of two head nodes donated by Map->Used
1238 and Map->Recycled of two doubly linked lists.
1239 Initializes the count of the <Key, Value> pairs in the netmap to zero.
1241 If Map is NULL, then ASSERT().
1242 If the address of Map->Used is NULL, then ASSERT().
1243 If the address of Map->Recycled is NULl, then ASSERT().
1245 @param[in, out] Map The netmap to initialize.
1254 ASSERT (Map
!= NULL
);
1256 InitializeListHead (&Map
->Used
);
1257 InitializeListHead (&Map
->Recycled
);
1263 To clean up the netmap, that is, release allocated memories.
1265 Removes all nodes of the Used doubly linked list and free memory of all related netmap items.
1266 Removes all nodes of the Recycled doubly linked list and free memory of all related netmap items.
1267 The number of the <Key, Value> pairs in the netmap is set to be zero.
1269 If Map is NULL, then ASSERT().
1271 @param[in, out] Map The netmap to clean up.
1284 ASSERT (Map
!= NULL
);
1286 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &Map
->Used
) {
1287 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1289 RemoveEntryList (&Item
->Link
);
1292 gBS
->FreePool (Item
);
1295 ASSERT ((Map
->Count
== 0) && IsListEmpty (&Map
->Used
));
1297 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &Map
->Recycled
) {
1298 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1300 RemoveEntryList (&Item
->Link
);
1301 gBS
->FreePool (Item
);
1304 ASSERT (IsListEmpty (&Map
->Recycled
));
1309 Test whether the netmap is empty and return true if it is.
1311 If the number of the <Key, Value> pairs in the netmap is zero, return TRUE.
1313 If Map is NULL, then ASSERT().
1315 @param[in] Map The net map to test.
1317 @return TRUE if the netmap is empty, otherwise FALSE.
1326 ASSERT (Map
!= NULL
);
1327 return (BOOLEAN
) (Map
->Count
== 0);
1332 Return the number of the <Key, Value> pairs in the netmap.
1334 If Map is NULL, then ASSERT().
1336 @param[in] Map The netmap to get the entry number.
1338 @return The entry number in the netmap.
1347 ASSERT (Map
!= NULL
);
1353 Return one allocated item.
1355 If the Recycled doubly linked list of the netmap is empty, it will try to allocate
1356 a batch of items if there are enough resources and add corresponding nodes to the begining
1357 of the Recycled doubly linked list of the netmap. Otherwise, it will directly remove
1358 the fist node entry of the Recycled doubly linked list and return the corresponding item.
1360 If Map is NULL, then ASSERT().
1362 @param[in, out] Map The netmap to allocate item for.
1364 @return The allocated item. If NULL, the
1365 allocation failed due to resource limit.
1377 ASSERT (Map
!= NULL
);
1379 Head
= &Map
->Recycled
;
1381 if (IsListEmpty (Head
)) {
1382 for (Index
= 0; Index
< NET_MAP_INCREAMENT
; Index
++) {
1383 Item
= AllocatePool (sizeof (NET_MAP_ITEM
));
1393 InsertHeadList (Head
, &Item
->Link
);
1397 Item
= NET_LIST_HEAD (Head
, NET_MAP_ITEM
, Link
);
1398 NetListRemoveHead (Head
);
1405 Allocate an item to save the <Key, Value> pair to the head of the netmap.
1407 Allocate an item to save the <Key, Value> pair and add corresponding node entry
1408 to the beginning of the Used doubly linked list. The number of the <Key, Value>
1409 pairs in the netmap increase by 1.
1411 If Map is NULL, then ASSERT().
1412 If Key is NULL, then ASSERT().
1414 @param[in, out] Map The netmap to insert into.
1415 @param[in] Key The user's key.
1416 @param[in] Value The user's value for the key.
1418 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
1419 @retval EFI_SUCCESS The item is inserted to the head.
1425 IN OUT NET_MAP
*Map
,
1427 IN VOID
*Value OPTIONAL
1432 ASSERT (Map
!= NULL
&& Key
!= NULL
);
1434 Item
= NetMapAllocItem (Map
);
1437 return EFI_OUT_OF_RESOURCES
;
1441 Item
->Value
= Value
;
1442 InsertHeadList (&Map
->Used
, &Item
->Link
);
1450 Allocate an item to save the <Key, Value> pair to the tail of the netmap.
1452 Allocate an item to save the <Key, Value> pair and add corresponding node entry
1453 to the tail of the Used doubly linked list. The number of the <Key, Value>
1454 pairs in the netmap increase by 1.
1456 If Map is NULL, then ASSERT().
1457 If Key is NULL, then ASSERT().
1459 @param[in, out] Map The netmap to insert into.
1460 @param[in] Key The user's key.
1461 @param[in] Value The user's value for the key.
1463 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
1464 @retval EFI_SUCCESS The item is inserted to the tail.
1470 IN OUT NET_MAP
*Map
,
1472 IN VOID
*Value OPTIONAL
1477 ASSERT (Map
!= NULL
&& Key
!= NULL
);
1479 Item
= NetMapAllocItem (Map
);
1482 return EFI_OUT_OF_RESOURCES
;
1486 Item
->Value
= Value
;
1487 InsertTailList (&Map
->Used
, &Item
->Link
);
1496 Check whether the item is in the Map and return TRUE if it is.
1498 If Map is NULL, then ASSERT().
1499 If Item is NULL, then ASSERT().
1501 @param[in] Map The netmap to search within.
1502 @param[in] Item The item to search.
1504 @return TRUE if the item is in the netmap, otherwise FALSE.
1510 IN NET_MAP_ITEM
*Item
1513 LIST_ENTRY
*ListEntry
;
1515 ASSERT (Map
!= NULL
&& Item
!= NULL
);
1517 NET_LIST_FOR_EACH (ListEntry
, &Map
->Used
) {
1518 if (ListEntry
== &Item
->Link
) {
1528 Find the key in the netmap and returns the point to the item contains the Key.
1530 Iterate the Used doubly linked list of the netmap to get every item. Compare the key of every
1531 item with the key to search. It returns the point to the item contains the Key if found.
1533 If Map is NULL, then ASSERT().
1534 If Key is NULL, then ASSERT().
1536 @param[in] Map The netmap to search within.
1537 @param[in] Key The key to search.
1539 @return The point to the item contains the Key, or NULL if Key isn't in the map.
1552 ASSERT (Map
!= NULL
&& Key
!= NULL
);
1554 NET_LIST_FOR_EACH (Entry
, &Map
->Used
) {
1555 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1557 if (Item
->Key
== Key
) {
1567 Remove the node entry of the item from the netmap and return the key of the removed item.
1569 Remove the node entry of the item from the Used doubly linked list of the netmap.
1570 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1571 entry of the item to the Recycled doubly linked list of the netmap. If Value is not NULL,
1572 Value will point to the value of the item. It returns the key of the removed item.
1574 If Map is NULL, then ASSERT().
1575 If Item is NULL, then ASSERT().
1576 if item in not in the netmap, then ASSERT().
1578 @param[in, out] Map The netmap to remove the item from.
1579 @param[in, out] Item The item to remove.
1580 @param[out] Value The variable to receive the value if not NULL.
1582 @return The key of the removed item.
1588 IN OUT NET_MAP
*Map
,
1589 IN OUT NET_MAP_ITEM
*Item
,
1590 OUT VOID
**Value OPTIONAL
1593 ASSERT ((Map
!= NULL
) && (Item
!= NULL
));
1594 ASSERT (NetItemInMap (Map
, Item
));
1596 RemoveEntryList (&Item
->Link
);
1598 InsertHeadList (&Map
->Recycled
, &Item
->Link
);
1600 if (Value
!= NULL
) {
1601 *Value
= Item
->Value
;
1609 Remove the first node entry on the netmap and return the key of the removed item.
1611 Remove the first node entry from the Used doubly linked list of the netmap.
1612 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1613 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
1614 parameter Value will point to the value of the item. It returns the key of the removed item.
1616 If Map is NULL, then ASSERT().
1617 If the Used doubly linked list is empty, then ASSERT().
1619 @param[in, out] Map The netmap to remove the head from.
1620 @param[out] Value The variable to receive the value if not NULL.
1622 @return The key of the item removed.
1628 IN OUT NET_MAP
*Map
,
1629 OUT VOID
**Value OPTIONAL
1635 // Often, it indicates a programming error to remove
1636 // the first entry in an empty list
1638 ASSERT (Map
&& !IsListEmpty (&Map
->Used
));
1640 Item
= NET_LIST_HEAD (&Map
->Used
, NET_MAP_ITEM
, Link
);
1641 RemoveEntryList (&Item
->Link
);
1643 InsertHeadList (&Map
->Recycled
, &Item
->Link
);
1645 if (Value
!= NULL
) {
1646 *Value
= Item
->Value
;
1654 Remove the last node entry on the netmap and return the key of the removed item.
1656 Remove the last node entry from the Used doubly linked list of the netmap.
1657 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1658 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
1659 parameter Value will point to the value of the item. It returns the key of the removed item.
1661 If Map is NULL, then ASSERT().
1662 If the Used doubly linked list is empty, then ASSERT().
1664 @param[in, out] Map The netmap to remove the tail from.
1665 @param[out] Value The variable to receive the value if not NULL.
1667 @return The key of the item removed.
1673 IN OUT NET_MAP
*Map
,
1674 OUT VOID
**Value OPTIONAL
1680 // Often, it indicates a programming error to remove
1681 // the last entry in an empty list
1683 ASSERT (Map
&& !IsListEmpty (&Map
->Used
));
1685 Item
= NET_LIST_TAIL (&Map
->Used
, NET_MAP_ITEM
, Link
);
1686 RemoveEntryList (&Item
->Link
);
1688 InsertHeadList (&Map
->Recycled
, &Item
->Link
);
1690 if (Value
!= NULL
) {
1691 *Value
= Item
->Value
;
1699 Iterate through the netmap and call CallBack for each item.
1701 It will continue the traverse if CallBack returns EFI_SUCCESS, otherwise, break
1702 from the loop. It returns the CallBack's last return value. This function is
1703 delete safe for the current item.
1705 If Map is NULL, then ASSERT().
1706 If CallBack is NULL, then ASSERT().
1708 @param[in] Map The Map to iterate through.
1709 @param[in] CallBack The callback function to call for each item.
1710 @param[in] Arg The opaque parameter to the callback.
1712 @retval EFI_SUCCESS There is no item in the netmap or CallBack for each item
1714 @retval Others It returns the CallBack's last return value.
1721 IN NET_MAP_CALLBACK CallBack
,
1722 IN VOID
*Arg OPTIONAL
1732 ASSERT ((Map
!= NULL
) && (CallBack
!= NULL
));
1736 if (IsListEmpty (Head
)) {
1740 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, Head
) {
1741 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1742 Result
= CallBack (Map
, Item
, Arg
);
1744 if (EFI_ERROR (Result
)) {
1754 This is the default unload handle for all the network drivers.
1756 Disconnect the driver specified by ImageHandle from all the devices in the handle database.
1757 Uninstall all the protocols installed in the driver entry point.
1759 @param[in] ImageHandle The drivers' driver image.
1761 @retval EFI_SUCCESS The image is unloaded.
1762 @retval Others Failed to unload the image.
1767 NetLibDefaultUnload (
1768 IN EFI_HANDLE ImageHandle
1772 EFI_HANDLE
*DeviceHandleBuffer
;
1773 UINTN DeviceHandleCount
;
1776 EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
;
1777 EFI_COMPONENT_NAME_PROTOCOL
*ComponentName
;
1778 EFI_COMPONENT_NAME2_PROTOCOL
*ComponentName2
;
1781 // Get the list of all the handles in the handle database.
1782 // If there is an error getting the list, then the unload
1785 Status
= gBS
->LocateHandleBuffer (
1793 if (EFI_ERROR (Status
)) {
1797 for (Index
= 0; Index
< DeviceHandleCount
; Index
++) {
1798 Status
= gBS
->HandleProtocol (
1799 DeviceHandleBuffer
[Index
],
1800 &gEfiDriverBindingProtocolGuid
,
1801 (VOID
**) &DriverBinding
1803 if (EFI_ERROR (Status
)) {
1807 if (DriverBinding
->ImageHandle
!= ImageHandle
) {
1812 // Disconnect the driver specified by ImageHandle from all
1813 // the devices in the handle database.
1815 for (Index2
= 0; Index2
< DeviceHandleCount
; Index2
++) {
1816 Status
= gBS
->DisconnectController (
1817 DeviceHandleBuffer
[Index2
],
1818 DriverBinding
->DriverBindingHandle
,
1824 // Uninstall all the protocols installed in the driver entry point
1826 gBS
->UninstallProtocolInterface (
1827 DriverBinding
->DriverBindingHandle
,
1828 &gEfiDriverBindingProtocolGuid
,
1832 Status
= gBS
->HandleProtocol (
1833 DeviceHandleBuffer
[Index
],
1834 &gEfiComponentNameProtocolGuid
,
1835 (VOID
**) &ComponentName
1837 if (!EFI_ERROR (Status
)) {
1838 gBS
->UninstallProtocolInterface (
1839 DriverBinding
->DriverBindingHandle
,
1840 &gEfiComponentNameProtocolGuid
,
1845 Status
= gBS
->HandleProtocol (
1846 DeviceHandleBuffer
[Index
],
1847 &gEfiComponentName2ProtocolGuid
,
1848 (VOID
**) &ComponentName2
1850 if (!EFI_ERROR (Status
)) {
1851 gBS
->UninstallProtocolInterface (
1852 DriverBinding
->DriverBindingHandle
,
1853 &gEfiComponentName2ProtocolGuid
,
1860 // Free the buffer containing the list of handles from the handle database
1862 if (DeviceHandleBuffer
!= NULL
) {
1863 gBS
->FreePool (DeviceHandleBuffer
);
1872 Create a child of the service that is identified by ServiceBindingGuid.
1874 Get the ServiceBinding Protocol first, then use it to create a child.
1876 If ServiceBindingGuid is NULL, then ASSERT().
1877 If ChildHandle is NULL, then ASSERT().
1879 @param[in] Controller The controller which has the service installed.
1880 @param[in] Image The image handle used to open service.
1881 @param[in] ServiceBindingGuid The service's Guid.
1882 @param[in, out] ChildHandle The handle to receive the create child.
1884 @retval EFI_SUCCESS The child is successfully created.
1885 @retval Others Failed to create the child.
1890 NetLibCreateServiceChild (
1891 IN EFI_HANDLE Controller
,
1892 IN EFI_HANDLE Image
,
1893 IN EFI_GUID
*ServiceBindingGuid
,
1894 IN OUT EFI_HANDLE
*ChildHandle
1898 EFI_SERVICE_BINDING_PROTOCOL
*Service
;
1901 ASSERT ((ServiceBindingGuid
!= NULL
) && (ChildHandle
!= NULL
));
1904 // Get the ServiceBinding Protocol
1906 Status
= gBS
->OpenProtocol (
1912 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1915 if (EFI_ERROR (Status
)) {
1922 Status
= Service
->CreateChild (Service
, ChildHandle
);
1928 Destroy a child of the service that is identified by ServiceBindingGuid.
1930 Get the ServiceBinding Protocol first, then use it to destroy a child.
1932 If ServiceBindingGuid is NULL, then ASSERT().
1934 @param[in] Controller The controller which has the service installed.
1935 @param[in] Image The image handle used to open service.
1936 @param[in] ServiceBindingGuid The service's Guid.
1937 @param[in] ChildHandle The child to destroy.
1939 @retval EFI_SUCCESS The child is successfully destroyed.
1940 @retval Others Failed to destroy the child.
1945 NetLibDestroyServiceChild (
1946 IN EFI_HANDLE Controller
,
1947 IN EFI_HANDLE Image
,
1948 IN EFI_GUID
*ServiceBindingGuid
,
1949 IN EFI_HANDLE ChildHandle
1953 EFI_SERVICE_BINDING_PROTOCOL
*Service
;
1955 ASSERT (ServiceBindingGuid
!= NULL
);
1958 // Get the ServiceBinding Protocol
1960 Status
= gBS
->OpenProtocol (
1966 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1969 if (EFI_ERROR (Status
)) {
1974 // destroy the child
1976 Status
= Service
->DestroyChild (Service
, ChildHandle
);
1981 Get handle with Simple Network Protocol installed on it.
1983 There should be MNP Service Binding Protocol installed on the input ServiceHandle.
1984 If Simple Network Protocol is already installed on the ServiceHandle, the
1985 ServiceHandle will be returned. If SNP is not installed on the ServiceHandle,
1986 try to find its parent handle with SNP installed.
1988 @param[in] ServiceHandle The handle where network service binding protocols are
1990 @param[out] Snp The pointer to store the address of the SNP instance.
1991 This is an optional parameter that may be NULL.
1993 @return The SNP handle, or NULL if not found.
1998 NetLibGetSnpHandle (
1999 IN EFI_HANDLE ServiceHandle
,
2000 OUT EFI_SIMPLE_NETWORK_PROTOCOL
**Snp OPTIONAL
2004 EFI_SIMPLE_NETWORK_PROTOCOL
*SnpInstance
;
2005 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2006 EFI_HANDLE SnpHandle
;
2009 // Try to open SNP from ServiceHandle
2012 Status
= gBS
->HandleProtocol (ServiceHandle
, &gEfiSimpleNetworkProtocolGuid
, (VOID
**) &SnpInstance
);
2013 if (!EFI_ERROR (Status
)) {
2017 return ServiceHandle
;
2021 // Failed to open SNP, try to get SNP handle by LocateDevicePath()
2023 DevicePath
= DevicePathFromHandle (ServiceHandle
);
2024 if (DevicePath
== NULL
) {
2029 Status
= gBS
->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid
, &DevicePath
, &SnpHandle
);
2030 if (EFI_ERROR (Status
)) {
2032 // Failed to find SNP handle
2037 Status
= gBS
->HandleProtocol (SnpHandle
, &gEfiSimpleNetworkProtocolGuid
, (VOID
**) &SnpInstance
);
2038 if (!EFI_ERROR (Status
)) {
2049 Retrieve VLAN ID of a VLAN device handle.
2051 Search VLAN device path node in Device Path of specified ServiceHandle and
2052 return its VLAN ID. If no VLAN device path node found, then this ServiceHandle
2053 is not a VLAN device handle, and 0 will be returned.
2055 @param[in] ServiceHandle The handle where network service binding protocols are
2058 @return VLAN ID of the device handle, or 0 if not a VLAN device.
2064 IN EFI_HANDLE ServiceHandle
2067 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2068 EFI_DEVICE_PATH_PROTOCOL
*Node
;
2070 DevicePath
= DevicePathFromHandle (ServiceHandle
);
2071 if (DevicePath
== NULL
) {
2076 while (!IsDevicePathEnd (Node
)) {
2077 if (Node
->Type
== MESSAGING_DEVICE_PATH
&& Node
->SubType
== MSG_VLAN_DP
) {
2078 return ((VLAN_DEVICE_PATH
*) Node
)->VlanId
;
2080 Node
= NextDevicePathNode (Node
);
2087 Find VLAN device handle with specified VLAN ID.
2089 The VLAN child device handle is created by VLAN Config Protocol on ControllerHandle.
2090 This function will append VLAN device path node to the parent device path,
2091 and then use LocateDevicePath() to find the correct VLAN device handle.
2093 @param[in] ControllerHandle The handle where network service binding protocols are
2095 @param[in] VlanId The configured VLAN ID for the VLAN device.
2097 @return The VLAN device handle, or NULL if not found.
2102 NetLibGetVlanHandle (
2103 IN EFI_HANDLE ControllerHandle
,
2107 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
2108 EFI_DEVICE_PATH_PROTOCOL
*VlanDevicePath
;
2109 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2110 VLAN_DEVICE_PATH VlanNode
;
2113 ParentDevicePath
= DevicePathFromHandle (ControllerHandle
);
2114 if (ParentDevicePath
== NULL
) {
2119 // Construct VLAN device path
2121 CopyMem (&VlanNode
, &mNetVlanDevicePathTemplate
, sizeof (VLAN_DEVICE_PATH
));
2122 VlanNode
.VlanId
= VlanId
;
2123 VlanDevicePath
= AppendDevicePathNode (
2125 (EFI_DEVICE_PATH_PROTOCOL
*) &VlanNode
2127 if (VlanDevicePath
== NULL
) {
2132 // Find VLAN device handle
2135 DevicePath
= VlanDevicePath
;
2136 gBS
->LocateDevicePath (
2137 &gEfiDevicePathProtocolGuid
,
2141 if (!IsDevicePathEnd (DevicePath
)) {
2143 // Device path is not exactly match
2148 FreePool (VlanDevicePath
);
2153 Get MAC address associated with the network service handle.
2155 If MacAddress is NULL, then ASSERT().
2156 If AddressSize is NULL, then ASSERT().
2158 There should be MNP Service Binding Protocol installed on the input ServiceHandle.
2159 If SNP is installed on the ServiceHandle or its parent handle, MAC address will
2160 be retrieved from SNP. If no SNP found, try to get SNP mode data use MNP.
2162 @param[in] ServiceHandle The handle where network service binding protocols are
2164 @param[out] MacAddress The pointer to store the returned MAC address.
2165 @param[out] AddressSize The length of returned MAC address.
2167 @retval EFI_SUCCESS MAC address is returned successfully.
2168 @retval Others Failed to get SNP mode data.
2173 NetLibGetMacAddress (
2174 IN EFI_HANDLE ServiceHandle
,
2175 OUT EFI_MAC_ADDRESS
*MacAddress
,
2176 OUT UINTN
*AddressSize
2180 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2181 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
2182 EFI_SIMPLE_NETWORK_MODE SnpModeData
;
2183 EFI_MANAGED_NETWORK_PROTOCOL
*Mnp
;
2184 EFI_SERVICE_BINDING_PROTOCOL
*MnpSb
;
2185 EFI_HANDLE SnpHandle
;
2186 EFI_HANDLE MnpChildHandle
;
2188 ASSERT (MacAddress
!= NULL
);
2189 ASSERT (AddressSize
!= NULL
);
2192 // Try to get SNP handle
2195 SnpHandle
= NetLibGetSnpHandle (ServiceHandle
, &Snp
);
2196 if (SnpHandle
!= NULL
) {
2198 // SNP found, use it directly
2200 SnpMode
= Snp
->Mode
;
2203 // Failed to get SNP handle, try to get MAC address from MNP
2205 MnpChildHandle
= NULL
;
2206 Status
= gBS
->HandleProtocol (
2208 &gEfiManagedNetworkServiceBindingProtocolGuid
,
2211 if (EFI_ERROR (Status
)) {
2216 // Create a MNP child
2218 Status
= MnpSb
->CreateChild (MnpSb
, &MnpChildHandle
);
2219 if (EFI_ERROR (Status
)) {
2224 // Open MNP protocol
2226 Status
= gBS
->HandleProtocol (
2228 &gEfiManagedNetworkProtocolGuid
,
2231 if (EFI_ERROR (Status
)) {
2232 MnpSb
->DestroyChild (MnpSb
, MnpChildHandle
);
2237 // Try to get SNP mode from MNP
2239 Status
= Mnp
->GetModeData (Mnp
, NULL
, &SnpModeData
);
2240 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_STARTED
)) {
2241 MnpSb
->DestroyChild (MnpSb
, MnpChildHandle
);
2244 SnpMode
= &SnpModeData
;
2247 // Destroy the MNP child
2249 MnpSb
->DestroyChild (MnpSb
, MnpChildHandle
);
2252 *AddressSize
= SnpMode
->HwAddressSize
;
2253 CopyMem (MacAddress
->Addr
, SnpMode
->CurrentAddress
.Addr
, SnpMode
->HwAddressSize
);
2259 Convert MAC address of the NIC associated with specified Service Binding Handle
2260 to a unicode string. Callers are responsible for freeing the string storage.
2262 If MacString is NULL, then ASSERT().
2264 Locate simple network protocol associated with the Service Binding Handle and
2265 get the mac address from SNP. Then convert the mac address into a unicode
2266 string. It takes 2 unicode characters to represent a 1 byte binary buffer.
2267 Plus one unicode character for the null-terminator.
2269 @param[in] ServiceHandle The handle where network service binding protocol is
2271 @param[in] ImageHandle The image handle used to act as the agent handle to
2272 get the simple network protocol. This parameter is
2273 optional and may be NULL.
2274 @param[out] MacString The pointer to store the address of the string
2275 representation of the mac address.
2277 @retval EFI_SUCCESS Convert the mac address a unicode string successfully.
2278 @retval EFI_OUT_OF_RESOURCES There are not enough memory resource.
2279 @retval Others Failed to open the simple network protocol.
2284 NetLibGetMacString (
2285 IN EFI_HANDLE ServiceHandle
,
2286 IN EFI_HANDLE ImageHandle
, OPTIONAL
2287 OUT CHAR16
**MacString
2291 EFI_MAC_ADDRESS MacAddress
;
2293 UINTN HwAddressSize
;
2299 ASSERT (MacString
!= NULL
);
2302 // Get MAC address of the network device
2304 Status
= NetLibGetMacAddress (ServiceHandle
, &MacAddress
, &HwAddressSize
);
2305 if (EFI_ERROR (Status
)) {
2310 // It takes 2 unicode characters to represent a 1 byte binary buffer.
2311 // If VLAN is configured, it will need extra 5 characters like "\0005".
2312 // Plus one unicode character for the null-terminator.
2314 BufferSize
= (2 * HwAddressSize
+ 5 + 1) * sizeof (CHAR16
);
2315 String
= AllocateZeroPool (BufferSize
);
2316 if (String
== NULL
) {
2317 return EFI_OUT_OF_RESOURCES
;
2319 *MacString
= String
;
2322 // Convert the MAC address into a unicode string.
2324 HwAddress
= &MacAddress
.Addr
[0];
2325 for (Index
= 0; Index
< HwAddressSize
; Index
++) {
2326 UnicodeValueToStringS (
2328 BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
),
2329 PREFIX_ZERO
| RADIX_HEX
,
2333 String
+= StrnLenS (String
, (BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
)) / sizeof (CHAR16
));
2337 // Append VLAN ID if any
2339 VlanId
= NetLibGetVlanId (ServiceHandle
);
2342 UnicodeValueToStringS (
2344 BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
),
2345 PREFIX_ZERO
| RADIX_HEX
,
2349 String
+= StrnLenS (String
, (BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
)) / sizeof (CHAR16
));
2353 // Null terminate the Unicode string
2361 Detect media status for specified network device.
2363 If MediaPresent is NULL, then ASSERT().
2365 The underlying UNDI driver may or may not support reporting media status from
2366 GET_STATUS command (PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED). This routine
2367 will try to invoke Snp->GetStatus() to get the media status: if media already
2368 present, it return directly; if media not present, it will stop SNP and then
2369 restart SNP to get the latest media status, this give chance to get the correct
2370 media status for old UNDI driver which doesn't support reporting media status
2371 from GET_STATUS command.
2372 Note: there will be two limitations for current algorithm:
2373 1) for UNDI with this capability, in case of cable is not attached, there will
2374 be an redundant Stop/Start() process;
2375 2) for UNDI without this capability, in case that network cable is attached when
2376 Snp->Initialize() is invoked while network cable is unattached later,
2377 NetLibDetectMedia() will report MediaPresent as TRUE, causing upper layer
2378 apps to wait for timeout time.
2380 @param[in] ServiceHandle The handle where network service binding protocols are
2382 @param[out] MediaPresent The pointer to store the media status.
2384 @retval EFI_SUCCESS Media detection success.
2385 @retval EFI_INVALID_PARAMETER ServiceHandle is not valid network device handle.
2386 @retval EFI_UNSUPPORTED Network device does not support media detection.
2387 @retval EFI_DEVICE_ERROR SNP is in unknown state.
2393 IN EFI_HANDLE ServiceHandle
,
2394 OUT BOOLEAN
*MediaPresent
2398 EFI_HANDLE SnpHandle
;
2399 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2400 UINT32 InterruptStatus
;
2402 EFI_MAC_ADDRESS
*MCastFilter
;
2403 UINT32 MCastFilterCount
;
2404 UINT32 EnableFilterBits
;
2405 UINT32 DisableFilterBits
;
2406 BOOLEAN ResetMCastFilters
;
2408 ASSERT (MediaPresent
!= NULL
);
2414 SnpHandle
= NetLibGetSnpHandle (ServiceHandle
, &Snp
);
2415 if (SnpHandle
== NULL
) {
2416 return EFI_INVALID_PARAMETER
;
2420 // Check whether SNP support media detection
2422 if (!Snp
->Mode
->MediaPresentSupported
) {
2423 return EFI_UNSUPPORTED
;
2427 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
2429 Status
= Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
2430 if (EFI_ERROR (Status
)) {
2434 if (Snp
->Mode
->MediaPresent
) {
2436 // Media is present, return directly
2438 *MediaPresent
= TRUE
;
2443 // Till now, GetStatus() report no media; while, in case UNDI not support
2444 // reporting media status from GetStatus(), this media status may be incorrect.
2445 // So, we will stop SNP and then restart it to get the correct media status.
2447 OldState
= Snp
->Mode
->State
;
2448 if (OldState
>= EfiSimpleNetworkMaxState
) {
2449 return EFI_DEVICE_ERROR
;
2454 if (OldState
== EfiSimpleNetworkInitialized
) {
2456 // SNP is already in use, need Shutdown/Stop and then Start/Initialize
2460 // Backup current SNP receive filter settings
2462 EnableFilterBits
= Snp
->Mode
->ReceiveFilterSetting
;
2463 DisableFilterBits
= Snp
->Mode
->ReceiveFilterMask
^ EnableFilterBits
;
2465 ResetMCastFilters
= TRUE
;
2466 MCastFilterCount
= Snp
->Mode
->MCastFilterCount
;
2467 if (MCastFilterCount
!= 0) {
2468 MCastFilter
= AllocateCopyPool (
2469 MCastFilterCount
* sizeof (EFI_MAC_ADDRESS
),
2470 Snp
->Mode
->MCastFilter
2472 ASSERT (MCastFilter
!= NULL
);
2473 if (MCastFilter
== NULL
) {
2474 Status
= EFI_OUT_OF_RESOURCES
;
2478 ResetMCastFilters
= FALSE
;
2482 // Shutdown/Stop the simple network
2484 Status
= Snp
->Shutdown (Snp
);
2485 if (!EFI_ERROR (Status
)) {
2486 Status
= Snp
->Stop (Snp
);
2488 if (EFI_ERROR (Status
)) {
2493 // Start/Initialize the simple network
2495 Status
= Snp
->Start (Snp
);
2496 if (!EFI_ERROR (Status
)) {
2497 Status
= Snp
->Initialize (Snp
, 0, 0);
2499 if (EFI_ERROR (Status
)) {
2504 // Here we get the correct media status
2506 *MediaPresent
= Snp
->Mode
->MediaPresent
;
2509 // Restore SNP receive filter settings
2511 Status
= Snp
->ReceiveFilters (
2520 if (MCastFilter
!= NULL
) {
2521 FreePool (MCastFilter
);
2528 // SNP is not in use, it's in state of EfiSimpleNetworkStopped or EfiSimpleNetworkStarted
2530 if (OldState
== EfiSimpleNetworkStopped
) {
2532 // SNP not start yet, start it
2534 Status
= Snp
->Start (Snp
);
2535 if (EFI_ERROR (Status
)) {
2541 // Initialize the simple network
2543 Status
= Snp
->Initialize (Snp
, 0, 0);
2544 if (EFI_ERROR (Status
)) {
2545 Status
= EFI_DEVICE_ERROR
;
2550 // Here we get the correct media status
2552 *MediaPresent
= Snp
->Mode
->MediaPresent
;
2555 // Shut down the simple network
2557 Snp
->Shutdown (Snp
);
2560 if (OldState
== EfiSimpleNetworkStopped
) {
2562 // Original SNP sate is Stopped, restore to original state
2567 if (MCastFilter
!= NULL
) {
2568 FreePool (MCastFilter
);
2576 Detect media state for a network device. This routine will wait for a period of time at
2577 a specified checking interval when a certain network is under connecting until connection
2578 process finishs or timeout. If Aip protocol is supported by low layer drivers, three kinds
2579 of media states can be detected: EFI_SUCCESS, EFI_NOT_READY and EFI_NO_MEDIA, represents
2580 connected state, connecting state and no media state respectively. When function detects
2581 the current state is EFI_NOT_READY, it will loop to wait for next time's check until state
2582 turns to be EFI_SUCCESS or EFI_NO_MEDIA. If Aip protocol is not supported, function will
2583 call NetLibDetectMedia() and return state directly.
2585 @param[in] ServiceHandle The handle where network service binding protocols are
2587 @param[in] Timeout The maximum number of 100ns units to wait when network
2588 is connecting. Zero value means detect once and return
2590 @param[out] MediaState The pointer to the detected media state.
2592 @retval EFI_SUCCESS Media detection success.
2593 @retval EFI_INVALID_PARAMETER ServiceHandle is not a valid network device handle or
2594 MediaState pointer is NULL.
2595 @retval EFI_DEVICE_ERROR A device error occurred.
2596 @retval EFI_TIMEOUT Network is connecting but timeout.
2601 NetLibDetectMediaWaitTimeout (
2602 IN EFI_HANDLE ServiceHandle
,
2604 OUT EFI_STATUS
*MediaState
2608 EFI_HANDLE SnpHandle
;
2609 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2610 EFI_ADAPTER_INFORMATION_PROTOCOL
*Aip
;
2611 EFI_ADAPTER_INFO_MEDIA_STATE
*MediaInfo
;
2612 BOOLEAN MediaPresent
;
2614 EFI_STATUS TimerStatus
;
2616 UINT64 TimeRemained
;
2618 if (MediaState
== NULL
) {
2619 return EFI_INVALID_PARAMETER
;
2621 *MediaState
= EFI_SUCCESS
;
2628 SnpHandle
= NetLibGetSnpHandle (ServiceHandle
, &Snp
);
2629 if (SnpHandle
== NULL
) {
2630 return EFI_INVALID_PARAMETER
;
2633 Status
= gBS
->HandleProtocol (
2635 &gEfiAdapterInformationProtocolGuid
,
2638 if (EFI_ERROR (Status
)) {
2640 MediaPresent
= TRUE
;
2641 Status
= NetLibDetectMedia (ServiceHandle
, &MediaPresent
);
2642 if (!EFI_ERROR (Status
)) {
2644 *MediaState
= EFI_SUCCESS
;
2646 *MediaState
= EFI_NO_MEDIA
;
2651 // NetLibDetectMedia doesn't support EFI_NOT_READY status, return now!
2656 Status
= Aip
->GetInformation (
2658 &gEfiAdapterInfoMediaStateGuid
,
2659 (VOID
**) &MediaInfo
,
2662 if (!EFI_ERROR (Status
)) {
2664 *MediaState
= MediaInfo
->MediaState
;
2665 FreePool (MediaInfo
);
2666 if (*MediaState
!= EFI_NOT_READY
|| Timeout
< MEDIA_STATE_DETECT_TIME_INTERVAL
) {
2672 if (MediaInfo
!= NULL
) {
2673 FreePool (MediaInfo
);
2676 if (Status
== EFI_UNSUPPORTED
) {
2679 // If gEfiAdapterInfoMediaStateGuid is not supported, call NetLibDetectMedia to get media state!
2681 MediaPresent
= TRUE
;
2682 Status
= NetLibDetectMedia (ServiceHandle
, &MediaPresent
);
2683 if (!EFI_ERROR (Status
)) {
2685 *MediaState
= EFI_SUCCESS
;
2687 *MediaState
= EFI_NO_MEDIA
;
2697 // Loop to check media state
2701 TimeRemained
= Timeout
;
2702 Status
= gBS
->CreateEvent (EVT_TIMER
, TPL_CALLBACK
, NULL
, NULL
, &Timer
);
2703 if (EFI_ERROR (Status
)) {
2704 return EFI_DEVICE_ERROR
;
2708 Status
= gBS
->SetTimer (
2711 MEDIA_STATE_DETECT_TIME_INTERVAL
2713 if (EFI_ERROR (Status
)) {
2714 gBS
->CloseEvent(Timer
);
2715 return EFI_DEVICE_ERROR
;
2719 TimerStatus
= gBS
->CheckEvent (Timer
);
2720 if (!EFI_ERROR (TimerStatus
)) {
2722 TimeRemained
-= MEDIA_STATE_DETECT_TIME_INTERVAL
;
2723 Status
= Aip
->GetInformation (
2725 &gEfiAdapterInfoMediaStateGuid
,
2726 (VOID
**) &MediaInfo
,
2729 if (!EFI_ERROR (Status
)) {
2731 *MediaState
= MediaInfo
->MediaState
;
2732 FreePool (MediaInfo
);
2735 if (MediaInfo
!= NULL
) {
2736 FreePool (MediaInfo
);
2738 gBS
->CloseEvent(Timer
);
2742 } while (TimerStatus
== EFI_NOT_READY
);
2743 } while (*MediaState
== EFI_NOT_READY
&& TimeRemained
>= MEDIA_STATE_DETECT_TIME_INTERVAL
);
2745 gBS
->CloseEvent(Timer
);
2746 if (*MediaState
== EFI_NOT_READY
&& TimeRemained
< MEDIA_STATE_DETECT_TIME_INTERVAL
) {
2754 Check the default address used by the IPv4 driver is static or dynamic (acquired
2757 If the controller handle does not have the EFI_IP4_CONFIG2_PROTOCOL installed, the
2758 default address is static. If failed to get the policy from Ip4 Config2 Protocol,
2759 the default address is static. Otherwise, get the result from Ip4 Config2 Protocol.
2761 @param[in] Controller The controller handle which has the EFI_IP4_CONFIG2_PROTOCOL
2762 relative with the default address to judge.
2764 @retval TRUE If the default address is static.
2765 @retval FALSE If the default address is acquired from DHCP.
2769 NetLibDefaultAddressIsStatic (
2770 IN EFI_HANDLE Controller
2774 EFI_IP4_CONFIG2_PROTOCOL
*Ip4Config2
;
2776 EFI_IP4_CONFIG2_POLICY Policy
;
2781 DataSize
= sizeof (EFI_IP4_CONFIG2_POLICY
);
2786 // Get Ip4Config2 policy.
2788 Status
= gBS
->HandleProtocol (Controller
, &gEfiIp4Config2ProtocolGuid
, (VOID
**) &Ip4Config2
);
2789 if (EFI_ERROR (Status
)) {
2793 Status
= Ip4Config2
->GetData (Ip4Config2
, Ip4Config2DataTypePolicy
, &DataSize
, &Policy
);
2794 if (EFI_ERROR (Status
)) {
2798 IsStatic
= (BOOLEAN
) (Policy
== Ip4Config2PolicyStatic
);
2806 Create an IPv4 device path node.
2808 If Node is NULL, then ASSERT().
2810 The header type of IPv4 device path node is MESSAGING_DEVICE_PATH.
2811 The header subtype of IPv4 device path node is MSG_IPv4_DP.
2812 Get other info from parameters to make up the whole IPv4 device path node.
2814 @param[in, out] Node Pointer to the IPv4 device path node.
2815 @param[in] Controller The controller handle.
2816 @param[in] LocalIp The local IPv4 address.
2817 @param[in] LocalPort The local port.
2818 @param[in] RemoteIp The remote IPv4 address.
2819 @param[in] RemotePort The remote port.
2820 @param[in] Protocol The protocol type in the IP header.
2821 @param[in] UseDefaultAddress Whether this instance is using default address or not.
2826 NetLibCreateIPv4DPathNode (
2827 IN OUT IPv4_DEVICE_PATH
*Node
,
2828 IN EFI_HANDLE Controller
,
2829 IN IP4_ADDR LocalIp
,
2830 IN UINT16 LocalPort
,
2831 IN IP4_ADDR RemoteIp
,
2832 IN UINT16 RemotePort
,
2834 IN BOOLEAN UseDefaultAddress
2837 ASSERT (Node
!= NULL
);
2839 Node
->Header
.Type
= MESSAGING_DEVICE_PATH
;
2840 Node
->Header
.SubType
= MSG_IPv4_DP
;
2841 SetDevicePathNodeLength (&Node
->Header
, sizeof (IPv4_DEVICE_PATH
));
2843 CopyMem (&Node
->LocalIpAddress
, &LocalIp
, sizeof (EFI_IPv4_ADDRESS
));
2844 CopyMem (&Node
->RemoteIpAddress
, &RemoteIp
, sizeof (EFI_IPv4_ADDRESS
));
2846 Node
->LocalPort
= LocalPort
;
2847 Node
->RemotePort
= RemotePort
;
2849 Node
->Protocol
= Protocol
;
2851 if (!UseDefaultAddress
) {
2852 Node
->StaticIpAddress
= TRUE
;
2854 Node
->StaticIpAddress
= NetLibDefaultAddressIsStatic (Controller
);
2858 // Set the Gateway IP address to default value 0:0:0:0.
2859 // Set the Subnet mask to default value 255:255:255:0.
2861 ZeroMem (&Node
->GatewayIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
2862 SetMem (&Node
->SubnetMask
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
2863 Node
->SubnetMask
.Addr
[3] = 0;
2867 Create an IPv6 device path node.
2869 If Node is NULL, then ASSERT().
2870 If LocalIp is NULL, then ASSERT().
2871 If RemoteIp is NULL, then ASSERT().
2873 The header type of IPv6 device path node is MESSAGING_DEVICE_PATH.
2874 The header subtype of IPv6 device path node is MSG_IPv6_DP.
2875 Get other info from parameters to make up the whole IPv6 device path node.
2877 @param[in, out] Node Pointer to the IPv6 device path node.
2878 @param[in] Controller The controller handle.
2879 @param[in] LocalIp The local IPv6 address.
2880 @param[in] LocalPort The local port.
2881 @param[in] RemoteIp The remote IPv6 address.
2882 @param[in] RemotePort The remote port.
2883 @param[in] Protocol The protocol type in the IP header.
2888 NetLibCreateIPv6DPathNode (
2889 IN OUT IPv6_DEVICE_PATH
*Node
,
2890 IN EFI_HANDLE Controller
,
2891 IN EFI_IPv6_ADDRESS
*LocalIp
,
2892 IN UINT16 LocalPort
,
2893 IN EFI_IPv6_ADDRESS
*RemoteIp
,
2894 IN UINT16 RemotePort
,
2898 ASSERT (Node
!= NULL
&& LocalIp
!= NULL
&& RemoteIp
!= NULL
);
2900 Node
->Header
.Type
= MESSAGING_DEVICE_PATH
;
2901 Node
->Header
.SubType
= MSG_IPv6_DP
;
2902 SetDevicePathNodeLength (&Node
->Header
, sizeof (IPv6_DEVICE_PATH
));
2904 CopyMem (&Node
->LocalIpAddress
, LocalIp
, sizeof (EFI_IPv6_ADDRESS
));
2905 CopyMem (&Node
->RemoteIpAddress
, RemoteIp
, sizeof (EFI_IPv6_ADDRESS
));
2907 Node
->LocalPort
= LocalPort
;
2908 Node
->RemotePort
= RemotePort
;
2910 Node
->Protocol
= Protocol
;
2913 // Set default value to IPAddressOrigin, PrefixLength.
2914 // Set the Gateway IP address to unspecified address.
2916 Node
->IpAddressOrigin
= 0;
2917 Node
->PrefixLength
= IP6_PREFIX_LENGTH
;
2918 ZeroMem (&Node
->GatewayIpAddress
, sizeof (EFI_IPv6_ADDRESS
));
2922 Find the UNDI/SNP handle from controller and protocol GUID.
2924 If ProtocolGuid is NULL, then ASSERT().
2926 For example, IP will open a MNP child to transmit/receive
2927 packets, when MNP is stopped, IP should also be stopped. IP
2928 needs to find its own private data which is related the IP's
2929 service binding instance that is install on UNDI/SNP handle.
2930 Now, the controller is either a MNP or ARP child handle. But
2931 IP opens these handle BY_DRIVER, use that info, we can get the
2934 @param[in] Controller Then protocol handle to check.
2935 @param[in] ProtocolGuid The protocol that is related with the handle.
2937 @return The UNDI/SNP handle or NULL for errors.
2942 NetLibGetNicHandle (
2943 IN EFI_HANDLE Controller
,
2944 IN EFI_GUID
*ProtocolGuid
2947 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenBuffer
;
2953 ASSERT (ProtocolGuid
!= NULL
);
2955 Status
= gBS
->OpenProtocolInformation (
2962 if (EFI_ERROR (Status
)) {
2968 for (Index
= 0; Index
< OpenCount
; Index
++) {
2969 if ((OpenBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_DRIVER
) != 0) {
2970 Handle
= OpenBuffer
[Index
].ControllerHandle
;
2975 gBS
->FreePool (OpenBuffer
);
2980 Convert one Null-terminated ASCII string (decimal dotted) to EFI_IPv4_ADDRESS.
2982 @param[in] String The pointer to the Ascii string.
2983 @param[out] Ip4Address The pointer to the converted IPv4 address.
2985 @retval EFI_SUCCESS Convert to IPv4 address successfully.
2986 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip4Address is NULL.
2991 NetLibAsciiStrToIp4 (
2992 IN CONST CHAR8
*String
,
2993 OUT EFI_IPv4_ADDRESS
*Ip4Address
2996 RETURN_STATUS Status
;
2999 Status
= AsciiStrToIpv4Address (String
, &EndPointer
, Ip4Address
, NULL
);
3000 if (RETURN_ERROR (Status
) || (*EndPointer
!= '\0')) {
3001 return EFI_INVALID_PARAMETER
;
3009 Convert one Null-terminated ASCII string to EFI_IPv6_ADDRESS. The format of the
3010 string is defined in RFC 4291 - Text Representation of Addresses.
3012 @param[in] String The pointer to the Ascii string.
3013 @param[out] Ip6Address The pointer to the converted IPv6 address.
3015 @retval EFI_SUCCESS Convert to IPv6 address successfully.
3016 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.
3021 NetLibAsciiStrToIp6 (
3022 IN CONST CHAR8
*String
,
3023 OUT EFI_IPv6_ADDRESS
*Ip6Address
3026 RETURN_STATUS Status
;
3029 Status
= AsciiStrToIpv6Address (String
, &EndPointer
, Ip6Address
, NULL
);
3030 if (RETURN_ERROR (Status
) || (*EndPointer
!= '\0')) {
3031 return EFI_INVALID_PARAMETER
;
3039 Convert one Null-terminated Unicode string (decimal dotted) to EFI_IPv4_ADDRESS.
3041 @param[in] String The pointer to the Ascii string.
3042 @param[out] Ip4Address The pointer to the converted IPv4 address.
3044 @retval EFI_SUCCESS Convert to IPv4 address successfully.
3045 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip4Address is NULL.
3051 IN CONST CHAR16
*String
,
3052 OUT EFI_IPv4_ADDRESS
*Ip4Address
3055 RETURN_STATUS Status
;
3058 Status
= StrToIpv4Address (String
, &EndPointer
, Ip4Address
, NULL
);
3059 if (RETURN_ERROR (Status
) || (*EndPointer
!= L
'\0')) {
3060 return EFI_INVALID_PARAMETER
;
3068 Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS. The format of
3069 the string is defined in RFC 4291 - Text Representation of Addresses.
3071 @param[in] String The pointer to the Ascii string.
3072 @param[out] Ip6Address The pointer to the converted IPv6 address.
3074 @retval EFI_SUCCESS Convert to IPv6 address successfully.
3075 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.
3081 IN CONST CHAR16
*String
,
3082 OUT EFI_IPv6_ADDRESS
*Ip6Address
3085 RETURN_STATUS Status
;
3088 Status
= StrToIpv6Address (String
, &EndPointer
, Ip6Address
, NULL
);
3089 if (RETURN_ERROR (Status
) || (*EndPointer
!= L
'\0')) {
3090 return EFI_INVALID_PARAMETER
;
3097 Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS and prefix length.
3098 The format of the string is defined in RFC 4291 - Text Representation of Addresses
3099 Prefixes: ipv6-address/prefix-length.
3101 @param[in] String The pointer to the Ascii string.
3102 @param[out] Ip6Address The pointer to the converted IPv6 address.
3103 @param[out] PrefixLength The pointer to the converted prefix length.
3105 @retval EFI_SUCCESS Convert to IPv6 address successfully.
3106 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.
3111 NetLibStrToIp6andPrefix (
3112 IN CONST CHAR16
*String
,
3113 OUT EFI_IPv6_ADDRESS
*Ip6Address
,
3114 OUT UINT8
*PrefixLength
3117 RETURN_STATUS Status
;
3120 Status
= StrToIpv6Address (String
, &EndPointer
, Ip6Address
, PrefixLength
);
3121 if (RETURN_ERROR (Status
) || (*EndPointer
!= L
'\0')) {
3122 return EFI_INVALID_PARAMETER
;
3130 Convert one EFI_IPv6_ADDRESS to Null-terminated Unicode string.
3131 The text representation of address is defined in RFC 4291.
3133 @param[in] Ip6Address The pointer to the IPv6 address.
3134 @param[out] String The buffer to return the converted string.
3135 @param[in] StringSize The length in bytes of the input String.
3137 @retval EFI_SUCCESS Convert to string successfully.
3138 @retval EFI_INVALID_PARAMETER The input parameter is invalid.
3139 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. BufferSize has been
3140 updated with the size needed to complete the request.
3145 IN EFI_IPv6_ADDRESS
*Ip6Address
,
3152 UINTN LongestZerosStart
;
3153 UINTN LongestZerosLength
;
3154 UINTN CurrentZerosStart
;
3155 UINTN CurrentZerosLength
;
3156 CHAR16 Buffer
[sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
3159 if (Ip6Address
== NULL
|| String
== NULL
|| StringSize
== 0) {
3160 return EFI_INVALID_PARAMETER
;
3164 // Convert the UINT8 array to an UINT16 array for easy handling.
3166 ZeroMem (Ip6Addr
, sizeof (Ip6Addr
));
3167 for (Index
= 0; Index
< 16; Index
++) {
3168 Ip6Addr
[Index
/ 2] |= (Ip6Address
->Addr
[Index
] << ((1 - (Index
% 2)) << 3));
3172 // Find the longest zeros and mark it.
3174 CurrentZerosStart
= DEFAULT_ZERO_START
;
3175 CurrentZerosLength
= 0;
3176 LongestZerosStart
= DEFAULT_ZERO_START
;
3177 LongestZerosLength
= 0;
3178 for (Index
= 0; Index
< 8; Index
++) {
3179 if (Ip6Addr
[Index
] == 0) {
3180 if (CurrentZerosStart
== DEFAULT_ZERO_START
) {
3181 CurrentZerosStart
= Index
;
3182 CurrentZerosLength
= 1;
3184 CurrentZerosLength
++;
3187 if (CurrentZerosStart
!= DEFAULT_ZERO_START
) {
3188 if (CurrentZerosLength
> 2 && (LongestZerosStart
== (DEFAULT_ZERO_START
) || CurrentZerosLength
> LongestZerosLength
)) {
3189 LongestZerosStart
= CurrentZerosStart
;
3190 LongestZerosLength
= CurrentZerosLength
;
3192 CurrentZerosStart
= DEFAULT_ZERO_START
;
3193 CurrentZerosLength
= 0;
3198 if (CurrentZerosStart
!= DEFAULT_ZERO_START
&& CurrentZerosLength
> 2) {
3199 if (LongestZerosStart
== DEFAULT_ZERO_START
|| LongestZerosLength
< CurrentZerosLength
) {
3200 LongestZerosStart
= CurrentZerosStart
;
3201 LongestZerosLength
= CurrentZerosLength
;
3206 for (Index
= 0; Index
< 8; Index
++) {
3207 if (LongestZerosStart
!= DEFAULT_ZERO_START
&& Index
>= LongestZerosStart
&& Index
< LongestZerosStart
+ LongestZerosLength
) {
3208 if (Index
== LongestZerosStart
) {
3216 Ptr
+= UnicodeSPrint(Ptr
, 10, L
"%x", Ip6Addr
[Index
]);
3219 if (LongestZerosStart
!= DEFAULT_ZERO_START
&& LongestZerosStart
+ LongestZerosLength
== 8) {
3224 if ((UINTN
)Ptr
- (UINTN
)Buffer
> StringSize
) {
3225 return EFI_BUFFER_TOO_SMALL
;
3228 StrCpyS (String
, StringSize
/ sizeof (CHAR16
), Buffer
);
3234 This function obtains the system guid from the smbios table.
3236 If SystemGuid is NULL, then ASSERT().
3238 @param[out] SystemGuid The pointer of the returned system guid.
3240 @retval EFI_SUCCESS Successfully obtained the system guid.
3241 @retval EFI_NOT_FOUND Did not find the SMBIOS table.
3246 NetLibGetSystemGuid (
3247 OUT EFI_GUID
*SystemGuid
3251 SMBIOS_TABLE_ENTRY_POINT
*SmbiosTable
;
3252 SMBIOS_TABLE_3_0_ENTRY_POINT
*Smbios30Table
;
3253 SMBIOS_STRUCTURE_POINTER Smbios
;
3254 SMBIOS_STRUCTURE_POINTER SmbiosEnd
;
3257 ASSERT (SystemGuid
!= NULL
);
3260 Status
= EfiGetSystemConfigurationTable (&gEfiSmbios3TableGuid
, (VOID
**) &Smbios30Table
);
3261 if (!(EFI_ERROR (Status
) || Smbios30Table
== NULL
)) {
3262 Smbios
.Hdr
= (SMBIOS_STRUCTURE
*) (UINTN
) Smbios30Table
->TableAddress
;
3263 SmbiosEnd
.Raw
= (UINT8
*) (UINTN
) (Smbios30Table
->TableAddress
+ Smbios30Table
->TableMaximumSize
);
3265 Status
= EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid
, (VOID
**) &SmbiosTable
);
3266 if (EFI_ERROR (Status
) || SmbiosTable
== NULL
) {
3267 return EFI_NOT_FOUND
;
3269 Smbios
.Hdr
= (SMBIOS_STRUCTURE
*) (UINTN
) SmbiosTable
->TableAddress
;
3270 SmbiosEnd
.Raw
= (UINT8
*) ((UINTN
) SmbiosTable
->TableAddress
+ SmbiosTable
->TableLength
);
3274 if (Smbios
.Hdr
->Type
== 1) {
3275 if (Smbios
.Hdr
->Length
< 0x19) {
3277 // Older version did not support UUID.
3279 return EFI_NOT_FOUND
;
3283 // SMBIOS tables are byte packed so we need to do a byte copy to
3284 // prevend alignment faults on Itanium-based platform.
3286 CopyMem (SystemGuid
, &Smbios
.Type1
->Uuid
, sizeof (EFI_GUID
));
3291 // Go to the next SMBIOS structure. Each SMBIOS structure may include 2 parts:
3292 // 1. Formatted section; 2. Unformatted string section. So, 2 steps are needed
3293 // to skip one SMBIOS structure.
3297 // Step 1: Skip over formatted section.
3299 String
= (CHAR8
*) (Smbios
.Raw
+ Smbios
.Hdr
->Length
);
3302 // Step 2: Skip over unformated string section.
3306 // Each string is terminated with a NULL(00h) BYTE and the sets of strings
3307 // is terminated with an additional NULL(00h) BYTE.
3309 for ( ; *String
!= 0; String
++) {
3312 if (*(UINT8
*)++String
== 0) {
3314 // Pointer to the next SMBIOS structure.
3316 Smbios
.Raw
= (UINT8
*)++String
;
3320 } while (Smbios
.Raw
< SmbiosEnd
.Raw
);
3321 return EFI_NOT_FOUND
;
3325 Create Dns QName according the queried domain name.
3327 If DomainName is NULL, then ASSERT().
3329 QName is a domain name represented as a sequence of labels,
3330 where each label consists of a length octet followed by that
3331 number of octets. The QName terminates with the zero
3332 length octet for the null label of the root. Caller should
3333 take responsibility to free the buffer in returned pointer.
3335 @param DomainName The pointer to the queried domain name string.
3337 @retval NULL Failed to fill QName.
3338 @return QName filled successfully.
3343 NetLibCreateDnsQName (
3344 IN CHAR16
*DomainName
3348 UINTN QueryNameSize
;
3354 ASSERT (DomainName
!= NULL
);
3362 // One byte for first label length, one byte for terminated length zero.
3364 QueryNameSize
= StrLen (DomainName
) + 2;
3366 if (QueryNameSize
> DNS_MAX_NAME_SIZE
) {
3370 QueryName
= AllocateZeroPool (QueryNameSize
);
3371 if (QueryName
== NULL
) {
3378 for (Index
= 0; DomainName
[Index
] != 0; Index
++) {
3379 *Tail
= (CHAR8
) DomainName
[Index
];
3381 *Header
= (CHAR8
) Len
;
3390 *Header
= (CHAR8
) Len
;