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
657 mask (RFC3021), or a 32bit NetMask (all 0xFF) is used for special network environment (e.g.
660 @param[in] Ip The IP to check against.
661 @param[in] NetMask The mask of the IP.
663 @return TRUE if IP is a valid unicast address on the network, otherwise FALSE.
675 ASSERT (NetMask
!= 0);
677 if (Ip
== 0 || IP4_IS_LOCAL_BROADCAST (Ip
)) {
681 MaskLength
= NetGetMaskLength (NetMask
);
682 ASSERT ((MaskLength
>= 0) && (MaskLength
<= IP4_MASK_NUM
));
683 if (MaskLength
< 31) {
684 if (((Ip
&~NetMask
) == ~NetMask
) || ((Ip
&~NetMask
) == 0)) {
693 Check whether the incoming IPv6 address is a valid unicast address.
695 ASSERT if Ip6 is NULL.
697 If the address is a multicast address has binary 0xFF at the start, it is not
698 a valid unicast address. If the address is unspecified ::, it is not a valid
699 unicast address to be assigned to any node. If the address is loopback address
700 ::1, it is also not a valid unicast address to be assigned to any physical
703 @param[in] Ip6 The IPv6 address to check against.
705 @return TRUE if Ip6 is a valid unicast address on the network, otherwise FALSE.
710 NetIp6IsValidUnicast (
711 IN EFI_IPv6_ADDRESS
*Ip6
717 ASSERT (Ip6
!= NULL
);
719 if (Ip6
->Addr
[0] == 0xFF) {
723 for (Index
= 0; Index
< 15; Index
++) {
724 if (Ip6
->Addr
[Index
] != 0) {
729 Byte
= Ip6
->Addr
[Index
];
731 if (Byte
== 0x0 || Byte
== 0x1) {
739 Check whether the incoming Ipv6 address is the unspecified address or not.
741 ASSERT if Ip6 is NULL.
743 @param[in] Ip6 - Ip6 address, in network order.
745 @retval TRUE - Yes, unspecified
751 NetIp6IsUnspecifiedAddr (
752 IN EFI_IPv6_ADDRESS
*Ip6
757 ASSERT (Ip6
!= NULL
);
759 for (Index
= 0; Index
< 16; Index
++) {
760 if (Ip6
->Addr
[Index
] != 0) {
769 Check whether the incoming Ipv6 address is a link-local address.
771 ASSERT if Ip6 is NULL.
773 @param[in] Ip6 - Ip6 address, in network order.
775 @retval TRUE - Yes, link-local address
781 NetIp6IsLinkLocalAddr (
782 IN EFI_IPv6_ADDRESS
*Ip6
787 ASSERT (Ip6
!= NULL
);
789 if (Ip6
->Addr
[0] != 0xFE) {
793 if (Ip6
->Addr
[1] != 0x80) {
797 for (Index
= 2; Index
< 8; Index
++) {
798 if (Ip6
->Addr
[Index
] != 0) {
807 Check whether the Ipv6 address1 and address2 are on the connected network.
809 ASSERT if Ip1 or Ip2 is NULL.
810 ASSERT if PrefixLength exceeds or equals to IP6_PREFIX_MAX.
812 @param[in] Ip1 - Ip6 address1, in network order.
813 @param[in] Ip2 - Ip6 address2, in network order.
814 @param[in] PrefixLength - The prefix length of the checking net.
816 @retval TRUE - Yes, connected.
823 EFI_IPv6_ADDRESS
*Ip1
,
824 EFI_IPv6_ADDRESS
*Ip2
,
832 ASSERT ((Ip1
!= NULL
) && (Ip2
!= NULL
) && (PrefixLength
< IP6_PREFIX_MAX
));
834 if (PrefixLength
== 0) {
838 Byte
= (UINT8
) (PrefixLength
/ 8);
839 Bit
= (UINT8
) (PrefixLength
% 8);
841 if (CompareMem (Ip1
, Ip2
, Byte
) != 0) {
846 Mask
= (UINT8
) (0xFF << (8 - Bit
));
852 if ((Ip1
->Addr
[Byte
] & Mask
) != (Ip2
->Addr
[Byte
] & Mask
)) {
862 Switches the endianess of an IPv6 address
864 ASSERT if Ip6 is NULL.
866 This function swaps the bytes in a 128-bit IPv6 address to switch the value
867 from little endian to big endian or vice versa. The byte swapped value is
870 @param Ip6 Points to an IPv6 address
872 @return The byte swapped IPv6 address.
878 EFI_IPv6_ADDRESS
*Ip6
884 ASSERT (Ip6
!= NULL
);
886 CopyMem (&High
, Ip6
, sizeof (UINT64
));
887 CopyMem (&Low
, &Ip6
->Addr
[8], sizeof (UINT64
));
889 High
= SwapBytes64 (High
);
890 Low
= SwapBytes64 (Low
);
892 CopyMem (Ip6
, &Low
, sizeof (UINT64
));
893 CopyMem (&Ip6
->Addr
[8], &High
, sizeof (UINT64
));
899 Initialize a random seed using current time and monotonic count.
901 Get current time and monotonic count first. Then initialize a random seed
902 based on some basic mathematics operation on the hour, day, minute, second,
903 nanosecond and year of the current time and the monotonic count value.
905 @return The random seed initialized with current time.
916 UINT64 MonotonicCount
;
918 gRT
->GetTime (&Time
, NULL
);
919 Seed
= (Time
.Hour
<< 24 | Time
.Day
<< 16 | Time
.Minute
<< 8 | Time
.Second
);
920 Seed
^= Time
.Nanosecond
;
921 Seed
^= Time
.Year
<< 7;
923 gBS
->GetNextMonotonicCount (&MonotonicCount
);
924 Seed
+= (UINT32
) MonotonicCount
;
931 Extract a UINT32 from a byte stream.
933 ASSERT if Buf is NULL.
935 Copy a UINT32 from a byte stream, then converts it from Network
936 byte order to host byte order. Use this function to avoid alignment error.
938 @param[in] Buf The buffer to extract the UINT32.
940 @return The UINT32 extracted.
951 ASSERT (Buf
!= NULL
);
953 CopyMem (&Value
, Buf
, sizeof (UINT32
));
954 return NTOHL (Value
);
959 Put a UINT32 to the byte stream in network byte order.
961 ASSERT if Buf is NULL.
963 Converts a UINT32 from host byte order to network byte order. Then copy it to the
966 @param[in, out] Buf The buffer to put the UINT32.
967 @param[in] Data The data to be converted and put into the byte stream.
977 ASSERT (Buf
!= NULL
);
980 CopyMem (Buf
, &Data
, sizeof (UINT32
));
985 Remove the first node entry on the list, and return the removed node entry.
987 Removes the first node Entry from a doubly linked list. It is up to the caller of
988 this function to release the memory used by the first node if that is required. On
989 exit, the removed node is returned.
991 If Head is NULL, then ASSERT().
992 If Head was not initialized, then ASSERT().
993 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
994 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
997 @param[in, out] Head The list header.
999 @return The first node entry that is removed from the list, NULL if the list is empty.
1005 IN OUT LIST_ENTRY
*Head
1010 ASSERT (Head
!= NULL
);
1012 if (IsListEmpty (Head
)) {
1016 First
= Head
->ForwardLink
;
1017 Head
->ForwardLink
= First
->ForwardLink
;
1018 First
->ForwardLink
->BackLink
= Head
;
1021 First
->ForwardLink
= (LIST_ENTRY
*) NULL
;
1022 First
->BackLink
= (LIST_ENTRY
*) NULL
;
1030 Remove the last node entry on the list and and return the removed node entry.
1032 Removes the last node entry from a doubly linked list. It is up to the caller of
1033 this function to release the memory used by the first node if that is required. On
1034 exit, the removed node is returned.
1036 If Head is NULL, then ASSERT().
1037 If Head was not initialized, then ASSERT().
1038 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
1039 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
1042 @param[in, out] Head The list head.
1044 @return The last node entry that is removed from the list, NULL if the list is empty.
1050 IN OUT LIST_ENTRY
*Head
1055 ASSERT (Head
!= NULL
);
1057 if (IsListEmpty (Head
)) {
1061 Last
= Head
->BackLink
;
1062 Head
->BackLink
= Last
->BackLink
;
1063 Last
->BackLink
->ForwardLink
= Head
;
1066 Last
->ForwardLink
= (LIST_ENTRY
*) NULL
;
1067 Last
->BackLink
= (LIST_ENTRY
*) NULL
;
1075 Insert a new node entry after a designated node entry of a doubly linked list.
1077 ASSERT if PrevEntry or NewEntry is NULL.
1079 Inserts a new node entry donated by NewEntry after the node entry donated by PrevEntry
1080 of the doubly linked list.
1082 @param[in, out] PrevEntry The previous entry to insert after.
1083 @param[in, out] NewEntry The new entry to insert.
1088 NetListInsertAfter (
1089 IN OUT LIST_ENTRY
*PrevEntry
,
1090 IN OUT LIST_ENTRY
*NewEntry
1093 ASSERT (PrevEntry
!= NULL
&& NewEntry
!= NULL
);
1095 NewEntry
->BackLink
= PrevEntry
;
1096 NewEntry
->ForwardLink
= PrevEntry
->ForwardLink
;
1097 PrevEntry
->ForwardLink
->BackLink
= NewEntry
;
1098 PrevEntry
->ForwardLink
= NewEntry
;
1103 Insert a new node entry before a designated node entry of a doubly linked list.
1105 ASSERT if PostEntry or NewEntry is NULL.
1107 Inserts a new node entry donated by NewEntry after the node entry donated by PostEntry
1108 of the doubly linked list.
1110 @param[in, out] PostEntry The entry to insert before.
1111 @param[in, out] NewEntry The new entry to insert.
1116 NetListInsertBefore (
1117 IN OUT LIST_ENTRY
*PostEntry
,
1118 IN OUT LIST_ENTRY
*NewEntry
1121 ASSERT (PostEntry
!= NULL
&& NewEntry
!= NULL
);
1123 NewEntry
->ForwardLink
= PostEntry
;
1124 NewEntry
->BackLink
= PostEntry
->BackLink
;
1125 PostEntry
->BackLink
->ForwardLink
= NewEntry
;
1126 PostEntry
->BackLink
= NewEntry
;
1130 Safe destroy nodes in a linked list, and return the length of the list after all possible operations finished.
1132 Destroy network child instance list by list traversals is not safe due to graph dependencies between nodes.
1133 This function performs a safe traversal to destroy these nodes by checking to see if the node being destroyed
1134 has been removed from the list or not.
1135 If it has been removed, then restart the traversal from the head.
1136 If it hasn't been removed, then continue with the next node directly.
1137 This function will end the iterate and return the CallBack's last return value if error happens,
1138 or retrun EFI_SUCCESS if 2 complete passes are made with no changes in the number of children in the list.
1140 @param[in] List The head of the list.
1141 @param[in] CallBack Pointer to the callback function to destroy one node in the list.
1142 @param[in] Context Pointer to the callback function's context: corresponds to the
1143 parameter Context in NET_DESTROY_LINK_LIST_CALLBACK.
1144 @param[out] ListLength The length of the link list if the function returns successfully.
1146 @retval EFI_SUCCESS Two complete passes are made with no changes in the number of children.
1147 @retval EFI_INVALID_PARAMETER The input parameter is invalid.
1148 @retval Others Return the CallBack's last return value.
1153 NetDestroyLinkList (
1154 IN LIST_ENTRY
*List
,
1155 IN NET_DESTROY_LINK_LIST_CALLBACK CallBack
,
1156 IN VOID
*Context
, OPTIONAL
1157 OUT UINTN
*ListLength OPTIONAL
1160 UINTN PreviousLength
;
1166 if (List
== NULL
|| CallBack
== NULL
) {
1167 return EFI_INVALID_PARAMETER
;
1172 PreviousLength
= Length
;
1173 Entry
= GetFirstNode (List
);
1174 while (!IsNull (List
, Entry
)) {
1175 Status
= CallBack (Entry
, Context
);
1176 if (EFI_ERROR (Status
)) {
1180 // Walk through the list to see whether the Entry has been removed or not.
1181 // If the Entry still exists, just try to destroy the next one.
1182 // If not, go back to the start point to iterate the list again.
1184 for (Ptr
= List
->ForwardLink
; Ptr
!= List
; Ptr
= Ptr
->ForwardLink
) {
1190 Entry
= GetNextNode (List
, Entry
);
1192 Entry
= GetFirstNode (List
);
1195 for (Length
= 0, Ptr
= List
->ForwardLink
; Ptr
!= List
; Length
++, Ptr
= Ptr
->ForwardLink
);
1196 } while (Length
!= PreviousLength
);
1198 if (ListLength
!= NULL
) {
1199 *ListLength
= Length
;
1205 This function checks the input Handle to see if it's one of these handles in ChildHandleBuffer.
1207 @param[in] Handle Handle to be checked.
1208 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer.
1209 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
1210 if NumberOfChildren is 0.
1212 @retval TRUE Found the input Handle in ChildHandleBuffer.
1213 @retval FALSE Can't find the input Handle in ChildHandleBuffer.
1218 NetIsInHandleBuffer (
1219 IN EFI_HANDLE Handle
,
1220 IN UINTN NumberOfChildren
,
1221 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
1226 if (NumberOfChildren
== 0 || ChildHandleBuffer
== NULL
) {
1230 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
1231 if (Handle
== ChildHandleBuffer
[Index
]) {
1241 Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.
1243 Initialize the forward and backward links of two head nodes donated by Map->Used
1244 and Map->Recycled of two doubly linked lists.
1245 Initializes the count of the <Key, Value> pairs in the netmap to zero.
1247 If Map is NULL, then ASSERT().
1248 If the address of Map->Used is NULL, then ASSERT().
1249 If the address of Map->Recycled is NULl, then ASSERT().
1251 @param[in, out] Map The netmap to initialize.
1260 ASSERT (Map
!= NULL
);
1262 InitializeListHead (&Map
->Used
);
1263 InitializeListHead (&Map
->Recycled
);
1269 To clean up the netmap, that is, release allocated memories.
1271 Removes all nodes of the Used doubly linked list and free memory of all related netmap items.
1272 Removes all nodes of the Recycled doubly linked list and free memory of all related netmap items.
1273 The number of the <Key, Value> pairs in the netmap is set to be zero.
1275 If Map is NULL, then ASSERT().
1277 @param[in, out] Map The netmap to clean up.
1290 ASSERT (Map
!= NULL
);
1292 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &Map
->Used
) {
1293 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1295 RemoveEntryList (&Item
->Link
);
1298 gBS
->FreePool (Item
);
1301 ASSERT ((Map
->Count
== 0) && IsListEmpty (&Map
->Used
));
1303 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &Map
->Recycled
) {
1304 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1306 RemoveEntryList (&Item
->Link
);
1307 gBS
->FreePool (Item
);
1310 ASSERT (IsListEmpty (&Map
->Recycled
));
1315 Test whether the netmap is empty and return true if it is.
1317 If the number of the <Key, Value> pairs in the netmap is zero, return TRUE.
1319 If Map is NULL, then ASSERT().
1321 @param[in] Map The net map to test.
1323 @return TRUE if the netmap is empty, otherwise FALSE.
1332 ASSERT (Map
!= NULL
);
1333 return (BOOLEAN
) (Map
->Count
== 0);
1338 Return the number of the <Key, Value> pairs in the netmap.
1340 If Map is NULL, then ASSERT().
1342 @param[in] Map The netmap to get the entry number.
1344 @return The entry number in the netmap.
1353 ASSERT (Map
!= NULL
);
1359 Return one allocated item.
1361 If the Recycled doubly linked list of the netmap is empty, it will try to allocate
1362 a batch of items if there are enough resources and add corresponding nodes to the begining
1363 of the Recycled doubly linked list of the netmap. Otherwise, it will directly remove
1364 the fist node entry of the Recycled doubly linked list and return the corresponding item.
1366 If Map is NULL, then ASSERT().
1368 @param[in, out] Map The netmap to allocate item for.
1370 @return The allocated item. If NULL, the
1371 allocation failed due to resource limit.
1383 ASSERT (Map
!= NULL
);
1385 Head
= &Map
->Recycled
;
1387 if (IsListEmpty (Head
)) {
1388 for (Index
= 0; Index
< NET_MAP_INCREAMENT
; Index
++) {
1389 Item
= AllocatePool (sizeof (NET_MAP_ITEM
));
1399 InsertHeadList (Head
, &Item
->Link
);
1403 Item
= NET_LIST_HEAD (Head
, NET_MAP_ITEM
, Link
);
1404 NetListRemoveHead (Head
);
1411 Allocate an item to save the <Key, Value> pair to the head of the netmap.
1413 Allocate an item to save the <Key, Value> pair and add corresponding node entry
1414 to the beginning of the Used doubly linked list. The number of the <Key, Value>
1415 pairs in the netmap increase by 1.
1417 If Map is NULL, then ASSERT().
1418 If Key is NULL, then ASSERT().
1420 @param[in, out] Map The netmap to insert into.
1421 @param[in] Key The user's key.
1422 @param[in] Value The user's value for the key.
1424 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
1425 @retval EFI_SUCCESS The item is inserted to the head.
1431 IN OUT NET_MAP
*Map
,
1433 IN VOID
*Value OPTIONAL
1438 ASSERT (Map
!= NULL
&& Key
!= NULL
);
1440 Item
= NetMapAllocItem (Map
);
1443 return EFI_OUT_OF_RESOURCES
;
1447 Item
->Value
= Value
;
1448 InsertHeadList (&Map
->Used
, &Item
->Link
);
1456 Allocate an item to save the <Key, Value> pair to the tail of the netmap.
1458 Allocate an item to save the <Key, Value> pair and add corresponding node entry
1459 to the tail of the Used doubly linked list. The number of the <Key, Value>
1460 pairs in the netmap increase by 1.
1462 If Map is NULL, then ASSERT().
1463 If Key is NULL, then ASSERT().
1465 @param[in, out] Map The netmap to insert into.
1466 @param[in] Key The user's key.
1467 @param[in] Value The user's value for the key.
1469 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
1470 @retval EFI_SUCCESS The item is inserted to the tail.
1476 IN OUT NET_MAP
*Map
,
1478 IN VOID
*Value OPTIONAL
1483 ASSERT (Map
!= NULL
&& Key
!= NULL
);
1485 Item
= NetMapAllocItem (Map
);
1488 return EFI_OUT_OF_RESOURCES
;
1492 Item
->Value
= Value
;
1493 InsertTailList (&Map
->Used
, &Item
->Link
);
1502 Check whether the item is in the Map and return TRUE if it is.
1504 If Map is NULL, then ASSERT().
1505 If Item is NULL, then ASSERT().
1507 @param[in] Map The netmap to search within.
1508 @param[in] Item The item to search.
1510 @return TRUE if the item is in the netmap, otherwise FALSE.
1516 IN NET_MAP_ITEM
*Item
1519 LIST_ENTRY
*ListEntry
;
1521 ASSERT (Map
!= NULL
&& Item
!= NULL
);
1523 NET_LIST_FOR_EACH (ListEntry
, &Map
->Used
) {
1524 if (ListEntry
== &Item
->Link
) {
1534 Find the key in the netmap and returns the point to the item contains the Key.
1536 Iterate the Used doubly linked list of the netmap to get every item. Compare the key of every
1537 item with the key to search. It returns the point to the item contains the Key if found.
1539 If Map is NULL, then ASSERT().
1540 If Key is NULL, then ASSERT().
1542 @param[in] Map The netmap to search within.
1543 @param[in] Key The key to search.
1545 @return The point to the item contains the Key, or NULL if Key isn't in the map.
1558 ASSERT (Map
!= NULL
&& Key
!= NULL
);
1560 NET_LIST_FOR_EACH (Entry
, &Map
->Used
) {
1561 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1563 if (Item
->Key
== Key
) {
1573 Remove the node entry of the item from the netmap and return the key of the removed item.
1575 Remove the node entry of the item from the Used doubly linked list of the netmap.
1576 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1577 entry of the item to the Recycled doubly linked list of the netmap. If Value is not NULL,
1578 Value will point to the value of the item. It returns the key of the removed item.
1580 If Map is NULL, then ASSERT().
1581 If Item is NULL, then ASSERT().
1582 if item in not in the netmap, then ASSERT().
1584 @param[in, out] Map The netmap to remove the item from.
1585 @param[in, out] Item The item to remove.
1586 @param[out] Value The variable to receive the value if not NULL.
1588 @return The key of the removed item.
1594 IN OUT NET_MAP
*Map
,
1595 IN OUT NET_MAP_ITEM
*Item
,
1596 OUT VOID
**Value OPTIONAL
1599 ASSERT ((Map
!= NULL
) && (Item
!= NULL
));
1600 ASSERT (NetItemInMap (Map
, Item
));
1602 RemoveEntryList (&Item
->Link
);
1604 InsertHeadList (&Map
->Recycled
, &Item
->Link
);
1606 if (Value
!= NULL
) {
1607 *Value
= Item
->Value
;
1615 Remove the first node entry on the netmap and return the key of the removed item.
1617 Remove the first node entry from the Used doubly linked list of the netmap.
1618 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1619 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
1620 parameter Value will point to the value of the item. It returns the key of the removed item.
1622 If Map is NULL, then ASSERT().
1623 If the Used doubly linked list is empty, then ASSERT().
1625 @param[in, out] Map The netmap to remove the head from.
1626 @param[out] Value The variable to receive the value if not NULL.
1628 @return The key of the item removed.
1634 IN OUT NET_MAP
*Map
,
1635 OUT VOID
**Value OPTIONAL
1641 // Often, it indicates a programming error to remove
1642 // the first entry in an empty list
1644 ASSERT (Map
&& !IsListEmpty (&Map
->Used
));
1646 Item
= NET_LIST_HEAD (&Map
->Used
, NET_MAP_ITEM
, Link
);
1647 RemoveEntryList (&Item
->Link
);
1649 InsertHeadList (&Map
->Recycled
, &Item
->Link
);
1651 if (Value
!= NULL
) {
1652 *Value
= Item
->Value
;
1660 Remove the last node entry on the netmap and return the key of the removed item.
1662 Remove the last node entry from the Used doubly linked list of the netmap.
1663 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1664 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
1665 parameter Value will point to the value of the item. It returns the key of the removed item.
1667 If Map is NULL, then ASSERT().
1668 If the Used doubly linked list is empty, then ASSERT().
1670 @param[in, out] Map The netmap to remove the tail from.
1671 @param[out] Value The variable to receive the value if not NULL.
1673 @return The key of the item removed.
1679 IN OUT NET_MAP
*Map
,
1680 OUT VOID
**Value OPTIONAL
1686 // Often, it indicates a programming error to remove
1687 // the last entry in an empty list
1689 ASSERT (Map
&& !IsListEmpty (&Map
->Used
));
1691 Item
= NET_LIST_TAIL (&Map
->Used
, NET_MAP_ITEM
, Link
);
1692 RemoveEntryList (&Item
->Link
);
1694 InsertHeadList (&Map
->Recycled
, &Item
->Link
);
1696 if (Value
!= NULL
) {
1697 *Value
= Item
->Value
;
1705 Iterate through the netmap and call CallBack for each item.
1707 It will continue the traverse if CallBack returns EFI_SUCCESS, otherwise, break
1708 from the loop. It returns the CallBack's last return value. This function is
1709 delete safe for the current item.
1711 If Map is NULL, then ASSERT().
1712 If CallBack is NULL, then ASSERT().
1714 @param[in] Map The Map to iterate through.
1715 @param[in] CallBack The callback function to call for each item.
1716 @param[in] Arg The opaque parameter to the callback.
1718 @retval EFI_SUCCESS There is no item in the netmap or CallBack for each item
1720 @retval Others It returns the CallBack's last return value.
1727 IN NET_MAP_CALLBACK CallBack
,
1728 IN VOID
*Arg OPTIONAL
1738 ASSERT ((Map
!= NULL
) && (CallBack
!= NULL
));
1742 if (IsListEmpty (Head
)) {
1746 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, Head
) {
1747 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1748 Result
= CallBack (Map
, Item
, Arg
);
1750 if (EFI_ERROR (Result
)) {
1760 This is the default unload handle for all the network drivers.
1762 Disconnect the driver specified by ImageHandle from all the devices in the handle database.
1763 Uninstall all the protocols installed in the driver entry point.
1765 @param[in] ImageHandle The drivers' driver image.
1767 @retval EFI_SUCCESS The image is unloaded.
1768 @retval Others Failed to unload the image.
1773 NetLibDefaultUnload (
1774 IN EFI_HANDLE ImageHandle
1778 EFI_HANDLE
*DeviceHandleBuffer
;
1779 UINTN DeviceHandleCount
;
1782 EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
;
1783 EFI_COMPONENT_NAME_PROTOCOL
*ComponentName
;
1784 EFI_COMPONENT_NAME2_PROTOCOL
*ComponentName2
;
1787 // Get the list of all the handles in the handle database.
1788 // If there is an error getting the list, then the unload
1791 Status
= gBS
->LocateHandleBuffer (
1799 if (EFI_ERROR (Status
)) {
1803 for (Index
= 0; Index
< DeviceHandleCount
; Index
++) {
1804 Status
= gBS
->HandleProtocol (
1805 DeviceHandleBuffer
[Index
],
1806 &gEfiDriverBindingProtocolGuid
,
1807 (VOID
**) &DriverBinding
1809 if (EFI_ERROR (Status
)) {
1813 if (DriverBinding
->ImageHandle
!= ImageHandle
) {
1818 // Disconnect the driver specified by ImageHandle from all
1819 // the devices in the handle database.
1821 for (Index2
= 0; Index2
< DeviceHandleCount
; Index2
++) {
1822 Status
= gBS
->DisconnectController (
1823 DeviceHandleBuffer
[Index2
],
1824 DriverBinding
->DriverBindingHandle
,
1830 // Uninstall all the protocols installed in the driver entry point
1832 gBS
->UninstallProtocolInterface (
1833 DriverBinding
->DriverBindingHandle
,
1834 &gEfiDriverBindingProtocolGuid
,
1838 Status
= gBS
->HandleProtocol (
1839 DeviceHandleBuffer
[Index
],
1840 &gEfiComponentNameProtocolGuid
,
1841 (VOID
**) &ComponentName
1843 if (!EFI_ERROR (Status
)) {
1844 gBS
->UninstallProtocolInterface (
1845 DriverBinding
->DriverBindingHandle
,
1846 &gEfiComponentNameProtocolGuid
,
1851 Status
= gBS
->HandleProtocol (
1852 DeviceHandleBuffer
[Index
],
1853 &gEfiComponentName2ProtocolGuid
,
1854 (VOID
**) &ComponentName2
1856 if (!EFI_ERROR (Status
)) {
1857 gBS
->UninstallProtocolInterface (
1858 DriverBinding
->DriverBindingHandle
,
1859 &gEfiComponentName2ProtocolGuid
,
1866 // Free the buffer containing the list of handles from the handle database
1868 if (DeviceHandleBuffer
!= NULL
) {
1869 gBS
->FreePool (DeviceHandleBuffer
);
1878 Create a child of the service that is identified by ServiceBindingGuid.
1880 Get the ServiceBinding Protocol first, then use it to create a child.
1882 If ServiceBindingGuid is NULL, then ASSERT().
1883 If ChildHandle is NULL, then ASSERT().
1885 @param[in] Controller The controller which has the service installed.
1886 @param[in] Image The image handle used to open service.
1887 @param[in] ServiceBindingGuid The service's Guid.
1888 @param[in, out] ChildHandle The handle to receive the create child.
1890 @retval EFI_SUCCESS The child is successfully created.
1891 @retval Others Failed to create the child.
1896 NetLibCreateServiceChild (
1897 IN EFI_HANDLE Controller
,
1898 IN EFI_HANDLE Image
,
1899 IN EFI_GUID
*ServiceBindingGuid
,
1900 IN OUT EFI_HANDLE
*ChildHandle
1904 EFI_SERVICE_BINDING_PROTOCOL
*Service
;
1907 ASSERT ((ServiceBindingGuid
!= NULL
) && (ChildHandle
!= NULL
));
1910 // Get the ServiceBinding Protocol
1912 Status
= gBS
->OpenProtocol (
1918 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1921 if (EFI_ERROR (Status
)) {
1928 Status
= Service
->CreateChild (Service
, ChildHandle
);
1934 Destroy a child of the service that is identified by ServiceBindingGuid.
1936 Get the ServiceBinding Protocol first, then use it to destroy a child.
1938 If ServiceBindingGuid is NULL, then ASSERT().
1940 @param[in] Controller The controller which has the service installed.
1941 @param[in] Image The image handle used to open service.
1942 @param[in] ServiceBindingGuid The service's Guid.
1943 @param[in] ChildHandle The child to destroy.
1945 @retval EFI_SUCCESS The child is successfully destroyed.
1946 @retval Others Failed to destroy the child.
1951 NetLibDestroyServiceChild (
1952 IN EFI_HANDLE Controller
,
1953 IN EFI_HANDLE Image
,
1954 IN EFI_GUID
*ServiceBindingGuid
,
1955 IN EFI_HANDLE ChildHandle
1959 EFI_SERVICE_BINDING_PROTOCOL
*Service
;
1961 ASSERT (ServiceBindingGuid
!= NULL
);
1964 // Get the ServiceBinding Protocol
1966 Status
= gBS
->OpenProtocol (
1972 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1975 if (EFI_ERROR (Status
)) {
1980 // destroy the child
1982 Status
= Service
->DestroyChild (Service
, ChildHandle
);
1987 Get handle with Simple Network Protocol installed on it.
1989 There should be MNP Service Binding Protocol installed on the input ServiceHandle.
1990 If Simple Network Protocol is already installed on the ServiceHandle, the
1991 ServiceHandle will be returned. If SNP is not installed on the ServiceHandle,
1992 try to find its parent handle with SNP installed.
1994 @param[in] ServiceHandle The handle where network service binding protocols are
1996 @param[out] Snp The pointer to store the address of the SNP instance.
1997 This is an optional parameter that may be NULL.
1999 @return The SNP handle, or NULL if not found.
2004 NetLibGetSnpHandle (
2005 IN EFI_HANDLE ServiceHandle
,
2006 OUT EFI_SIMPLE_NETWORK_PROTOCOL
**Snp OPTIONAL
2010 EFI_SIMPLE_NETWORK_PROTOCOL
*SnpInstance
;
2011 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2012 EFI_HANDLE SnpHandle
;
2015 // Try to open SNP from ServiceHandle
2018 Status
= gBS
->HandleProtocol (ServiceHandle
, &gEfiSimpleNetworkProtocolGuid
, (VOID
**) &SnpInstance
);
2019 if (!EFI_ERROR (Status
)) {
2023 return ServiceHandle
;
2027 // Failed to open SNP, try to get SNP handle by LocateDevicePath()
2029 DevicePath
= DevicePathFromHandle (ServiceHandle
);
2030 if (DevicePath
== NULL
) {
2035 Status
= gBS
->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid
, &DevicePath
, &SnpHandle
);
2036 if (EFI_ERROR (Status
)) {
2038 // Failed to find SNP handle
2043 Status
= gBS
->HandleProtocol (SnpHandle
, &gEfiSimpleNetworkProtocolGuid
, (VOID
**) &SnpInstance
);
2044 if (!EFI_ERROR (Status
)) {
2055 Retrieve VLAN ID of a VLAN device handle.
2057 Search VLAN device path node in Device Path of specified ServiceHandle and
2058 return its VLAN ID. If no VLAN device path node found, then this ServiceHandle
2059 is not a VLAN device handle, and 0 will be returned.
2061 @param[in] ServiceHandle The handle where network service binding protocols are
2064 @return VLAN ID of the device handle, or 0 if not a VLAN device.
2070 IN EFI_HANDLE ServiceHandle
2073 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2074 EFI_DEVICE_PATH_PROTOCOL
*Node
;
2076 DevicePath
= DevicePathFromHandle (ServiceHandle
);
2077 if (DevicePath
== NULL
) {
2082 while (!IsDevicePathEnd (Node
)) {
2083 if (Node
->Type
== MESSAGING_DEVICE_PATH
&& Node
->SubType
== MSG_VLAN_DP
) {
2084 return ((VLAN_DEVICE_PATH
*) Node
)->VlanId
;
2086 Node
= NextDevicePathNode (Node
);
2093 Find VLAN device handle with specified VLAN ID.
2095 The VLAN child device handle is created by VLAN Config Protocol on ControllerHandle.
2096 This function will append VLAN device path node to the parent device path,
2097 and then use LocateDevicePath() to find the correct VLAN device handle.
2099 @param[in] ControllerHandle The handle where network service binding protocols are
2101 @param[in] VlanId The configured VLAN ID for the VLAN device.
2103 @return The VLAN device handle, or NULL if not found.
2108 NetLibGetVlanHandle (
2109 IN EFI_HANDLE ControllerHandle
,
2113 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
2114 EFI_DEVICE_PATH_PROTOCOL
*VlanDevicePath
;
2115 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2116 VLAN_DEVICE_PATH VlanNode
;
2119 ParentDevicePath
= DevicePathFromHandle (ControllerHandle
);
2120 if (ParentDevicePath
== NULL
) {
2125 // Construct VLAN device path
2127 CopyMem (&VlanNode
, &mNetVlanDevicePathTemplate
, sizeof (VLAN_DEVICE_PATH
));
2128 VlanNode
.VlanId
= VlanId
;
2129 VlanDevicePath
= AppendDevicePathNode (
2131 (EFI_DEVICE_PATH_PROTOCOL
*) &VlanNode
2133 if (VlanDevicePath
== NULL
) {
2138 // Find VLAN device handle
2141 DevicePath
= VlanDevicePath
;
2142 gBS
->LocateDevicePath (
2143 &gEfiDevicePathProtocolGuid
,
2147 if (!IsDevicePathEnd (DevicePath
)) {
2149 // Device path is not exactly match
2154 FreePool (VlanDevicePath
);
2159 Get MAC address associated with the network service handle.
2161 If MacAddress is NULL, then ASSERT().
2162 If AddressSize is NULL, then ASSERT().
2164 There should be MNP Service Binding Protocol installed on the input ServiceHandle.
2165 If SNP is installed on the ServiceHandle or its parent handle, MAC address will
2166 be retrieved from SNP. If no SNP found, try to get SNP mode data use MNP.
2168 @param[in] ServiceHandle The handle where network service binding protocols are
2170 @param[out] MacAddress The pointer to store the returned MAC address.
2171 @param[out] AddressSize The length of returned MAC address.
2173 @retval EFI_SUCCESS MAC address is returned successfully.
2174 @retval Others Failed to get SNP mode data.
2179 NetLibGetMacAddress (
2180 IN EFI_HANDLE ServiceHandle
,
2181 OUT EFI_MAC_ADDRESS
*MacAddress
,
2182 OUT UINTN
*AddressSize
2186 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2187 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
2188 EFI_SIMPLE_NETWORK_MODE SnpModeData
;
2189 EFI_MANAGED_NETWORK_PROTOCOL
*Mnp
;
2190 EFI_SERVICE_BINDING_PROTOCOL
*MnpSb
;
2191 EFI_HANDLE
*SnpHandle
;
2192 EFI_HANDLE MnpChildHandle
;
2194 ASSERT (MacAddress
!= NULL
);
2195 ASSERT (AddressSize
!= NULL
);
2198 // Try to get SNP handle
2201 SnpHandle
= NetLibGetSnpHandle (ServiceHandle
, &Snp
);
2202 if (SnpHandle
!= NULL
) {
2204 // SNP found, use it directly
2206 SnpMode
= Snp
->Mode
;
2209 // Failed to get SNP handle, try to get MAC address from MNP
2211 MnpChildHandle
= NULL
;
2212 Status
= gBS
->HandleProtocol (
2214 &gEfiManagedNetworkServiceBindingProtocolGuid
,
2217 if (EFI_ERROR (Status
)) {
2222 // Create a MNP child
2224 Status
= MnpSb
->CreateChild (MnpSb
, &MnpChildHandle
);
2225 if (EFI_ERROR (Status
)) {
2230 // Open MNP protocol
2232 Status
= gBS
->HandleProtocol (
2234 &gEfiManagedNetworkProtocolGuid
,
2237 if (EFI_ERROR (Status
)) {
2238 MnpSb
->DestroyChild (MnpSb
, MnpChildHandle
);
2243 // Try to get SNP mode from MNP
2245 Status
= Mnp
->GetModeData (Mnp
, NULL
, &SnpModeData
);
2246 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_STARTED
)) {
2247 MnpSb
->DestroyChild (MnpSb
, MnpChildHandle
);
2250 SnpMode
= &SnpModeData
;
2253 // Destroy the MNP child
2255 MnpSb
->DestroyChild (MnpSb
, MnpChildHandle
);
2258 *AddressSize
= SnpMode
->HwAddressSize
;
2259 CopyMem (MacAddress
->Addr
, SnpMode
->CurrentAddress
.Addr
, SnpMode
->HwAddressSize
);
2265 Convert MAC address of the NIC associated with specified Service Binding Handle
2266 to a unicode string. Callers are responsible for freeing the string storage.
2268 If MacString is NULL, then ASSERT().
2270 Locate simple network protocol associated with the Service Binding Handle and
2271 get the mac address from SNP. Then convert the mac address into a unicode
2272 string. It takes 2 unicode characters to represent a 1 byte binary buffer.
2273 Plus one unicode character for the null-terminator.
2275 @param[in] ServiceHandle The handle where network service binding protocol is
2277 @param[in] ImageHandle The image handle used to act as the agent handle to
2278 get the simple network protocol. This parameter is
2279 optional and may be NULL.
2280 @param[out] MacString The pointer to store the address of the string
2281 representation of the mac address.
2283 @retval EFI_SUCCESS Convert the mac address a unicode string successfully.
2284 @retval EFI_OUT_OF_RESOURCES There are not enough memory resource.
2285 @retval Others Failed to open the simple network protocol.
2290 NetLibGetMacString (
2291 IN EFI_HANDLE ServiceHandle
,
2292 IN EFI_HANDLE ImageHandle
, OPTIONAL
2293 OUT CHAR16
**MacString
2297 EFI_MAC_ADDRESS MacAddress
;
2299 UINTN HwAddressSize
;
2305 ASSERT (MacString
!= NULL
);
2308 // Get MAC address of the network device
2310 Status
= NetLibGetMacAddress (ServiceHandle
, &MacAddress
, &HwAddressSize
);
2311 if (EFI_ERROR (Status
)) {
2316 // It takes 2 unicode characters to represent a 1 byte binary buffer.
2317 // If VLAN is configured, it will need extra 5 characters like "\0005".
2318 // Plus one unicode character for the null-terminator.
2320 BufferSize
= (2 * HwAddressSize
+ 5 + 1) * sizeof (CHAR16
);
2321 String
= AllocateZeroPool (BufferSize
);
2322 if (String
== NULL
) {
2323 return EFI_OUT_OF_RESOURCES
;
2325 *MacString
= String
;
2328 // Convert the MAC address into a unicode string.
2330 HwAddress
= &MacAddress
.Addr
[0];
2331 for (Index
= 0; Index
< HwAddressSize
; Index
++) {
2332 UnicodeValueToStringS (
2334 BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
),
2335 PREFIX_ZERO
| RADIX_HEX
,
2339 String
+= StrnLenS (String
, (BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
)) / sizeof (CHAR16
));
2343 // Append VLAN ID if any
2345 VlanId
= NetLibGetVlanId (ServiceHandle
);
2348 UnicodeValueToStringS (
2350 BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
),
2351 PREFIX_ZERO
| RADIX_HEX
,
2355 String
+= StrnLenS (String
, (BufferSize
- ((UINTN
)String
- (UINTN
)*MacString
)) / sizeof (CHAR16
));
2359 // Null terminate the Unicode string
2367 Detect media status for specified network device.
2369 If MediaPresent is NULL, then ASSERT().
2371 The underlying UNDI driver may or may not support reporting media status from
2372 GET_STATUS command (PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED). This routine
2373 will try to invoke Snp->GetStatus() to get the media status: if media already
2374 present, it return directly; if media not present, it will stop SNP and then
2375 restart SNP to get the latest media status, this give chance to get the correct
2376 media status for old UNDI driver which doesn't support reporting media status
2377 from GET_STATUS command.
2378 Note: there will be two limitations for current algorithm:
2379 1) for UNDI with this capability, in case of cable is not attached, there will
2380 be an redundant Stop/Start() process;
2381 2) for UNDI without this capability, in case that network cable is attached when
2382 Snp->Initialize() is invoked while network cable is unattached later,
2383 NetLibDetectMedia() will report MediaPresent as TRUE, causing upper layer
2384 apps to wait for timeout time.
2386 @param[in] ServiceHandle The handle where network service binding protocols are
2388 @param[out] MediaPresent The pointer to store the media status.
2390 @retval EFI_SUCCESS Media detection success.
2391 @retval EFI_INVALID_PARAMETER ServiceHandle is not valid network device handle.
2392 @retval EFI_UNSUPPORTED Network device does not support media detection.
2393 @retval EFI_DEVICE_ERROR SNP is in unknown state.
2399 IN EFI_HANDLE ServiceHandle
,
2400 OUT BOOLEAN
*MediaPresent
2404 EFI_HANDLE SnpHandle
;
2405 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2406 UINT32 InterruptStatus
;
2408 EFI_MAC_ADDRESS
*MCastFilter
;
2409 UINT32 MCastFilterCount
;
2410 UINT32 EnableFilterBits
;
2411 UINT32 DisableFilterBits
;
2412 BOOLEAN ResetMCastFilters
;
2414 ASSERT (MediaPresent
!= NULL
);
2420 SnpHandle
= NetLibGetSnpHandle (ServiceHandle
, &Snp
);
2421 if (SnpHandle
== NULL
) {
2422 return EFI_INVALID_PARAMETER
;
2426 // Check whether SNP support media detection
2428 if (!Snp
->Mode
->MediaPresentSupported
) {
2429 return EFI_UNSUPPORTED
;
2433 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
2435 Status
= Snp
->GetStatus (Snp
, &InterruptStatus
, NULL
);
2436 if (EFI_ERROR (Status
)) {
2440 if (Snp
->Mode
->MediaPresent
) {
2442 // Media is present, return directly
2444 *MediaPresent
= TRUE
;
2449 // Till now, GetStatus() report no media; while, in case UNDI not support
2450 // reporting media status from GetStatus(), this media status may be incorrect.
2451 // So, we will stop SNP and then restart it to get the correct media status.
2453 OldState
= Snp
->Mode
->State
;
2454 if (OldState
>= EfiSimpleNetworkMaxState
) {
2455 return EFI_DEVICE_ERROR
;
2460 if (OldState
== EfiSimpleNetworkInitialized
) {
2462 // SNP is already in use, need Shutdown/Stop and then Start/Initialize
2466 // Backup current SNP receive filter settings
2468 EnableFilterBits
= Snp
->Mode
->ReceiveFilterSetting
;
2469 DisableFilterBits
= Snp
->Mode
->ReceiveFilterMask
^ EnableFilterBits
;
2471 ResetMCastFilters
= TRUE
;
2472 MCastFilterCount
= Snp
->Mode
->MCastFilterCount
;
2473 if (MCastFilterCount
!= 0) {
2474 MCastFilter
= AllocateCopyPool (
2475 MCastFilterCount
* sizeof (EFI_MAC_ADDRESS
),
2476 Snp
->Mode
->MCastFilter
2478 ASSERT (MCastFilter
!= NULL
);
2479 if (MCastFilter
== NULL
) {
2480 Status
= EFI_OUT_OF_RESOURCES
;
2484 ResetMCastFilters
= FALSE
;
2488 // Shutdown/Stop the simple network
2490 Status
= Snp
->Shutdown (Snp
);
2491 if (!EFI_ERROR (Status
)) {
2492 Status
= Snp
->Stop (Snp
);
2494 if (EFI_ERROR (Status
)) {
2499 // Start/Initialize the simple network
2501 Status
= Snp
->Start (Snp
);
2502 if (!EFI_ERROR (Status
)) {
2503 Status
= Snp
->Initialize (Snp
, 0, 0);
2505 if (EFI_ERROR (Status
)) {
2510 // Here we get the correct media status
2512 *MediaPresent
= Snp
->Mode
->MediaPresent
;
2515 // Restore SNP receive filter settings
2517 Status
= Snp
->ReceiveFilters (
2526 if (MCastFilter
!= NULL
) {
2527 FreePool (MCastFilter
);
2534 // SNP is not in use, it's in state of EfiSimpleNetworkStopped or EfiSimpleNetworkStarted
2536 if (OldState
== EfiSimpleNetworkStopped
) {
2538 // SNP not start yet, start it
2540 Status
= Snp
->Start (Snp
);
2541 if (EFI_ERROR (Status
)) {
2547 // Initialize the simple network
2549 Status
= Snp
->Initialize (Snp
, 0, 0);
2550 if (EFI_ERROR (Status
)) {
2551 Status
= EFI_DEVICE_ERROR
;
2556 // Here we get the correct media status
2558 *MediaPresent
= Snp
->Mode
->MediaPresent
;
2561 // Shut down the simple network
2563 Snp
->Shutdown (Snp
);
2566 if (OldState
== EfiSimpleNetworkStopped
) {
2568 // Original SNP sate is Stopped, restore to original state
2573 if (MCastFilter
!= NULL
) {
2574 FreePool (MCastFilter
);
2582 Detect media state for a network device. This routine will wait for a period of time at
2583 a specified checking interval when a certain network is under connecting until connection
2584 process finishs or timeout. If Aip protocol is supported by low layer drivers, three kinds
2585 of media states can be detected: EFI_SUCCESS, EFI_NOT_READY and EFI_NO_MEDIA, represents
2586 connected state, connecting state and no media state respectively. When function detects
2587 the current state is EFI_NOT_READY, it will loop to wait for next time's check until state
2588 turns to be EFI_SUCCESS or EFI_NO_MEDIA. If Aip protocol is not supported, function will
2589 call NetLibDetectMedia() and return state directly.
2591 @param[in] ServiceHandle The handle where network service binding protocols are
2593 @param[in] Timeout The maximum number of 100ns units to wait when network
2594 is connecting. Zero value means detect once and return
2596 @param[out] MediaState The pointer to the detected media state.
2598 @retval EFI_SUCCESS Media detection success.
2599 @retval EFI_INVALID_PARAMETER ServiceHandle is not a valid network device handle or
2600 MediaState pointer is NULL.
2601 @retval EFI_DEVICE_ERROR A device error occurred.
2602 @retval EFI_TIMEOUT Network is connecting but timeout.
2607 NetLibDetectMediaWaitTimeout (
2608 IN EFI_HANDLE ServiceHandle
,
2610 OUT EFI_STATUS
*MediaState
2614 EFI_HANDLE SnpHandle
;
2615 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
2616 EFI_ADAPTER_INFORMATION_PROTOCOL
*Aip
;
2617 EFI_ADAPTER_INFO_MEDIA_STATE
*MediaInfo
;
2618 BOOLEAN MediaPresent
;
2620 EFI_STATUS TimerStatus
;
2622 UINT64 TimeRemained
;
2624 if (MediaState
== NULL
) {
2625 return EFI_INVALID_PARAMETER
;
2627 *MediaState
= EFI_SUCCESS
;
2634 SnpHandle
= NetLibGetSnpHandle (ServiceHandle
, &Snp
);
2635 if (SnpHandle
== NULL
) {
2636 return EFI_INVALID_PARAMETER
;
2639 Status
= gBS
->HandleProtocol (
2641 &gEfiAdapterInformationProtocolGuid
,
2644 if (EFI_ERROR (Status
)) {
2646 MediaPresent
= TRUE
;
2647 Status
= NetLibDetectMedia (ServiceHandle
, &MediaPresent
);
2648 if (!EFI_ERROR (Status
)) {
2650 *MediaState
= EFI_SUCCESS
;
2652 *MediaState
= EFI_NO_MEDIA
;
2657 // NetLibDetectMedia doesn't support EFI_NOT_READY status, return now!
2662 Status
= Aip
->GetInformation (
2664 &gEfiAdapterInfoMediaStateGuid
,
2665 (VOID
**) &MediaInfo
,
2668 if (!EFI_ERROR (Status
)) {
2670 *MediaState
= MediaInfo
->MediaState
;
2671 FreePool (MediaInfo
);
2672 if (*MediaState
!= EFI_NOT_READY
|| Timeout
< MEDIA_STATE_DETECT_TIME_INTERVAL
) {
2678 if (MediaInfo
!= NULL
) {
2679 FreePool (MediaInfo
);
2682 if (Status
== EFI_UNSUPPORTED
) {
2685 // If gEfiAdapterInfoMediaStateGuid is not supported, call NetLibDetectMedia to get media state!
2687 MediaPresent
= TRUE
;
2688 Status
= NetLibDetectMedia (ServiceHandle
, &MediaPresent
);
2689 if (!EFI_ERROR (Status
)) {
2691 *MediaState
= EFI_SUCCESS
;
2693 *MediaState
= EFI_NO_MEDIA
;
2703 // Loop to check media state
2707 TimeRemained
= Timeout
;
2708 Status
= gBS
->CreateEvent (EVT_TIMER
, TPL_CALLBACK
, NULL
, NULL
, &Timer
);
2709 if (EFI_ERROR (Status
)) {
2710 return EFI_DEVICE_ERROR
;
2714 Status
= gBS
->SetTimer (
2717 MEDIA_STATE_DETECT_TIME_INTERVAL
2719 if (EFI_ERROR (Status
)) {
2720 gBS
->CloseEvent(Timer
);
2721 return EFI_DEVICE_ERROR
;
2725 TimerStatus
= gBS
->CheckEvent (Timer
);
2726 if (!EFI_ERROR (TimerStatus
)) {
2728 TimeRemained
-= MEDIA_STATE_DETECT_TIME_INTERVAL
;
2729 Status
= Aip
->GetInformation (
2731 &gEfiAdapterInfoMediaStateGuid
,
2732 (VOID
**) &MediaInfo
,
2735 if (!EFI_ERROR (Status
)) {
2737 *MediaState
= MediaInfo
->MediaState
;
2738 FreePool (MediaInfo
);
2741 if (MediaInfo
!= NULL
) {
2742 FreePool (MediaInfo
);
2744 gBS
->CloseEvent(Timer
);
2748 } while (TimerStatus
== EFI_NOT_READY
);
2749 } while (*MediaState
== EFI_NOT_READY
&& TimeRemained
>= MEDIA_STATE_DETECT_TIME_INTERVAL
);
2751 gBS
->CloseEvent(Timer
);
2752 if (*MediaState
== EFI_NOT_READY
&& TimeRemained
< MEDIA_STATE_DETECT_TIME_INTERVAL
) {
2760 Check the default address used by the IPv4 driver is static or dynamic (acquired
2763 If the controller handle does not have the EFI_IP4_CONFIG2_PROTOCOL installed, the
2764 default address is static. If failed to get the policy from Ip4 Config2 Protocol,
2765 the default address is static. Otherwise, get the result from Ip4 Config2 Protocol.
2767 @param[in] Controller The controller handle which has the EFI_IP4_CONFIG2_PROTOCOL
2768 relative with the default address to judge.
2770 @retval TRUE If the default address is static.
2771 @retval FALSE If the default address is acquired from DHCP.
2775 NetLibDefaultAddressIsStatic (
2776 IN EFI_HANDLE Controller
2780 EFI_IP4_CONFIG2_PROTOCOL
*Ip4Config2
;
2782 EFI_IP4_CONFIG2_POLICY Policy
;
2787 DataSize
= sizeof (EFI_IP4_CONFIG2_POLICY
);
2792 // Get Ip4Config2 policy.
2794 Status
= gBS
->HandleProtocol (Controller
, &gEfiIp4Config2ProtocolGuid
, (VOID
**) &Ip4Config2
);
2795 if (EFI_ERROR (Status
)) {
2799 Status
= Ip4Config2
->GetData (Ip4Config2
, Ip4Config2DataTypePolicy
, &DataSize
, &Policy
);
2800 if (EFI_ERROR (Status
)) {
2804 IsStatic
= (BOOLEAN
) (Policy
== Ip4Config2PolicyStatic
);
2812 Create an IPv4 device path node.
2814 If Node is NULL, then ASSERT().
2816 The header type of IPv4 device path node is MESSAGING_DEVICE_PATH.
2817 The header subtype of IPv4 device path node is MSG_IPv4_DP.
2818 Get other info from parameters to make up the whole IPv4 device path node.
2820 @param[in, out] Node Pointer to the IPv4 device path node.
2821 @param[in] Controller The controller handle.
2822 @param[in] LocalIp The local IPv4 address.
2823 @param[in] LocalPort The local port.
2824 @param[in] RemoteIp The remote IPv4 address.
2825 @param[in] RemotePort The remote port.
2826 @param[in] Protocol The protocol type in the IP header.
2827 @param[in] UseDefaultAddress Whether this instance is using default address or not.
2832 NetLibCreateIPv4DPathNode (
2833 IN OUT IPv4_DEVICE_PATH
*Node
,
2834 IN EFI_HANDLE Controller
,
2835 IN IP4_ADDR LocalIp
,
2836 IN UINT16 LocalPort
,
2837 IN IP4_ADDR RemoteIp
,
2838 IN UINT16 RemotePort
,
2840 IN BOOLEAN UseDefaultAddress
2843 ASSERT (Node
!= NULL
);
2845 Node
->Header
.Type
= MESSAGING_DEVICE_PATH
;
2846 Node
->Header
.SubType
= MSG_IPv4_DP
;
2847 SetDevicePathNodeLength (&Node
->Header
, sizeof (IPv4_DEVICE_PATH
));
2849 CopyMem (&Node
->LocalIpAddress
, &LocalIp
, sizeof (EFI_IPv4_ADDRESS
));
2850 CopyMem (&Node
->RemoteIpAddress
, &RemoteIp
, sizeof (EFI_IPv4_ADDRESS
));
2852 Node
->LocalPort
= LocalPort
;
2853 Node
->RemotePort
= RemotePort
;
2855 Node
->Protocol
= Protocol
;
2857 if (!UseDefaultAddress
) {
2858 Node
->StaticIpAddress
= TRUE
;
2860 Node
->StaticIpAddress
= NetLibDefaultAddressIsStatic (Controller
);
2864 // Set the Gateway IP address to default value 0:0:0:0.
2865 // Set the Subnet mask to default value 255:255:255:0.
2867 ZeroMem (&Node
->GatewayIpAddress
, sizeof (EFI_IPv4_ADDRESS
));
2868 SetMem (&Node
->SubnetMask
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
2869 Node
->SubnetMask
.Addr
[3] = 0;
2873 Create an IPv6 device path node.
2875 If Node is NULL, then ASSERT().
2876 If LocalIp is NULL, then ASSERT().
2877 If RemoteIp is NULL, then ASSERT().
2879 The header type of IPv6 device path node is MESSAGING_DEVICE_PATH.
2880 The header subtype of IPv6 device path node is MSG_IPv6_DP.
2881 Get other info from parameters to make up the whole IPv6 device path node.
2883 @param[in, out] Node Pointer to the IPv6 device path node.
2884 @param[in] Controller The controller handle.
2885 @param[in] LocalIp The local IPv6 address.
2886 @param[in] LocalPort The local port.
2887 @param[in] RemoteIp The remote IPv6 address.
2888 @param[in] RemotePort The remote port.
2889 @param[in] Protocol The protocol type in the IP header.
2894 NetLibCreateIPv6DPathNode (
2895 IN OUT IPv6_DEVICE_PATH
*Node
,
2896 IN EFI_HANDLE Controller
,
2897 IN EFI_IPv6_ADDRESS
*LocalIp
,
2898 IN UINT16 LocalPort
,
2899 IN EFI_IPv6_ADDRESS
*RemoteIp
,
2900 IN UINT16 RemotePort
,
2904 ASSERT (Node
!= NULL
&& LocalIp
!= NULL
&& RemoteIp
!= NULL
);
2906 Node
->Header
.Type
= MESSAGING_DEVICE_PATH
;
2907 Node
->Header
.SubType
= MSG_IPv6_DP
;
2908 SetDevicePathNodeLength (&Node
->Header
, sizeof (IPv6_DEVICE_PATH
));
2910 CopyMem (&Node
->LocalIpAddress
, LocalIp
, sizeof (EFI_IPv6_ADDRESS
));
2911 CopyMem (&Node
->RemoteIpAddress
, RemoteIp
, sizeof (EFI_IPv6_ADDRESS
));
2913 Node
->LocalPort
= LocalPort
;
2914 Node
->RemotePort
= RemotePort
;
2916 Node
->Protocol
= Protocol
;
2919 // Set default value to IPAddressOrigin, PrefixLength.
2920 // Set the Gateway IP address to unspecified address.
2922 Node
->IpAddressOrigin
= 0;
2923 Node
->PrefixLength
= IP6_PREFIX_LENGTH
;
2924 ZeroMem (&Node
->GatewayIpAddress
, sizeof (EFI_IPv6_ADDRESS
));
2928 Find the UNDI/SNP handle from controller and protocol GUID.
2930 If ProtocolGuid is NULL, then ASSERT().
2932 For example, IP will open a MNP child to transmit/receive
2933 packets, when MNP is stopped, IP should also be stopped. IP
2934 needs to find its own private data which is related the IP's
2935 service binding instance that is install on UNDI/SNP handle.
2936 Now, the controller is either a MNP or ARP child handle. But
2937 IP opens these handle BY_DRIVER, use that info, we can get the
2940 @param[in] Controller Then protocol handle to check.
2941 @param[in] ProtocolGuid The protocol that is related with the handle.
2943 @return The UNDI/SNP handle or NULL for errors.
2948 NetLibGetNicHandle (
2949 IN EFI_HANDLE Controller
,
2950 IN EFI_GUID
*ProtocolGuid
2953 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenBuffer
;
2959 ASSERT (ProtocolGuid
!= NULL
);
2961 Status
= gBS
->OpenProtocolInformation (
2968 if (EFI_ERROR (Status
)) {
2974 for (Index
= 0; Index
< OpenCount
; Index
++) {
2975 if ((OpenBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_DRIVER
) != 0) {
2976 Handle
= OpenBuffer
[Index
].ControllerHandle
;
2981 gBS
->FreePool (OpenBuffer
);
2986 Convert one Null-terminated ASCII string (decimal dotted) to EFI_IPv4_ADDRESS.
2988 @param[in] String The pointer to the Ascii string.
2989 @param[out] Ip4Address The pointer to the converted IPv4 address.
2991 @retval EFI_SUCCESS Convert to IPv4 address successfully.
2992 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip4Address is NULL.
2997 NetLibAsciiStrToIp4 (
2998 IN CONST CHAR8
*String
,
2999 OUT EFI_IPv4_ADDRESS
*Ip4Address
3002 RETURN_STATUS Status
;
3005 Status
= AsciiStrToIpv4Address (String
, &EndPointer
, Ip4Address
, NULL
);
3006 if (RETURN_ERROR (Status
) || (*EndPointer
!= '\0')) {
3007 return EFI_INVALID_PARAMETER
;
3015 Convert one Null-terminated ASCII string to EFI_IPv6_ADDRESS. The format of the
3016 string is defined in RFC 4291 - Text Representation of Addresses.
3018 @param[in] String The pointer to the Ascii string.
3019 @param[out] Ip6Address The pointer to the converted IPv6 address.
3021 @retval EFI_SUCCESS Convert to IPv6 address successfully.
3022 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.
3027 NetLibAsciiStrToIp6 (
3028 IN CONST CHAR8
*String
,
3029 OUT EFI_IPv6_ADDRESS
*Ip6Address
3032 RETURN_STATUS Status
;
3035 Status
= AsciiStrToIpv6Address (String
, &EndPointer
, Ip6Address
, NULL
);
3036 if (RETURN_ERROR (Status
) || (*EndPointer
!= '\0')) {
3037 return EFI_INVALID_PARAMETER
;
3045 Convert one Null-terminated Unicode string (decimal dotted) to EFI_IPv4_ADDRESS.
3047 @param[in] String The pointer to the Ascii string.
3048 @param[out] Ip4Address The pointer to the converted IPv4 address.
3050 @retval EFI_SUCCESS Convert to IPv4 address successfully.
3051 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip4Address is NULL.
3057 IN CONST CHAR16
*String
,
3058 OUT EFI_IPv4_ADDRESS
*Ip4Address
3061 RETURN_STATUS Status
;
3064 Status
= StrToIpv4Address (String
, &EndPointer
, Ip4Address
, NULL
);
3065 if (RETURN_ERROR (Status
) || (*EndPointer
!= L
'\0')) {
3066 return EFI_INVALID_PARAMETER
;
3074 Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS. The format of
3075 the string is defined in RFC 4291 - Text Representation of Addresses.
3077 @param[in] String The pointer to the Ascii string.
3078 @param[out] Ip6Address The pointer to the converted IPv6 address.
3080 @retval EFI_SUCCESS Convert to IPv6 address successfully.
3081 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.
3087 IN CONST CHAR16
*String
,
3088 OUT EFI_IPv6_ADDRESS
*Ip6Address
3091 RETURN_STATUS Status
;
3094 Status
= StrToIpv6Address (String
, &EndPointer
, Ip6Address
, NULL
);
3095 if (RETURN_ERROR (Status
) || (*EndPointer
!= L
'\0')) {
3096 return EFI_INVALID_PARAMETER
;
3103 Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS and prefix length.
3104 The format of the string is defined in RFC 4291 - Text Representation of Addresses
3105 Prefixes: ipv6-address/prefix-length.
3107 @param[in] String The pointer to the Ascii string.
3108 @param[out] Ip6Address The pointer to the converted IPv6 address.
3109 @param[out] PrefixLength The pointer to the converted prefix length.
3111 @retval EFI_SUCCESS Convert to IPv6 address successfully.
3112 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.
3117 NetLibStrToIp6andPrefix (
3118 IN CONST CHAR16
*String
,
3119 OUT EFI_IPv6_ADDRESS
*Ip6Address
,
3120 OUT UINT8
*PrefixLength
3123 RETURN_STATUS Status
;
3126 Status
= StrToIpv6Address (String
, &EndPointer
, Ip6Address
, PrefixLength
);
3127 if (RETURN_ERROR (Status
) || (*EndPointer
!= L
'\0')) {
3128 return EFI_INVALID_PARAMETER
;
3136 Convert one EFI_IPv6_ADDRESS to Null-terminated Unicode string.
3137 The text representation of address is defined in RFC 4291.
3139 @param[in] Ip6Address The pointer to the IPv6 address.
3140 @param[out] String The buffer to return the converted string.
3141 @param[in] StringSize The length in bytes of the input String.
3143 @retval EFI_SUCCESS Convert to string successfully.
3144 @retval EFI_INVALID_PARAMETER The input parameter is invalid.
3145 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. BufferSize has been
3146 updated with the size needed to complete the request.
3151 IN EFI_IPv6_ADDRESS
*Ip6Address
,
3158 UINTN LongestZerosStart
;
3159 UINTN LongestZerosLength
;
3160 UINTN CurrentZerosStart
;
3161 UINTN CurrentZerosLength
;
3162 CHAR16 Buffer
[sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
3165 if (Ip6Address
== NULL
|| String
== NULL
|| StringSize
== 0) {
3166 return EFI_INVALID_PARAMETER
;
3170 // Convert the UINT8 array to an UINT16 array for easy handling.
3172 ZeroMem (Ip6Addr
, sizeof (Ip6Addr
));
3173 for (Index
= 0; Index
< 16; Index
++) {
3174 Ip6Addr
[Index
/ 2] |= (Ip6Address
->Addr
[Index
] << ((1 - (Index
% 2)) << 3));
3178 // Find the longest zeros and mark it.
3180 CurrentZerosStart
= DEFAULT_ZERO_START
;
3181 CurrentZerosLength
= 0;
3182 LongestZerosStart
= DEFAULT_ZERO_START
;
3183 LongestZerosLength
= 0;
3184 for (Index
= 0; Index
< 8; Index
++) {
3185 if (Ip6Addr
[Index
] == 0) {
3186 if (CurrentZerosStart
== DEFAULT_ZERO_START
) {
3187 CurrentZerosStart
= Index
;
3188 CurrentZerosLength
= 1;
3190 CurrentZerosLength
++;
3193 if (CurrentZerosStart
!= DEFAULT_ZERO_START
) {
3194 if (CurrentZerosLength
> 2 && (LongestZerosStart
== (DEFAULT_ZERO_START
) || CurrentZerosLength
> LongestZerosLength
)) {
3195 LongestZerosStart
= CurrentZerosStart
;
3196 LongestZerosLength
= CurrentZerosLength
;
3198 CurrentZerosStart
= DEFAULT_ZERO_START
;
3199 CurrentZerosLength
= 0;
3204 if (CurrentZerosStart
!= DEFAULT_ZERO_START
&& CurrentZerosLength
> 2) {
3205 if (LongestZerosStart
== DEFAULT_ZERO_START
|| LongestZerosLength
< CurrentZerosLength
) {
3206 LongestZerosStart
= CurrentZerosStart
;
3207 LongestZerosLength
= CurrentZerosLength
;
3212 for (Index
= 0; Index
< 8; Index
++) {
3213 if (LongestZerosStart
!= DEFAULT_ZERO_START
&& Index
>= LongestZerosStart
&& Index
< LongestZerosStart
+ LongestZerosLength
) {
3214 if (Index
== LongestZerosStart
) {
3222 Ptr
+= UnicodeSPrint(Ptr
, 10, L
"%x", Ip6Addr
[Index
]);
3225 if (LongestZerosStart
!= DEFAULT_ZERO_START
&& LongestZerosStart
+ LongestZerosLength
== 8) {
3230 if ((UINTN
)Ptr
- (UINTN
)Buffer
> StringSize
) {
3231 return EFI_BUFFER_TOO_SMALL
;
3234 StrCpyS (String
, StringSize
/ sizeof (CHAR16
), Buffer
);
3240 This function obtains the system guid from the smbios table.
3242 If SystemGuid is NULL, then ASSERT().
3244 @param[out] SystemGuid The pointer of the returned system guid.
3246 @retval EFI_SUCCESS Successfully obtained the system guid.
3247 @retval EFI_NOT_FOUND Did not find the SMBIOS table.
3252 NetLibGetSystemGuid (
3253 OUT EFI_GUID
*SystemGuid
3257 SMBIOS_TABLE_ENTRY_POINT
*SmbiosTable
;
3258 SMBIOS_TABLE_3_0_ENTRY_POINT
*Smbios30Table
;
3259 SMBIOS_STRUCTURE_POINTER Smbios
;
3260 SMBIOS_STRUCTURE_POINTER SmbiosEnd
;
3263 ASSERT (SystemGuid
!= NULL
);
3266 Status
= EfiGetSystemConfigurationTable (&gEfiSmbios3TableGuid
, (VOID
**) &Smbios30Table
);
3267 if (!(EFI_ERROR (Status
) || Smbios30Table
== NULL
)) {
3268 Smbios
.Hdr
= (SMBIOS_STRUCTURE
*) (UINTN
) Smbios30Table
->TableAddress
;
3269 SmbiosEnd
.Raw
= (UINT8
*) (UINTN
) (Smbios30Table
->TableAddress
+ Smbios30Table
->TableMaximumSize
);
3271 Status
= EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid
, (VOID
**) &SmbiosTable
);
3272 if (EFI_ERROR (Status
) || SmbiosTable
== NULL
) {
3273 return EFI_NOT_FOUND
;
3275 Smbios
.Hdr
= (SMBIOS_STRUCTURE
*) (UINTN
) SmbiosTable
->TableAddress
;
3276 SmbiosEnd
.Raw
= (UINT8
*) ((UINTN
) SmbiosTable
->TableAddress
+ SmbiosTable
->TableLength
);
3280 if (Smbios
.Hdr
->Type
== 1) {
3281 if (Smbios
.Hdr
->Length
< 0x19) {
3283 // Older version did not support UUID.
3285 return EFI_NOT_FOUND
;
3289 // SMBIOS tables are byte packed so we need to do a byte copy to
3290 // prevend alignment faults on Itanium-based platform.
3292 CopyMem (SystemGuid
, &Smbios
.Type1
->Uuid
, sizeof (EFI_GUID
));
3297 // Go to the next SMBIOS structure. Each SMBIOS structure may include 2 parts:
3298 // 1. Formatted section; 2. Unformatted string section. So, 2 steps are needed
3299 // to skip one SMBIOS structure.
3303 // Step 1: Skip over formatted section.
3305 String
= (CHAR8
*) (Smbios
.Raw
+ Smbios
.Hdr
->Length
);
3308 // Step 2: Skip over unformated string section.
3312 // Each string is terminated with a NULL(00h) BYTE and the sets of strings
3313 // is terminated with an additional NULL(00h) BYTE.
3315 for ( ; *String
!= 0; String
++) {
3318 if (*(UINT8
*)++String
== 0) {
3320 // Pointer to the next SMBIOS structure.
3322 Smbios
.Raw
= (UINT8
*)++String
;
3326 } while (Smbios
.Raw
< SmbiosEnd
.Raw
);
3327 return EFI_NOT_FOUND
;
3331 Create Dns QName according the queried domain name.
3333 If DomainName is NULL, then ASSERT().
3335 QName is a domain name represented as a sequence of labels,
3336 where each label consists of a length octet followed by that
3337 number of octets. The QName terminates with the zero
3338 length octet for the null label of the root. Caller should
3339 take responsibility to free the buffer in returned pointer.
3341 @param DomainName The pointer to the queried domain name string.
3343 @retval NULL Failed to fill QName.
3344 @return QName filled successfully.
3349 NetLibCreateDnsQName (
3350 IN CHAR16
*DomainName
3354 UINTN QueryNameSize
;
3360 ASSERT (DomainName
!= NULL
);
3368 // One byte for first label length, one byte for terminated length zero.
3370 QueryNameSize
= StrLen (DomainName
) + 2;
3372 if (QueryNameSize
> DNS_MAX_NAME_SIZE
) {
3376 QueryName
= AllocateZeroPool (QueryNameSize
);
3377 if (QueryName
== NULL
) {
3384 for (Index
= 0; DomainName
[Index
] != 0; Index
++) {
3385 *Tail
= (CHAR8
) DomainName
[Index
];
3387 *Header
= (CHAR8
) Len
;
3396 *Header
= (CHAR8
) Len
;