4 Copyright (c) 2005 - 2009, Intel Corporation.<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include <Protocol/DriverBinding.h>
17 #include <Protocol/ServiceBinding.h>
18 #include <Protocol/SimpleNetwork.h>
19 #include <Protocol/HiiConfigRouting.h>
20 #include <Protocol/ComponentName.h>
21 #include <Protocol/ComponentName2.h>
23 #include <Guid/NicIp4ConfigNvData.h>
25 #include <Library/NetLib.h>
26 #include <Library/BaseLib.h>
27 #include <Library/DebugLib.h>
28 #include <Library/BaseMemoryLib.h>
29 #include <Library/UefiBootServicesTableLib.h>
30 #include <Library/UefiRuntimeServicesTableLib.h>
31 #include <Library/MemoryAllocationLib.h>
32 #include <Library/DevicePathLib.h>
33 #include <Library/HiiLib.h>
34 #include <Library/PrintLib.h>
36 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mNetLibHexStr
[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
38 #define NIC_ITEM_CONFIG_SIZE sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE
41 // All the supported IP4 maskes in host byte order.
43 IP4_ADDR gIp4AllMasks
[IP4_MASK_NUM
] = {
82 EFI_IPv4_ADDRESS mZeroIp4Addr
= {{0, 0, 0, 0}};
85 // Any error level digitally larger than mNetDebugLevelMax
86 // will be silently discarded.
88 UINTN mNetDebugLevelMax
= NETDEBUG_LEVEL_ERROR
;
89 UINT32 mSyslogPacketSeq
= 0xDEADBEEF;
92 // You can change mSyslogDstMac mSyslogDstIp and mSyslogSrcIp
93 // here to direct the syslog packets to the syslog deamon. The
94 // default is broadcast to both the ethernet and IP.
96 UINT8 mSyslogDstMac
[NET_ETHER_ADDR_LEN
] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
97 UINT32 mSyslogDstIp
= 0xffffffff;
98 UINT32 mSyslogSrcIp
= 0;
117 Locate the handles that support SNP, then open one of them
118 to send the syslog packets. The caller isn't required to close
119 the SNP after use because the SNP is opened by HandleProtocol.
121 @return The point to SNP if one is properly openned. Otherwise NULL
124 EFI_SIMPLE_NETWORK_PROTOCOL
*
129 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
136 // Locate the handles which has SNP installed.
139 Status
= gBS
->LocateHandleBuffer (
141 &gEfiSimpleNetworkProtocolGuid
,
147 if (EFI_ERROR (Status
) || (HandleCount
== 0)) {
152 // Try to open one of the ethernet SNP protocol to send packet
156 for (Index
= 0; Index
< HandleCount
; Index
++) {
157 Status
= gBS
->HandleProtocol (
159 &gEfiSimpleNetworkProtocolGuid
,
163 if ((Status
== EFI_SUCCESS
) && (Snp
!= NULL
) &&
164 (Snp
->Mode
->IfType
== NET_IFTYPE_ETHERNET
) &&
165 (Snp
->Mode
->MaxPacketSize
>= NET_SYSLOG_PACKET_LEN
)) {
178 Transmit a syslog packet synchronously through SNP. The Packet
179 already has the ethernet header prepended. This function should
180 fill in the source MAC because it will try to locate a SNP each
181 time it is called to avoid the problem if SNP is unloaded.
182 This code snip is copied from MNP.
184 @param[in] Packet - The Syslog packet
185 @param[in] Length - The length of the packet
187 @retval EFI_DEVICE_ERROR - Failed to locate a usable SNP protocol
188 @retval EFI_TIMEOUT - Timeout happened to send the packet.
189 @retval EFI_SUCCESS - Packet is sent.
198 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
201 EFI_EVENT TimeoutEvent
;
204 Snp
= SyslogLocateSnp ();
207 return EFI_DEVICE_ERROR
;
210 Ether
= (ETHER_HEAD
*) Packet
;
211 CopyMem (Ether
->SrcMac
, Snp
->Mode
->CurrentAddress
.Addr
, NET_ETHER_ADDR_LEN
);
214 // Start the timeout event.
216 Status
= gBS
->CreateEvent (
224 if (EFI_ERROR (Status
)) {
228 Status
= gBS
->SetTimer (TimeoutEvent
, TimerRelative
, NET_SYSLOG_TX_TIMEOUT
);
230 if (EFI_ERROR (Status
)) {
236 // Transmit the packet through SNP.
238 Status
= Snp
->Transmit (Snp
, 0, Length
, Packet
, NULL
, NULL
, NULL
);
240 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_READY
)) {
241 Status
= EFI_DEVICE_ERROR
;
246 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.
247 // if Status is EFI_NOT_READY, the transmit engine of the network
248 // interface is busy. Both need to sync SNP.
254 // Get the recycled transmit buffer status.
256 Snp
->GetStatus (Snp
, NULL
, (VOID
**) &TxBuf
);
258 if (!EFI_ERROR (gBS
->CheckEvent (TimeoutEvent
))) {
259 Status
= EFI_TIMEOUT
;
263 } while (TxBuf
== NULL
);
265 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_TIMEOUT
)) {
270 // Status is EFI_NOT_READY. Restart the timer event and
271 // call Snp->Transmit again.
273 gBS
->SetTimer (TimeoutEvent
, TimerRelative
, NET_SYSLOG_TX_TIMEOUT
);
276 gBS
->SetTimer (TimeoutEvent
, TimerCancel
, 0);
279 gBS
->CloseEvent (TimeoutEvent
);
284 Build a syslog packet, including the Ethernet/Ip/Udp headers
287 @param[in] Level - Syslog servity level
288 @param[in] Module - The module that generates the log
289 @param[in] File - The file that contains the current log
290 @param[in] Line - The line of code in the File that contains the current log
291 @param[in] Message - The log message
292 @param[in] BufLen - The lenght of the Buf
293 @param[out] Buf - The buffer to put the packet data
297 The length of the syslog packet built.
313 EFI_UDP_HEADER
*Udp4
;
319 // Fill in the Ethernet header. Leave alone the source MAC.
320 // SyslogSendPacket will fill in the address for us.
322 Ether
= (ETHER_HEAD
*) Buf
;
323 CopyMem (Ether
->DstMac
, mSyslogDstMac
, NET_ETHER_ADDR_LEN
);
324 ZeroMem (Ether
->SrcMac
, NET_ETHER_ADDR_LEN
);
326 Ether
->EtherType
= HTONS (0x0800); // IPv4 protocol
328 Buf
+= sizeof (ETHER_HEAD
);
329 BufLen
-= sizeof (ETHER_HEAD
);
332 // Fill in the IP header
334 Ip4
= (IP4_HEAD
*) Buf
;
339 Ip4
->Id
= (UINT16
) mSyslogPacketSeq
;
342 Ip4
->Protocol
= 0x11;
344 Ip4
->Src
= mSyslogSrcIp
;
345 Ip4
->Dst
= mSyslogDstIp
;
347 Buf
+= sizeof (IP4_HEAD
);
348 BufLen
-= sizeof (IP4_HEAD
);
351 // Fill in the UDP header, Udp checksum is optional. Leave it zero.
353 Udp4
= (EFI_UDP_HEADER
*) Buf
;
354 Udp4
->SrcPort
= HTONS (514);
355 Udp4
->DstPort
= HTONS (514);
359 Buf
+= sizeof (EFI_UDP_HEADER
);
360 BufLen
-= sizeof (EFI_UDP_HEADER
);
363 // Build the syslog message body with <PRI> Timestamp machine module Message
365 Pri
= ((NET_SYSLOG_FACILITY
& 31) << 3) | (Level
& 7);
366 gRT
->GetTime (&Time
, NULL
);
369 // Use %a to format the ASCII strings, %s to format UNICODE strings
372 Len
+= (UINT32
) AsciiSPrint (
375 "<%d> %a %d %d:%d:%d ",
377 mMonthName
[Time
.Month
-1],
385 Len
+= (UINT32
) AsciiSPrint (
388 "Tiano %a: %a (Line: %d File: %a)",
397 // OK, patch the IP length/checksum and UDP length fields.
399 Len
+= sizeof (EFI_UDP_HEADER
);
400 Udp4
->Length
= HTONS ((UINT16
) Len
);
402 Len
+= sizeof (IP4_HEAD
);
403 Ip4
->TotalLen
= HTONS ((UINT16
) Len
);
404 Ip4
->Checksum
= (UINT16
) (~NetblockChecksum ((UINT8
*) Ip4
, sizeof (IP4_HEAD
)));
406 return Len
+ sizeof (ETHER_HEAD
);
410 Allocate a buffer, then format the message to it. This is a
411 help function for the NET_DEBUG_XXX macros. The PrintArg of
412 these macros treats the variable length print parameters as a
413 single parameter, and pass it to the NetDebugASPrint. For
414 example, NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name))
418 NETDEBUG_LEVEL_TRACE,
422 NetDebugASPrint ("State transit to %a\n", Name)
425 @param Format The ASCII format string.
426 @param ... The variable length parameter whose format is determined
427 by the Format string.
429 @return The buffer containing the formatted message,
430 or NULL if failed to allocate memory.
442 Buf
= (CHAR8
*) AllocatePool (NET_DEBUG_MSG_LEN
);
448 VA_START (Marker
, Format
);
449 AsciiVSPrint (Buf
, NET_DEBUG_MSG_LEN
, Format
, Marker
);
456 Builds an UDP4 syslog packet and send it using SNP.
458 This function will locate a instance of SNP then send the message through it.
459 Because it isn't open the SNP BY_DRIVER, apply caution when using it.
461 @param Level The servity level of the message.
462 @param Module The Moudle that generates the log.
463 @param File The file that contains the log.
464 @param Line The exact line that contains the log.
465 @param Message The user message to log.
467 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
468 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet
469 @retval EFI_SUCCESS The log is discard because that it is more verbose
470 than the mNetDebugLevelMax. Or, it has been sent out.
486 // Check whether the message should be sent out
488 if (Message
== NULL
) {
489 return EFI_INVALID_PARAMETER
;
492 if (Level
> mNetDebugLevelMax
) {
493 Status
= EFI_SUCCESS
;
498 // Allocate a maxium of 1024 bytes, the caller should ensure
499 // that the message plus the ethernet/ip/udp header is shorter
502 Packet
= (CHAR8
*) AllocatePool (NET_SYSLOG_PACKET_LEN
);
504 if (Packet
== NULL
) {
505 Status
= EFI_OUT_OF_RESOURCES
;
510 // Build the message: Ethernet header + IP header + Udp Header + user data
512 Len
= SyslogBuildPacket (
518 NET_SYSLOG_PACKET_LEN
,
523 Status
= SyslogSendPacket (Packet
, Len
);
531 Return the length of the mask.
533 Return the length of the mask, the correct value is from 0 to 32.
534 If the mask is invalid, return the invalid length 33, which is IP4_MASK_NUM.
535 NetMask is in the host byte order.
537 @param[in] NetMask The netmask to get the length from.
539 @return The length of the netmask, IP4_MASK_NUM if the mask is invalid.
550 for (Index
= 0; Index
< IP4_MASK_NUM
; Index
++) {
551 if (NetMask
== gIp4AllMasks
[Index
]) {
562 Return the class of the IP address, such as class A, B, C.
563 Addr is in host byte order.
565 The address of class A starts with 0.
566 If the address belong to class A, return IP4_ADDR_CLASSA.
567 The address of class B starts with 10.
568 If the address belong to class B, return IP4_ADDR_CLASSB.
569 The address of class C starts with 110.
570 If the address belong to class C, return IP4_ADDR_CLASSC.
571 The address of class D starts with 1110.
572 If the address belong to class D, return IP4_ADDR_CLASSD.
573 The address of class E starts with 1111.
574 If the address belong to class E, return IP4_ADDR_CLASSE.
577 @param[in] Addr The address to get the class from.
579 @return IP address class, such as IP4_ADDR_CLASSA.
590 ByteOne
= (UINT8
) (Addr
>> 24);
592 if ((ByteOne
& 0x80) == 0) {
593 return IP4_ADDR_CLASSA
;
595 } else if ((ByteOne
& 0xC0) == 0x80) {
596 return IP4_ADDR_CLASSB
;
598 } else if ((ByteOne
& 0xE0) == 0xC0) {
599 return IP4_ADDR_CLASSC
;
601 } else if ((ByteOne
& 0xF0) == 0xE0) {
602 return IP4_ADDR_CLASSD
;
605 return IP4_ADDR_CLASSE
;
612 Check whether the IP is a valid unicast address according to
613 the netmask. If NetMask is zero, use the IP address's class to get the default mask.
615 If Ip is 0, IP is not a valid unicast address.
616 Class D address is used for multicasting and class E address is reserved for future. If Ip
617 belongs to class D or class E, IP is not a valid unicast address.
618 If all bits of the host address of IP are 0 or 1, IP is also not a valid unicast address.
620 @param[in] Ip The IP to check against.
621 @param[in] NetMask The mask of the IP.
623 @return TRUE if IP is a valid unicast address on the network, otherwise FALSE.
635 Class
= NetGetIpClass (Ip
);
637 if ((Ip
== 0) || (Class
>= IP4_ADDR_CLASSD
)) {
642 NetMask
= gIp4AllMasks
[Class
<< 3];
645 if (((Ip
&~NetMask
) == ~NetMask
) || ((Ip
&~NetMask
) == 0)) {
653 Check whether the incoming IPv6 address is a valid unicast address.
655 If the address is a multicast address has binary 0xFF at the start, it is not
656 a valid unicast address. If the address is unspecified ::, it is not a valid
657 unicast address to be assigned to any node. If the address is loopback address
658 ::1, it is also not a valid unicast address to be assigned to any physical
661 @param[in] Ip6 The IPv6 address to check against.
663 @return TRUE if Ip6 is a valid unicast address on the network, otherwise FALSE.
667 NetIp6IsValidUnicast (
668 IN EFI_IPv6_ADDRESS
*Ip6
674 if (Ip6
->Addr
[0] == 0xFF) {
678 for (Index
= 0; Index
< 15; Index
++) {
679 if (Ip6
->Addr
[Index
] != 0) {
684 Byte
= Ip6
->Addr
[Index
];
686 if (Byte
== 0x0 || Byte
== 0x1) {
694 Check whether the incoming Ipv6 address is the unspecified address or not.
696 @param[in] Ip6 - Ip6 address, in network order.
698 @retval TRUE - Yes, unspecified
703 NetIp6IsUnspecifiedAddr (
704 IN EFI_IPv6_ADDRESS
*Ip6
709 for (Index
= 0; Index
< 16; Index
++) {
710 if (Ip6
->Addr
[Index
] != 0) {
719 Check whether the incoming Ipv6 address is a link-local address.
721 @param[in] Ip6 - Ip6 address, in network order.
723 @retval TRUE - Yes, link-local address
728 NetIp6IsLinkLocalAddr (
729 IN EFI_IPv6_ADDRESS
*Ip6
734 ASSERT (Ip6
!= NULL
);
736 if (Ip6
->Addr
[0] != 0xFE) {
740 if (Ip6
->Addr
[1] != 0x80) {
744 for (Index
= 2; Index
< 8; Index
++) {
745 if (Ip6
->Addr
[Index
] != 0) {
754 Check whether the Ipv6 address1 and address2 are on the connected network.
756 @param[in] Ip1 - Ip6 address1, in network order.
757 @param[in] Ip2 - Ip6 address2, in network order.
758 @param[in] PrefixLength - The prefix length of the checking net.
760 @retval TRUE - Yes, connected.
766 EFI_IPv6_ADDRESS
*Ip1
,
767 EFI_IPv6_ADDRESS
*Ip2
,
775 ASSERT (Ip1
!= NULL
&& Ip2
!= NULL
);
777 if (PrefixLength
== 0) {
781 Byte
= (UINT8
) (PrefixLength
/ 8);
782 Bit
= (UINT8
) (PrefixLength
% 8);
784 if (CompareMem (Ip1
, Ip2
, Byte
) != 0) {
789 Mask
= (UINT8
) (0xFF << (8 - Bit
));
791 if ((Ip1
->Addr
[Byte
] & Mask
) != (Ip2
->Addr
[Byte
] & Mask
)) {
801 Switches the endianess of an IPv6 address
803 This function swaps the bytes in a 128-bit IPv6 address to switch the value
804 from little endian to big endian or vice versa. The byte swapped value is
807 @param Ip6 Points to an IPv6 address
809 @return The byte swapped IPv6 address.
814 EFI_IPv6_ADDRESS
*Ip6
820 CopyMem (&High
, Ip6
, sizeof (UINT64
));
821 CopyMem (&Low
, &Ip6
->Addr
[8], sizeof (UINT64
));
823 High
= SwapBytes64 (High
);
824 Low
= SwapBytes64 (Low
);
826 CopyMem (Ip6
, &Low
, sizeof (UINT64
));
827 CopyMem (&Ip6
->Addr
[8], &High
, sizeof (UINT64
));
833 Initialize a random seed using current time.
835 Get current time first. Then initialize a random seed based on some basic
836 mathematics operation on the hour, day, minute, second, nanosecond and year
839 @return The random seed initialized with current time.
851 gRT
->GetTime (&Time
, NULL
);
852 Seed
= (~Time
.Hour
<< 24 | Time
.Day
<< 16 | Time
.Minute
<< 8 | Time
.Second
);
853 Seed
^= Time
.Nanosecond
;
854 Seed
^= Time
.Year
<< 7;
861 Extract a UINT32 from a byte stream.
863 Copy a UINT32 from a byte stream, then converts it from Network
864 byte order to host byte order. Use this function to avoid alignment error.
866 @param[in] Buf The buffer to extract the UINT32.
868 @return The UINT32 extracted.
879 CopyMem (&Value
, Buf
, sizeof (UINT32
));
880 return NTOHL (Value
);
885 Put a UINT32 to the byte stream in network byte order.
887 Converts a UINT32 from host byte order to network byte order. Then copy it to the
890 @param[in, out] Buf The buffer to put the UINT32.
891 @param[in] Data The data to put.
902 CopyMem (Buf
, &Data
, sizeof (UINT32
));
907 Remove the first node entry on the list, and return the removed node entry.
909 Removes the first node Entry from a doubly linked list. It is up to the caller of
910 this function to release the memory used by the first node if that is required. On
911 exit, the removed node is returned.
913 If Head is NULL, then ASSERT().
914 If Head was not initialized, then ASSERT().
915 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
916 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
919 @param[in, out] Head The list header.
921 @return The first node entry that is removed from the list, NULL if the list is empty.
927 IN OUT LIST_ENTRY
*Head
932 ASSERT (Head
!= NULL
);
934 if (IsListEmpty (Head
)) {
938 First
= Head
->ForwardLink
;
939 Head
->ForwardLink
= First
->ForwardLink
;
940 First
->ForwardLink
->BackLink
= Head
;
943 First
->ForwardLink
= (LIST_ENTRY
*) NULL
;
944 First
->BackLink
= (LIST_ENTRY
*) NULL
;
952 Remove the last node entry on the list and and return the removed node entry.
954 Removes the last node entry from a doubly linked list. It is up to the caller of
955 this function to release the memory used by the first node if that is required. On
956 exit, the removed node is returned.
958 If Head is NULL, then ASSERT().
959 If Head was not initialized, then ASSERT().
960 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the
961 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,
964 @param[in, out] Head The list head.
966 @return The last node entry that is removed from the list, NULL if the list is empty.
972 IN OUT LIST_ENTRY
*Head
977 ASSERT (Head
!= NULL
);
979 if (IsListEmpty (Head
)) {
983 Last
= Head
->BackLink
;
984 Head
->BackLink
= Last
->BackLink
;
985 Last
->BackLink
->ForwardLink
= Head
;
988 Last
->ForwardLink
= (LIST_ENTRY
*) NULL
;
989 Last
->BackLink
= (LIST_ENTRY
*) NULL
;
997 Insert a new node entry after a designated node entry of a doubly linked list.
999 Inserts a new node entry donated by NewEntry after the node entry donated by PrevEntry
1000 of the doubly linked list.
1002 @param[in, out] PrevEntry The previous entry to insert after.
1003 @param[in, out] NewEntry The new entry to insert.
1008 NetListInsertAfter (
1009 IN OUT LIST_ENTRY
*PrevEntry
,
1010 IN OUT LIST_ENTRY
*NewEntry
1013 NewEntry
->BackLink
= PrevEntry
;
1014 NewEntry
->ForwardLink
= PrevEntry
->ForwardLink
;
1015 PrevEntry
->ForwardLink
->BackLink
= NewEntry
;
1016 PrevEntry
->ForwardLink
= NewEntry
;
1021 Insert a new node entry before a designated node entry of a doubly linked list.
1023 Inserts a new node entry donated by NewEntry after the node entry donated by PostEntry
1024 of the doubly linked list.
1026 @param[in, out] PostEntry The entry to insert before.
1027 @param[in, out] NewEntry The new entry to insert.
1032 NetListInsertBefore (
1033 IN OUT LIST_ENTRY
*PostEntry
,
1034 IN OUT LIST_ENTRY
*NewEntry
1037 NewEntry
->ForwardLink
= PostEntry
;
1038 NewEntry
->BackLink
= PostEntry
->BackLink
;
1039 PostEntry
->BackLink
->ForwardLink
= NewEntry
;
1040 PostEntry
->BackLink
= NewEntry
;
1045 Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.
1047 Initialize the forward and backward links of two head nodes donated by Map->Used
1048 and Map->Recycled of two doubly linked lists.
1049 Initializes the count of the <Key, Value> pairs in the netmap to zero.
1051 If Map is NULL, then ASSERT().
1052 If the address of Map->Used is NULL, then ASSERT().
1053 If the address of Map->Recycled is NULl, then ASSERT().
1055 @param[in, out] Map The netmap to initialize.
1064 ASSERT (Map
!= NULL
);
1066 InitializeListHead (&Map
->Used
);
1067 InitializeListHead (&Map
->Recycled
);
1073 To clean up the netmap, that is, release allocated memories.
1075 Removes all nodes of the Used doubly linked list and free memory of all related netmap items.
1076 Removes all nodes of the Recycled doubly linked list and free memory of all related netmap items.
1077 The number of the <Key, Value> pairs in the netmap is set to be zero.
1079 If Map is NULL, then ASSERT().
1081 @param[in, out] Map The netmap to clean up.
1094 ASSERT (Map
!= NULL
);
1096 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &Map
->Used
) {
1097 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1099 RemoveEntryList (&Item
->Link
);
1102 gBS
->FreePool (Item
);
1105 ASSERT ((Map
->Count
== 0) && IsListEmpty (&Map
->Used
));
1107 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &Map
->Recycled
) {
1108 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1110 RemoveEntryList (&Item
->Link
);
1111 gBS
->FreePool (Item
);
1114 ASSERT (IsListEmpty (&Map
->Recycled
));
1119 Test whether the netmap is empty and return true if it is.
1121 If the number of the <Key, Value> pairs in the netmap is zero, return TRUE.
1123 If Map is NULL, then ASSERT().
1126 @param[in] Map The net map to test.
1128 @return TRUE if the netmap is empty, otherwise FALSE.
1137 ASSERT (Map
!= NULL
);
1138 return (BOOLEAN
) (Map
->Count
== 0);
1143 Return the number of the <Key, Value> pairs in the netmap.
1145 @param[in] Map The netmap to get the entry number.
1147 @return The entry number in the netmap.
1161 Return one allocated item.
1163 If the Recycled doubly linked list of the netmap is empty, it will try to allocate
1164 a batch of items if there are enough resources and add corresponding nodes to the begining
1165 of the Recycled doubly linked list of the netmap. Otherwise, it will directly remove
1166 the fist node entry of the Recycled doubly linked list and return the corresponding item.
1168 If Map is NULL, then ASSERT().
1170 @param[in, out] Map The netmap to allocate item for.
1172 @return The allocated item. If NULL, the
1173 allocation failed due to resource limit.
1185 ASSERT (Map
!= NULL
);
1187 Head
= &Map
->Recycled
;
1189 if (IsListEmpty (Head
)) {
1190 for (Index
= 0; Index
< NET_MAP_INCREAMENT
; Index
++) {
1191 Item
= AllocatePool (sizeof (NET_MAP_ITEM
));
1201 InsertHeadList (Head
, &Item
->Link
);
1205 Item
= NET_LIST_HEAD (Head
, NET_MAP_ITEM
, Link
);
1206 NetListRemoveHead (Head
);
1213 Allocate an item to save the <Key, Value> pair to the head of the netmap.
1215 Allocate an item to save the <Key, Value> pair and add corresponding node entry
1216 to the beginning of the Used doubly linked list. The number of the <Key, Value>
1217 pairs in the netmap increase by 1.
1219 If Map is NULL, then ASSERT().
1221 @param[in, out] Map The netmap to insert into.
1222 @param[in] Key The user's key.
1223 @param[in] Value The user's value for the key.
1225 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
1226 @retval EFI_SUCCESS The item is inserted to the head.
1232 IN OUT NET_MAP
*Map
,
1234 IN VOID
*Value OPTIONAL
1239 ASSERT (Map
!= NULL
);
1241 Item
= NetMapAllocItem (Map
);
1244 return EFI_OUT_OF_RESOURCES
;
1248 Item
->Value
= Value
;
1249 InsertHeadList (&Map
->Used
, &Item
->Link
);
1257 Allocate an item to save the <Key, Value> pair to the tail of the netmap.
1259 Allocate an item to save the <Key, Value> pair and add corresponding node entry
1260 to the tail of the Used doubly linked list. The number of the <Key, Value>
1261 pairs in the netmap increase by 1.
1263 If Map is NULL, then ASSERT().
1265 @param[in, out] Map The netmap to insert into.
1266 @param[in] Key The user's key.
1267 @param[in] Value The user's value for the key.
1269 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.
1270 @retval EFI_SUCCESS The item is inserted to the tail.
1276 IN OUT NET_MAP
*Map
,
1278 IN VOID
*Value OPTIONAL
1283 ASSERT (Map
!= NULL
);
1285 Item
= NetMapAllocItem (Map
);
1288 return EFI_OUT_OF_RESOURCES
;
1292 Item
->Value
= Value
;
1293 InsertTailList (&Map
->Used
, &Item
->Link
);
1302 Check whether the item is in the Map and return TRUE if it is.
1304 @param[in] Map The netmap to search within.
1305 @param[in] Item The item to search.
1307 @return TRUE if the item is in the netmap, otherwise FALSE.
1313 IN NET_MAP_ITEM
*Item
1316 LIST_ENTRY
*ListEntry
;
1318 NET_LIST_FOR_EACH (ListEntry
, &Map
->Used
) {
1319 if (ListEntry
== &Item
->Link
) {
1329 Find the key in the netmap and returns the point to the item contains the Key.
1331 Iterate the Used doubly linked list of the netmap to get every item. Compare the key of every
1332 item with the key to search. It returns the point to the item contains the Key if found.
1334 If Map is NULL, then ASSERT().
1336 @param[in] Map The netmap to search within.
1337 @param[in] Key The key to search.
1339 @return The point to the item contains the Key, or NULL if Key isn't in the map.
1352 ASSERT (Map
!= NULL
);
1354 NET_LIST_FOR_EACH (Entry
, &Map
->Used
) {
1355 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1357 if (Item
->Key
== Key
) {
1367 Remove the node entry of the item from the netmap and return the key of the removed item.
1369 Remove the node entry of the item from the Used doubly linked list of the netmap.
1370 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1371 entry of the item to the Recycled doubly linked list of the netmap. If Value is not NULL,
1372 Value will point to the value of the item. It returns the key of the removed item.
1374 If Map is NULL, then ASSERT().
1375 If Item is NULL, then ASSERT().
1376 if item in not in the netmap, then ASSERT().
1378 @param[in, out] Map The netmap to remove the item from.
1379 @param[in, out] Item The item to remove.
1380 @param[out] Value The variable to receive the value if not NULL.
1382 @return The key of the removed item.
1388 IN OUT NET_MAP
*Map
,
1389 IN OUT NET_MAP_ITEM
*Item
,
1390 OUT VOID
**Value OPTIONAL
1393 ASSERT ((Map
!= NULL
) && (Item
!= NULL
));
1394 ASSERT (NetItemInMap (Map
, Item
));
1396 RemoveEntryList (&Item
->Link
);
1398 InsertHeadList (&Map
->Recycled
, &Item
->Link
);
1400 if (Value
!= NULL
) {
1401 *Value
= Item
->Value
;
1409 Remove the first node entry on the netmap and return the key of the removed item.
1411 Remove the first node entry from the Used doubly linked list of the netmap.
1412 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1413 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
1414 parameter Value will point to the value of the item. It returns the key of the removed item.
1416 If Map is NULL, then ASSERT().
1417 If the Used doubly linked list is empty, then ASSERT().
1419 @param[in, out] Map The netmap to remove the head from.
1420 @param[out] Value The variable to receive the value if not NULL.
1422 @return The key of the item removed.
1428 IN OUT NET_MAP
*Map
,
1429 OUT VOID
**Value OPTIONAL
1435 // Often, it indicates a programming error to remove
1436 // the first entry in an empty list
1438 ASSERT (Map
&& !IsListEmpty (&Map
->Used
));
1440 Item
= NET_LIST_HEAD (&Map
->Used
, NET_MAP_ITEM
, Link
);
1441 RemoveEntryList (&Item
->Link
);
1443 InsertHeadList (&Map
->Recycled
, &Item
->Link
);
1445 if (Value
!= NULL
) {
1446 *Value
= Item
->Value
;
1454 Remove the last node entry on the netmap and return the key of the removed item.
1456 Remove the last node entry from the Used doubly linked list of the netmap.
1457 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node
1458 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,
1459 parameter Value will point to the value of the item. It returns the key of the removed item.
1461 If Map is NULL, then ASSERT().
1462 If the Used doubly linked list is empty, then ASSERT().
1464 @param[in, out] Map The netmap to remove the tail from.
1465 @param[out] Value The variable to receive the value if not NULL.
1467 @return The key of the item removed.
1473 IN OUT NET_MAP
*Map
,
1474 OUT VOID
**Value OPTIONAL
1480 // Often, it indicates a programming error to remove
1481 // the last entry in an empty list
1483 ASSERT (Map
&& !IsListEmpty (&Map
->Used
));
1485 Item
= NET_LIST_TAIL (&Map
->Used
, NET_MAP_ITEM
, Link
);
1486 RemoveEntryList (&Item
->Link
);
1488 InsertHeadList (&Map
->Recycled
, &Item
->Link
);
1490 if (Value
!= NULL
) {
1491 *Value
= Item
->Value
;
1499 Iterate through the netmap and call CallBack for each item.
1501 It will contiue the traverse if CallBack returns EFI_SUCCESS, otherwise, break
1502 from the loop. It returns the CallBack's last return value. This function is
1503 delete safe for the current item.
1505 If Map is NULL, then ASSERT().
1506 If CallBack is NULL, then ASSERT().
1508 @param[in] Map The Map to iterate through.
1509 @param[in] CallBack The callback function to call for each item.
1510 @param[in] Arg The opaque parameter to the callback.
1512 @retval EFI_SUCCESS There is no item in the netmap or CallBack for each item
1514 @retval Others It returns the CallBack's last return value.
1521 IN NET_MAP_CALLBACK CallBack
,
1532 ASSERT ((Map
!= NULL
) && (CallBack
!= NULL
));
1536 if (IsListEmpty (Head
)) {
1540 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, Head
) {
1541 Item
= NET_LIST_USER_STRUCT (Entry
, NET_MAP_ITEM
, Link
);
1542 Result
= CallBack (Map
, Item
, Arg
);
1544 if (EFI_ERROR (Result
)) {
1554 This is the default unload handle for all the network drivers.
1556 Disconnect the driver specified by ImageHandle from all the devices in the handle database.
1557 Uninstall all the protocols installed in the driver entry point.
1559 @param[in] ImageHandle The drivers' driver image.
1561 @retval EFI_SUCCESS The image is unloaded.
1562 @retval Others Failed to unload the image.
1567 NetLibDefaultUnload (
1568 IN EFI_HANDLE ImageHandle
1572 EFI_HANDLE
*DeviceHandleBuffer
;
1573 UINTN DeviceHandleCount
;
1575 EFI_DRIVER_BINDING_PROTOCOL
*DriverBinding
;
1576 EFI_COMPONENT_NAME_PROTOCOL
*ComponentName
;
1577 EFI_COMPONENT_NAME2_PROTOCOL
*ComponentName2
;
1580 // Get the list of all the handles in the handle database.
1581 // If there is an error getting the list, then the unload
1584 Status
= gBS
->LocateHandleBuffer (
1592 if (EFI_ERROR (Status
)) {
1597 // Disconnect the driver specified by ImageHandle from all
1598 // the devices in the handle database.
1600 for (Index
= 0; Index
< DeviceHandleCount
; Index
++) {
1601 Status
= gBS
->DisconnectController (
1602 DeviceHandleBuffer
[Index
],
1609 // Uninstall all the protocols installed in the driver entry point
1611 for (Index
= 0; Index
< DeviceHandleCount
; Index
++) {
1612 Status
= gBS
->HandleProtocol (
1613 DeviceHandleBuffer
[Index
],
1614 &gEfiDriverBindingProtocolGuid
,
1615 (VOID
**) &DriverBinding
1618 if (EFI_ERROR (Status
)) {
1622 if (DriverBinding
->ImageHandle
!= ImageHandle
) {
1626 gBS
->UninstallProtocolInterface (
1628 &gEfiDriverBindingProtocolGuid
,
1631 Status
= gBS
->HandleProtocol (
1632 DeviceHandleBuffer
[Index
],
1633 &gEfiComponentNameProtocolGuid
,
1634 (VOID
**) &ComponentName
1636 if (!EFI_ERROR (Status
)) {
1637 gBS
->UninstallProtocolInterface (
1639 &gEfiComponentNameProtocolGuid
,
1644 Status
= gBS
->HandleProtocol (
1645 DeviceHandleBuffer
[Index
],
1646 &gEfiComponentName2ProtocolGuid
,
1647 (VOID
**) &ComponentName2
1649 if (!EFI_ERROR (Status
)) {
1650 gBS
->UninstallProtocolInterface (
1652 &gEfiComponentName2ProtocolGuid
,
1659 // Free the buffer containing the list of handles from the handle database
1661 if (DeviceHandleBuffer
!= NULL
) {
1662 gBS
->FreePool (DeviceHandleBuffer
);
1671 Create a child of the service that is identified by ServiceBindingGuid.
1673 Get the ServiceBinding Protocol first, then use it to create a child.
1675 If ServiceBindingGuid is NULL, then ASSERT().
1676 If ChildHandle is NULL, then ASSERT().
1678 @param[in] Controller The controller which has the service installed.
1679 @param[in] Image The image handle used to open service.
1680 @param[in] ServiceBindingGuid The service's Guid.
1681 @param[in, out] ChildHandle The handle to receive the create child.
1683 @retval EFI_SUCCESS The child is successfully created.
1684 @retval Others Failed to create the child.
1689 NetLibCreateServiceChild (
1690 IN EFI_HANDLE Controller
,
1691 IN EFI_HANDLE Image
,
1692 IN EFI_GUID
*ServiceBindingGuid
,
1693 IN OUT EFI_HANDLE
*ChildHandle
1697 EFI_SERVICE_BINDING_PROTOCOL
*Service
;
1700 ASSERT ((ServiceBindingGuid
!= NULL
) && (ChildHandle
!= NULL
));
1703 // Get the ServiceBinding Protocol
1705 Status
= gBS
->OpenProtocol (
1711 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1714 if (EFI_ERROR (Status
)) {
1721 Status
= Service
->CreateChild (Service
, ChildHandle
);
1727 Destory a child of the service that is identified by ServiceBindingGuid.
1729 Get the ServiceBinding Protocol first, then use it to destroy a child.
1731 If ServiceBindingGuid is NULL, then ASSERT().
1733 @param[in] Controller The controller which has the service installed.
1734 @param[in] Image The image handle used to open service.
1735 @param[in] ServiceBindingGuid The service's Guid.
1736 @param[in] ChildHandle The child to destory.
1738 @retval EFI_SUCCESS The child is successfully destoried.
1739 @retval Others Failed to destory the child.
1744 NetLibDestroyServiceChild (
1745 IN EFI_HANDLE Controller
,
1746 IN EFI_HANDLE Image
,
1747 IN EFI_GUID
*ServiceBindingGuid
,
1748 IN EFI_HANDLE ChildHandle
1752 EFI_SERVICE_BINDING_PROTOCOL
*Service
;
1754 ASSERT (ServiceBindingGuid
!= NULL
);
1757 // Get the ServiceBinding Protocol
1759 Status
= gBS
->OpenProtocol (
1765 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1768 if (EFI_ERROR (Status
)) {
1773 // destory the child
1775 Status
= Service
->DestroyChild (Service
, ChildHandle
);
1781 Convert the mac address of the simple network protocol installed on
1782 SnpHandle to a unicode string. Callers are responsible for freeing the
1785 Get the mac address of the Simple Network protocol from the SnpHandle. Then convert
1786 the mac address into a unicode string. It takes 2 unicode characters to represent
1787 a 1 byte binary buffer. Plus one unicode character for the null-terminator.
1790 @param[in] SnpHandle The handle where the simple network protocol is
1792 @param[in] ImageHandle The image handle used to act as the agent handle to
1793 get the simple network protocol.
1794 @param[out] MacString The pointer to store the address of the string
1795 representation of the mac address.
1797 @retval EFI_SUCCESS Convert the mac address a unicode string successfully.
1798 @retval EFI_OUT_OF_RESOURCES There are not enough memory resource.
1799 @retval Others Failed to open the simple network protocol.
1804 NetLibGetMacString (
1805 IN EFI_HANDLE SnpHandle
,
1806 IN EFI_HANDLE ImageHandle
,
1807 OUT CHAR16
**MacString
1811 EFI_SIMPLE_NETWORK_PROTOCOL
*Snp
;
1812 EFI_SIMPLE_NETWORK_MODE
*Mode
;
1819 // Get the Simple Network protocol from the SnpHandle.
1821 Status
= gBS
->OpenProtocol (
1823 &gEfiSimpleNetworkProtocolGuid
,
1827 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1829 if (EFI_ERROR (Status
)) {
1836 // It takes 2 unicode characters to represent a 1 byte binary buffer.
1837 // Plus one unicode character for the null-terminator.
1839 MacAddress
= AllocatePool ((2 * Mode
->HwAddressSize
+ 1) * sizeof (CHAR16
));
1840 if (MacAddress
== NULL
) {
1841 return EFI_OUT_OF_RESOURCES
;
1845 // Convert the mac address into a unicode string.
1847 for (Index
= 0; Index
< Mode
->HwAddressSize
; Index
++) {
1848 MacAddress
[Index
* 2] = (CHAR16
) mNetLibHexStr
[(Mode
->CurrentAddress
.Addr
[Index
] >> 4) & 0x0F];
1849 MacAddress
[Index
* 2 + 1] = (CHAR16
) mNetLibHexStr
[Mode
->CurrentAddress
.Addr
[Index
] & 0x0F];
1852 MacAddress
[Mode
->HwAddressSize
* 2] = L
'\0';
1854 *MacString
= MacAddress
;
1860 Check the default address used by the IPv4 driver is static or dynamic (acquired
1863 If the controller handle does not have the NIC Ip4 Config Protocol installed, the
1864 default address is static. If the EFI variable to save the configuration is not found,
1865 the default address is static. Otherwise, get the result from the EFI variable which
1866 saving the configuration.
1868 @param[in] Controller The controller handle which has the NIC Ip4 Config Protocol
1869 relative with the default address to judge.
1871 @retval TRUE If the default address is static.
1872 @retval FALSE If the default address is acquired from DHCP.
1876 NetLibDefaultAddressIsStatic (
1877 IN EFI_HANDLE Controller
1881 EFI_HII_CONFIG_ROUTING_PROTOCOL
*HiiConfigRouting
;
1883 NIC_IP4_CONFIG_INFO
*ConfigInfo
;
1885 EFI_STRING ConfigHdr
;
1886 EFI_STRING ConfigResp
;
1887 EFI_STRING AccessProgress
;
1888 EFI_STRING AccessResults
;
1894 AccessProgress
= NULL
;
1895 AccessResults
= NULL
;
1898 Status
= gBS
->LocateProtocol (
1899 &gEfiHiiConfigRoutingProtocolGuid
,
1901 (VOID
**) &HiiConfigRouting
1903 if (EFI_ERROR (Status
)) {
1908 // Construct config request string header
1910 ConfigHdr
= HiiConstructConfigHdr (&gEfiNicIp4ConfigVariableGuid
, EFI_NIC_IP4_CONFIG_VARIABLE
, Controller
);
1911 if (ConfigHdr
== NULL
) {
1915 Len
= StrLen (ConfigHdr
);
1916 ConfigResp
= AllocateZeroPool ((Len
+ NIC_ITEM_CONFIG_SIZE
* 2 + 100) * sizeof (CHAR16
));
1917 if (ConfigResp
== NULL
) {
1920 StrCpy (ConfigResp
, ConfigHdr
);
1922 String
= ConfigResp
+ Len
;
1925 (8 + 4 + 7 + 4 + 1) * sizeof (CHAR16
),
1926 L
"&OFFSET=%04X&WIDTH=%04X",
1927 OFFSET_OF (NIC_IP4_CONFIG_INFO
, Source
),
1931 Status
= HiiConfigRouting
->ExtractConfig (
1937 if (EFI_ERROR (Status
)) {
1941 ConfigInfo
= AllocateZeroPool (sizeof (NIC_ITEM_CONFIG_SIZE
));
1942 if (ConfigInfo
== NULL
) {
1946 ConfigInfo
->Source
= IP4_CONFIG_SOURCE_STATIC
;
1947 Len
= NIC_ITEM_CONFIG_SIZE
;
1948 Status
= HiiConfigRouting
->ConfigToBlock (
1951 (UINT8
*) ConfigInfo
,
1955 if (EFI_ERROR (Status
)) {
1959 IsStatic
= (BOOLEAN
) (ConfigInfo
->Source
== IP4_CONFIG_SOURCE_STATIC
);
1963 if (AccessResults
!= NULL
) {
1964 FreePool (AccessResults
);
1966 if (ConfigInfo
!= NULL
) {
1967 FreePool (ConfigInfo
);
1969 if (ConfigResp
!= NULL
) {
1970 FreePool (ConfigResp
);
1972 if (ConfigHdr
!= NULL
) {
1973 FreePool (ConfigHdr
);
1980 Create an IPv4 device path node.
1982 The header type of IPv4 device path node is MESSAGING_DEVICE_PATH.
1983 The header subtype of IPv4 device path node is MSG_IPv4_DP.
1984 The length of the IPv4 device path node in bytes is 19.
1985 Get other info from parameters to make up the whole IPv4 device path node.
1987 @param[in, out] Node Pointer to the IPv4 device path node.
1988 @param[in] Controller The controller handle.
1989 @param[in] LocalIp The local IPv4 address.
1990 @param[in] LocalPort The local port.
1991 @param[in] RemoteIp The remote IPv4 address.
1992 @param[in] RemotePort The remote port.
1993 @param[in] Protocol The protocol type in the IP header.
1994 @param[in] UseDefaultAddress Whether this instance is using default address or not.
1999 NetLibCreateIPv4DPathNode (
2000 IN OUT IPv4_DEVICE_PATH
*Node
,
2001 IN EFI_HANDLE Controller
,
2002 IN IP4_ADDR LocalIp
,
2003 IN UINT16 LocalPort
,
2004 IN IP4_ADDR RemoteIp
,
2005 IN UINT16 RemotePort
,
2007 IN BOOLEAN UseDefaultAddress
2010 Node
->Header
.Type
= MESSAGING_DEVICE_PATH
;
2011 Node
->Header
.SubType
= MSG_IPv4_DP
;
2012 SetDevicePathNodeLength (&Node
->Header
, 19);
2014 CopyMem (&Node
->LocalIpAddress
, &LocalIp
, sizeof (EFI_IPv4_ADDRESS
));
2015 CopyMem (&Node
->RemoteIpAddress
, &RemoteIp
, sizeof (EFI_IPv4_ADDRESS
));
2017 Node
->LocalPort
= LocalPort
;
2018 Node
->RemotePort
= RemotePort
;
2020 Node
->Protocol
= Protocol
;
2022 if (!UseDefaultAddress
) {
2023 Node
->StaticIpAddress
= TRUE
;
2025 Node
->StaticIpAddress
= NetLibDefaultAddressIsStatic (Controller
);
2030 Create an IPv6 device path node.
2032 The header type of IPv6 device path node is MESSAGING_DEVICE_PATH.
2033 The header subtype of IPv6 device path node is MSG_IPv6_DP.
2034 Get other info from parameters to make up the whole IPv6 device path node.
2036 @param[in, out] Node Pointer to the IPv6 device path node.
2037 @param[in] Controller The controller handle.
2038 @param[in] LocalIp The local IPv6 address.
2039 @param[in] LocalPort The local port.
2040 @param[in] RemoteIp The remote IPv6 address.
2041 @param[in] RemotePort The remote port.
2042 @param[in] Protocol The protocol type in the IP header.
2047 NetLibCreateIPv6DPathNode (
2048 IN OUT IPv6_DEVICE_PATH
*Node
,
2049 IN EFI_HANDLE Controller
,
2050 IN EFI_IPv6_ADDRESS
*LocalIp
,
2051 IN UINT16 LocalPort
,
2052 IN EFI_IPv6_ADDRESS
*RemoteIp
,
2053 IN UINT16 RemotePort
,
2057 Node
->Header
.Type
= MESSAGING_DEVICE_PATH
;
2058 Node
->Header
.SubType
= MSG_IPv6_DP
;
2059 SetDevicePathNodeLength (&Node
->Header
, sizeof (IPv6_DEVICE_PATH
));
2061 CopyMem (&Node
->LocalIpAddress
, LocalIp
, sizeof (EFI_IPv6_ADDRESS
));
2062 CopyMem (&Node
->RemoteIpAddress
, RemoteIp
, sizeof (EFI_IPv6_ADDRESS
));
2064 Node
->LocalPort
= LocalPort
;
2065 Node
->RemotePort
= RemotePort
;
2067 Node
->Protocol
= Protocol
;
2068 Node
->StaticIpAddress
= FALSE
;
2072 Find the UNDI/SNP handle from controller and protocol GUID.
2074 For example, IP will open a MNP child to transmit/receive
2075 packets, when MNP is stopped, IP should also be stopped. IP
2076 needs to find its own private data which is related the IP's
2077 service binding instance that is install on UNDI/SNP handle.
2078 Now, the controller is either a MNP or ARP child handle. But
2079 IP opens these handle BY_DRIVER, use that info, we can get the
2082 @param[in] Controller Then protocol handle to check.
2083 @param[in] ProtocolGuid The protocol that is related with the handle.
2085 @return The UNDI/SNP handle or NULL for errors.
2090 NetLibGetNicHandle (
2091 IN EFI_HANDLE Controller
,
2092 IN EFI_GUID
*ProtocolGuid
2095 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenBuffer
;
2101 Status
= gBS
->OpenProtocolInformation (
2108 if (EFI_ERROR (Status
)) {
2114 for (Index
= 0; Index
< OpenCount
; Index
++) {
2115 if (OpenBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_DRIVER
) {
2116 Handle
= OpenBuffer
[Index
].ControllerHandle
;
2121 gBS
->FreePool (OpenBuffer
);