]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeNetLib/DxeNetLib.c
Add VLAN support.
[mirror_edk2.git] / MdeModulePkg / Library / DxeNetLib / DxeNetLib.c
CommitLineData
da1d0201 1/** @file\r
3e7104c2 2 Network library.\r
1204fe83 3\r
ce4106be 4Copyright (c) 2005 - 2009, Intel Corporation.<BR>\r
da1d0201 5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
da1d0201 12**/\r
13\r
3e7104c2 14#include <Uefi.h>\r
da1d0201 15\r
752ef5d8 16#include <Protocol/DriverBinding.h>\r
da1d0201 17#include <Protocol/ServiceBinding.h>\r
18#include <Protocol/SimpleNetwork.h>\r
1204fe83 19#include <Protocol/ManagedNetwork.h>\r
63886849 20#include <Protocol/HiiConfigRouting.h>\r
3012ce5c 21#include <Protocol/ComponentName.h>\r
22#include <Protocol/ComponentName2.h>\r
da1d0201 23\r
63886849 24#include <Guid/NicIp4ConfigNvData.h>\r
25\r
da1d0201 26#include <Library/NetLib.h>\r
27#include <Library/BaseLib.h>\r
28#include <Library/DebugLib.h>\r
29#include <Library/BaseMemoryLib.h>\r
30#include <Library/UefiBootServicesTableLib.h>\r
31#include <Library/UefiRuntimeServicesTableLib.h>\r
da1d0201 32#include <Library/MemoryAllocationLib.h>\r
1232b214 33#include <Library/DevicePathLib.h>\r
63886849 34#include <Library/HiiLib.h>\r
35#include <Library/PrintLib.h>\r
da1d0201 36\r
ce4106be 37#define NIC_ITEM_CONFIG_SIZE sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE\r
63886849 38\r
da1d0201 39//\r
40// All the supported IP4 maskes in host byte order.\r
41//\r
1204fe83 42GLOBAL_REMOVE_IF_UNREFERENCED IP4_ADDR gIp4AllMasks[IP4_MASK_NUM] = {\r
da1d0201 43 0x00000000,\r
44 0x80000000,\r
45 0xC0000000,\r
46 0xE0000000,\r
47 0xF0000000,\r
48 0xF8000000,\r
49 0xFC000000,\r
50 0xFE000000,\r
51\r
52 0xFF000000,\r
53 0xFF800000,\r
54 0xFFC00000,\r
55 0xFFE00000,\r
56 0xFFF00000,\r
57 0xFFF80000,\r
58 0xFFFC0000,\r
59 0xFFFE0000,\r
60\r
61 0xFFFF0000,\r
62 0xFFFF8000,\r
63 0xFFFFC000,\r
64 0xFFFFE000,\r
65 0xFFFFF000,\r
66 0xFFFFF800,\r
67 0xFFFFFC00,\r
68 0xFFFFFE00,\r
69\r
70 0xFFFFFF00,\r
71 0xFFFFFF80,\r
72 0xFFFFFFC0,\r
73 0xFFFFFFE0,\r
74 0xFFFFFFF0,\r
75 0xFFFFFFF8,\r
76 0xFFFFFFFC,\r
77 0xFFFFFFFE,\r
78 0xFFFFFFFF,\r
79};\r
80\r
1204fe83 81GLOBAL_REMOVE_IF_UNREFERENCED EFI_IPv4_ADDRESS mZeroIp4Addr = {{0, 0, 0, 0}};\r
da1d0201 82\r
f6b7393c 83//\r
1204fe83 84// Any error level digitally larger than mNetDebugLevelMax\r
f6b7393c 85// will be silently discarded.\r
86//\r
1204fe83 87GLOBAL_REMOVE_IF_UNREFERENCED UINTN mNetDebugLevelMax = NETDEBUG_LEVEL_ERROR;\r
88GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogPacketSeq = 0xDEADBEEF;\r
f6b7393c 89\r
f6b7393c 90//\r
1204fe83 91// You can change mSyslogDstMac mSyslogDstIp and mSyslogSrcIp\r
92// here to direct the syslog packets to the syslog deamon. The\r
93// default is broadcast to both the ethernet and IP.\r
94//\r
95GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mSyslogDstMac[NET_ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
96GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogDstIp = 0xffffffff;\r
97GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogSrcIp = 0;\r
f6b7393c 98\r
1204fe83 99GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mMonthName[] = {\r
f6b7393c 100 "Jan",\r
101 "Feb",\r
102 "Mar",\r
103 "Apr",\r
104 "May",\r
105 "Jun",\r
106 "Jul",\r
107 "Aug",\r
108 "Sep",\r
109 "Oct",\r
110 "Nov",\r
111 "Dec"\r
112};\r
113\r
779ae357 114//\r
115// VLAN device path node template\r
116//\r
117GLOBAL_REMOVE_IF_UNREFERENCED VLAN_DEVICE_PATH mNetVlanDevicePathTemplate = {\r
118 {\r
119 MESSAGING_DEVICE_PATH,\r
120 MSG_VLAN_DP,\r
121 {\r
122 (UINT8) (sizeof (VLAN_DEVICE_PATH)),\r
123 (UINT8) ((sizeof (VLAN_DEVICE_PATH)) >> 8)\r
124 }\r
125 },\r
126 0\r
127};\r
128\r
f6b7393c 129/**\r
1204fe83 130 Locate the handles that support SNP, then open one of them\r
f6b7393c 131 to send the syslog packets. The caller isn't required to close\r
132 the SNP after use because the SNP is opened by HandleProtocol.\r
133\r
134 @return The point to SNP if one is properly openned. Otherwise NULL\r
135\r
136**/\r
137EFI_SIMPLE_NETWORK_PROTOCOL *\r
138SyslogLocateSnp (\r
139 VOID\r
140 )\r
141{\r
142 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
143 EFI_STATUS Status;\r
144 EFI_HANDLE *Handles;\r
145 UINTN HandleCount;\r
146 UINTN Index;\r
147\r
148 //\r
149 // Locate the handles which has SNP installed.\r
150 //\r
151 Handles = NULL;\r
152 Status = gBS->LocateHandleBuffer (\r
153 ByProtocol,\r
154 &gEfiSimpleNetworkProtocolGuid,\r
155 NULL,\r
156 &HandleCount,\r
157 &Handles\r
158 );\r
159\r
160 if (EFI_ERROR (Status) || (HandleCount == 0)) {\r
161 return NULL;\r
162 }\r
1204fe83 163\r
f6b7393c 164 //\r
165 // Try to open one of the ethernet SNP protocol to send packet\r
166 //\r
167 Snp = NULL;\r
1204fe83 168\r
f6b7393c 169 for (Index = 0; Index < HandleCount; Index++) {\r
170 Status = gBS->HandleProtocol (\r
171 Handles[Index],\r
172 &gEfiSimpleNetworkProtocolGuid,\r
173 (VOID **) &Snp\r
174 );\r
175\r
1204fe83 176 if ((Status == EFI_SUCCESS) && (Snp != NULL) &&\r
f6b7393c 177 (Snp->Mode->IfType == NET_IFTYPE_ETHERNET) &&\r
178 (Snp->Mode->MaxPacketSize >= NET_SYSLOG_PACKET_LEN)) {\r
1204fe83 179\r
f6b7393c 180 break;\r
181 }\r
182\r
183 Snp = NULL;\r
184 }\r
185\r
186 FreePool (Handles);\r
187 return Snp;\r
188}\r
189\r
190/**\r
191 Transmit a syslog packet synchronously through SNP. The Packet\r
1204fe83 192 already has the ethernet header prepended. This function should\r
f6b7393c 193 fill in the source MAC because it will try to locate a SNP each\r
194 time it is called to avoid the problem if SNP is unloaded.\r
1204fe83 195 This code snip is copied from MNP.\r
196\r
197 @param[in] Packet The Syslog packet\r
198 @param[in] Length The length of the packet\r
f6b7393c 199\r
1204fe83 200 @retval EFI_DEVICE_ERROR Failed to locate a usable SNP protocol\r
201 @retval EFI_TIMEOUT Timeout happened to send the packet.\r
202 @retval EFI_SUCCESS Packet is sent.\r
f6b7393c 203\r
f6b7393c 204**/\r
205EFI_STATUS\r
206SyslogSendPacket (\r
207 IN CHAR8 *Packet,\r
208 IN UINT32 Length\r
209 )\r
210{\r
211 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
212 ETHER_HEAD *Ether;\r
213 EFI_STATUS Status;\r
214 EFI_EVENT TimeoutEvent;\r
215 UINT8 *TxBuf;\r
216\r
217 Snp = SyslogLocateSnp ();\r
218\r
219 if (Snp == NULL) {\r
220 return EFI_DEVICE_ERROR;\r
221 }\r
222\r
223 Ether = (ETHER_HEAD *) Packet;\r
224 CopyMem (Ether->SrcMac, Snp->Mode->CurrentAddress.Addr, NET_ETHER_ADDR_LEN);\r
225\r
226 //\r
227 // Start the timeout event.\r
228 //\r
229 Status = gBS->CreateEvent (\r
230 EVT_TIMER,\r
231 TPL_NOTIFY,\r
232 NULL,\r
233 NULL,\r
234 &TimeoutEvent\r
235 );\r
236\r
237 if (EFI_ERROR (Status)) {\r
238 return Status;\r
239 }\r
240\r
241 Status = gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);\r
242\r
243 if (EFI_ERROR (Status)) {\r
244 goto ON_EXIT;\r
245 }\r
246\r
247 for (;;) {\r
248 //\r
249 // Transmit the packet through SNP.\r
250 //\r
251 Status = Snp->Transmit (Snp, 0, Length, Packet, NULL, NULL, NULL);\r
252\r
253 if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {\r
254 Status = EFI_DEVICE_ERROR;\r
255 break;\r
256 }\r
1204fe83 257\r
f6b7393c 258 //\r
259 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.\r
260 // if Status is EFI_NOT_READY, the transmit engine of the network\r
261 // interface is busy. Both need to sync SNP.\r
262 //\r
263 TxBuf = NULL;\r
264\r
265 do {\r
266 //\r
267 // Get the recycled transmit buffer status.\r
268 //\r
269 Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf);\r
270\r
271 if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
272 Status = EFI_TIMEOUT;\r
273 break;\r
274 }\r
275\r
276 } while (TxBuf == NULL);\r
277\r
278 if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {\r
279 break;\r
280 }\r
1204fe83 281\r
f6b7393c 282 //\r
283 // Status is EFI_NOT_READY. Restart the timer event and\r
284 // call Snp->Transmit again.\r
285 //\r
286 gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);\r
287 }\r
288\r
289 gBS->SetTimer (TimeoutEvent, TimerCancel, 0);\r
290\r
291ON_EXIT:\r
292 gBS->CloseEvent (TimeoutEvent);\r
293 return Status;\r
294}\r
295\r
296/**\r
1204fe83 297 Build a syslog packet, including the Ethernet/Ip/Udp headers\r
298 and user's message.\r
f6b7393c 299\r
1204fe83 300 @param[in] Level Syslog servity level\r
301 @param[in] Module The module that generates the log\r
302 @param[in] File The file that contains the current log\r
303 @param[in] Line The line of code in the File that contains the current log\r
304 @param[in] Message The log message\r
305 @param[in] BufLen The lenght of the Buf\r
306 @param[out] Buf The buffer to put the packet data\r
f6b7393c 307\r
1204fe83 308 @return The length of the syslog packet built.\r
f6b7393c 309\r
310**/\r
311UINT32\r
312SyslogBuildPacket (\r
313 IN UINT32 Level,\r
314 IN UINT8 *Module,\r
315 IN UINT8 *File,\r
316 IN UINT32 Line,\r
317 IN UINT8 *Message,\r
318 IN UINT32 BufLen,\r
1204fe83 319 OUT CHAR8 *Buf\r
f6b7393c 320 )\r
321{\r
322 ETHER_HEAD *Ether;\r
323 IP4_HEAD *Ip4;\r
324 EFI_UDP_HEADER *Udp4;\r
325 EFI_TIME Time;\r
326 UINT32 Pri;\r
327 UINT32 Len;\r
328\r
329 //\r
1204fe83 330 // Fill in the Ethernet header. Leave alone the source MAC.\r
f6b7393c 331 // SyslogSendPacket will fill in the address for us.\r
332 //\r
333 Ether = (ETHER_HEAD *) Buf;\r
334 CopyMem (Ether->DstMac, mSyslogDstMac, NET_ETHER_ADDR_LEN);\r
335 ZeroMem (Ether->SrcMac, NET_ETHER_ADDR_LEN);\r
336\r
337 Ether->EtherType = HTONS (0x0800); // IPv4 protocol\r
338\r
339 Buf += sizeof (ETHER_HEAD);\r
340 BufLen -= sizeof (ETHER_HEAD);\r
341\r
342 //\r
343 // Fill in the IP header\r
344 //\r
345 Ip4 = (IP4_HEAD *) Buf;\r
346 Ip4->HeadLen = 5;\r
347 Ip4->Ver = 4;\r
348 Ip4->Tos = 0;\r
349 Ip4->TotalLen = 0;\r
350 Ip4->Id = (UINT16) mSyslogPacketSeq;\r
351 Ip4->Fragment = 0;\r
352 Ip4->Ttl = 16;\r
353 Ip4->Protocol = 0x11;\r
354 Ip4->Checksum = 0;\r
355 Ip4->Src = mSyslogSrcIp;\r
356 Ip4->Dst = mSyslogDstIp;\r
357\r
358 Buf += sizeof (IP4_HEAD);\r
359 BufLen -= sizeof (IP4_HEAD);\r
360\r
361 //\r
362 // Fill in the UDP header, Udp checksum is optional. Leave it zero.\r
363 //\r
364 Udp4 = (EFI_UDP_HEADER *) Buf;\r
365 Udp4->SrcPort = HTONS (514);\r
366 Udp4->DstPort = HTONS (514);\r
367 Udp4->Length = 0;\r
368 Udp4->Checksum = 0;\r
369\r
370 Buf += sizeof (EFI_UDP_HEADER);\r
371 BufLen -= sizeof (EFI_UDP_HEADER);\r
372\r
373 //\r
374 // Build the syslog message body with <PRI> Timestamp machine module Message\r
375 //\r
376 Pri = ((NET_SYSLOG_FACILITY & 31) << 3) | (Level & 7);\r
377 gRT->GetTime (&Time, NULL);\r
378\r
379 //\r
380 // Use %a to format the ASCII strings, %s to format UNICODE strings\r
381 //\r
382 Len = 0;\r
383 Len += (UINT32) AsciiSPrint (\r
384 Buf,\r
385 BufLen,\r
386 "<%d> %a %d %d:%d:%d ",\r
387 Pri,\r
1204fe83 388 mMonthName [Time.Month-1],\r
f6b7393c 389 Time.Day,\r
390 Time.Hour,\r
391 Time.Minute,\r
392 Time.Second\r
393 );\r
394 Len--;\r
395\r
396 Len += (UINT32) AsciiSPrint (\r
1204fe83 397 Buf + Len,\r
398 BufLen - Len,\r
399 "Tiano %a: %a (Line: %d File: %a)",\r
f6b7393c 400 Module,\r
401 Message,\r
402 Line,\r
403 File\r
404 );\r
405 Len--;\r
406\r
407 //\r
408 // OK, patch the IP length/checksum and UDP length fields.\r
409 //\r
410 Len += sizeof (EFI_UDP_HEADER);\r
411 Udp4->Length = HTONS ((UINT16) Len);\r
412\r
413 Len += sizeof (IP4_HEAD);\r
414 Ip4->TotalLen = HTONS ((UINT16) Len);\r
415 Ip4->Checksum = (UINT16) (~NetblockChecksum ((UINT8 *) Ip4, sizeof (IP4_HEAD)));\r
416\r
417 return Len + sizeof (ETHER_HEAD);\r
418}\r
419\r
420/**\r
1204fe83 421 Allocate a buffer, then format the message to it. This is a\r
422 help function for the NET_DEBUG_XXX macros. The PrintArg of\r
423 these macros treats the variable length print parameters as a\r
f6b7393c 424 single parameter, and pass it to the NetDebugASPrint. For\r
425 example, NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name))\r
1204fe83 426 if extracted to:\r
427\r
f6b7393c 428 NetDebugOutput (\r
1204fe83 429 NETDEBUG_LEVEL_TRACE,\r
430 "Tcp",\r
f6b7393c 431 __FILE__,\r
432 __LINE__,\r
1204fe83 433 NetDebugASPrint ("State transit to %a\n", Name)\r
434 )\r
435\r
f6b7393c 436 @param Format The ASCII format string.\r
1204fe83 437 @param ... The variable length parameter whose format is determined\r
f6b7393c 438 by the Format string.\r
439\r
440 @return The buffer containing the formatted message,\r
441 or NULL if failed to allocate memory.\r
442\r
443**/\r
444CHAR8 *\r
445NetDebugASPrint (\r
446 IN CHAR8 *Format,\r
447 ...\r
448 )\r
449{\r
450 VA_LIST Marker;\r
451 CHAR8 *Buf;\r
452\r
453 Buf = (CHAR8 *) AllocatePool (NET_DEBUG_MSG_LEN);\r
454\r
455 if (Buf == NULL) {\r
456 return NULL;\r
457 }\r
458\r
459 VA_START (Marker, Format);\r
460 AsciiVSPrint (Buf, NET_DEBUG_MSG_LEN, Format, Marker);\r
461 VA_END (Marker);\r
462\r
463 return Buf;\r
464}\r
465\r
466/**\r
467 Builds an UDP4 syslog packet and send it using SNP.\r
468\r
469 This function will locate a instance of SNP then send the message through it.\r
470 Because it isn't open the SNP BY_DRIVER, apply caution when using it.\r
471\r
472 @param Level The servity level of the message.\r
473 @param Module The Moudle that generates the log.\r
474 @param File The file that contains the log.\r
475 @param Line The exact line that contains the log.\r
476 @param Message The user message to log.\r
477\r
478 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
479 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet\r
1204fe83 480 @retval EFI_SUCCESS The log is discard because that it is more verbose\r
f6b7393c 481 than the mNetDebugLevelMax. Or, it has been sent out.\r
1204fe83 482**/\r
f6b7393c 483EFI_STATUS\r
484NetDebugOutput (\r
1204fe83 485 IN UINT32 Level,\r
f6b7393c 486 IN UINT8 *Module,\r
487 IN UINT8 *File,\r
488 IN UINT32 Line,\r
489 IN UINT8 *Message\r
490 )\r
491{\r
492 CHAR8 *Packet;\r
493 UINT32 Len;\r
494 EFI_STATUS Status;\r
495\r
496 //\r
497 // Check whether the message should be sent out\r
498 //\r
499 if (Message == NULL) {\r
500 return EFI_INVALID_PARAMETER;\r
501 }\r
502\r
503 if (Level > mNetDebugLevelMax) {\r
504 Status = EFI_SUCCESS;\r
505 goto ON_EXIT;\r
506 }\r
1204fe83 507\r
f6b7393c 508 //\r
509 // Allocate a maxium of 1024 bytes, the caller should ensure\r
510 // that the message plus the ethernet/ip/udp header is shorter\r
511 // than this\r
512 //\r
513 Packet = (CHAR8 *) AllocatePool (NET_SYSLOG_PACKET_LEN);\r
514\r
515 if (Packet == NULL) {\r
516 Status = EFI_OUT_OF_RESOURCES;\r
517 goto ON_EXIT;\r
518 }\r
1204fe83 519\r
f6b7393c 520 //\r
521 // Build the message: Ethernet header + IP header + Udp Header + user data\r
522 //\r
523 Len = SyslogBuildPacket (\r
524 Level,\r
525 Module,\r
526 File,\r
527 Line,\r
528 Message,\r
529 NET_SYSLOG_PACKET_LEN,\r
530 Packet\r
531 );\r
532\r
533 mSyslogPacketSeq++;\r
534 Status = SyslogSendPacket (Packet, Len);\r
535 FreePool (Packet);\r
536\r
537ON_EXIT:\r
538 FreePool (Message);\r
539 return Status;\r
540}\r
da1d0201 541/**\r
1204fe83 542 Return the length of the mask.\r
543\r
b9008c87 544 Return the length of the mask, the correct value is from 0 to 32.\r
545 If the mask is invalid, return the invalid length 33, which is IP4_MASK_NUM.\r
da1d0201 546 NetMask is in the host byte order.\r
547\r
3e7104c2 548 @param[in] NetMask The netmask to get the length from.\r
da1d0201 549\r
b9008c87 550 @return The length of the netmask, IP4_MASK_NUM if the mask is invalid.\r
1204fe83 551\r
da1d0201 552**/\r
553INTN\r
7b414b4e 554EFIAPI\r
da1d0201 555NetGetMaskLength (\r
556 IN IP4_ADDR NetMask\r
557 )\r
558{\r
559 INTN Index;\r
560\r
561 for (Index = 0; Index < IP4_MASK_NUM; Index++) {\r
2a86ff1c 562 if (NetMask == gIp4AllMasks[Index]) {\r
da1d0201 563 break;\r
564 }\r
565 }\r
566\r
567 return Index;\r
568}\r
569\r
570\r
571\r
572/**\r
b9008c87 573 Return the class of the IP address, such as class A, B, C.\r
da1d0201 574 Addr is in host byte order.\r
1204fe83 575\r
b9008c87 576 The address of class A starts with 0.\r
577 If the address belong to class A, return IP4_ADDR_CLASSA.\r
1204fe83 578 The address of class B starts with 10.\r
b9008c87 579 If the address belong to class B, return IP4_ADDR_CLASSB.\r
1204fe83 580 The address of class C starts with 110.\r
b9008c87 581 If the address belong to class C, return IP4_ADDR_CLASSC.\r
1204fe83 582 The address of class D starts with 1110.\r
b9008c87 583 If the address belong to class D, return IP4_ADDR_CLASSD.\r
584 The address of class E starts with 1111.\r
585 If the address belong to class E, return IP4_ADDR_CLASSE.\r
da1d0201 586\r
1204fe83 587\r
3e7104c2 588 @param[in] Addr The address to get the class from.\r
da1d0201 589\r
3e7104c2 590 @return IP address class, such as IP4_ADDR_CLASSA.\r
da1d0201 591\r
592**/\r
593INTN\r
7b414b4e 594EFIAPI\r
da1d0201 595NetGetIpClass (\r
596 IN IP4_ADDR Addr\r
597 )\r
598{\r
599 UINT8 ByteOne;\r
600\r
601 ByteOne = (UINT8) (Addr >> 24);\r
602\r
603 if ((ByteOne & 0x80) == 0) {\r
604 return IP4_ADDR_CLASSA;\r
605\r
606 } else if ((ByteOne & 0xC0) == 0x80) {\r
607 return IP4_ADDR_CLASSB;\r
608\r
609 } else if ((ByteOne & 0xE0) == 0xC0) {\r
610 return IP4_ADDR_CLASSC;\r
611\r
612 } else if ((ByteOne & 0xF0) == 0xE0) {\r
613 return IP4_ADDR_CLASSD;\r
614\r
615 } else {\r
616 return IP4_ADDR_CLASSE;\r
617\r
618 }\r
619}\r
620\r
621\r
622/**\r
623 Check whether the IP is a valid unicast address according to\r
b9008c87 624 the netmask. If NetMask is zero, use the IP address's class to get the default mask.\r
1204fe83 625\r
b9008c87 626 If Ip is 0, IP is not a valid unicast address.\r
627 Class D address is used for multicasting and class E address is reserved for future. If Ip\r
1204fe83 628 belongs to class D or class E, IP is not a valid unicast address.\r
b9008c87 629 If all bits of the host address of IP are 0 or 1, IP is also not a valid unicast address.\r
da1d0201 630\r
3e7104c2 631 @param[in] Ip The IP to check against.\r
632 @param[in] NetMask The mask of the IP.\r
da1d0201 633\r
3e7104c2 634 @return TRUE if IP is a valid unicast address on the network, otherwise FALSE.\r
da1d0201 635\r
636**/\r
637BOOLEAN\r
7b414b4e 638EFIAPI\r
f6b7393c 639NetIp4IsUnicast (\r
da1d0201 640 IN IP4_ADDR Ip,\r
641 IN IP4_ADDR NetMask\r
642 )\r
643{\r
644 INTN Class;\r
645\r
646 Class = NetGetIpClass (Ip);\r
647\r
648 if ((Ip == 0) || (Class >= IP4_ADDR_CLASSD)) {\r
649 return FALSE;\r
650 }\r
651\r
652 if (NetMask == 0) {\r
2a86ff1c 653 NetMask = gIp4AllMasks[Class << 3];\r
da1d0201 654 }\r
655\r
656 if (((Ip &~NetMask) == ~NetMask) || ((Ip &~NetMask) == 0)) {\r
657 return FALSE;\r
658 }\r
659\r
660 return TRUE;\r
661}\r
662\r
fb115c61 663/**\r
664 Check whether the incoming IPv6 address is a valid unicast address.\r
665\r
666 If the address is a multicast address has binary 0xFF at the start, it is not\r
667 a valid unicast address. If the address is unspecified ::, it is not a valid\r
668 unicast address to be assigned to any node. If the address is loopback address\r
669 ::1, it is also not a valid unicast address to be assigned to any physical\r
1204fe83 670 interface.\r
fb115c61 671\r
672 @param[in] Ip6 The IPv6 address to check against.\r
673\r
674 @return TRUE if Ip6 is a valid unicast address on the network, otherwise FALSE.\r
675\r
1204fe83 676**/\r
fb115c61 677BOOLEAN\r
f6b7393c 678NetIp6IsValidUnicast (\r
fb115c61 679 IN EFI_IPv6_ADDRESS *Ip6\r
1204fe83 680 )\r
fb115c61 681{\r
b45b45b2 682 UINT8 Byte;\r
683 UINT8 Index;\r
1204fe83 684\r
fb115c61 685 if (Ip6->Addr[0] == 0xFF) {\r
686 return FALSE;\r
687 }\r
688\r
b45b45b2 689 for (Index = 0; Index < 15; Index++) {\r
690 if (Ip6->Addr[Index] != 0) {\r
fb115c61 691 return TRUE;\r
692 }\r
693 }\r
694\r
b45b45b2 695 Byte = Ip6->Addr[Index];\r
fb115c61 696\r
b45b45b2 697 if (Byte == 0x0 || Byte == 0x1) {\r
fb115c61 698 return FALSE;\r
699 }\r
700\r
1204fe83 701 return TRUE;\r
fb115c61 702}\r
da1d0201 703\r
f6b7393c 704/**\r
705 Check whether the incoming Ipv6 address is the unspecified address or not.\r
706\r
707 @param[in] Ip6 - Ip6 address, in network order.\r
708\r
709 @retval TRUE - Yes, unspecified\r
710 @retval FALSE - No\r
1204fe83 711\r
f6b7393c 712**/\r
713BOOLEAN\r
714NetIp6IsUnspecifiedAddr (\r
715 IN EFI_IPv6_ADDRESS *Ip6\r
716 )\r
717{\r
718 UINT8 Index;\r
719\r
720 for (Index = 0; Index < 16; Index++) {\r
721 if (Ip6->Addr[Index] != 0) {\r
722 return FALSE;\r
723 }\r
724 }\r
725\r
726 return TRUE;\r
727}\r
728\r
729/**\r
730 Check whether the incoming Ipv6 address is a link-local address.\r
731\r
732 @param[in] Ip6 - Ip6 address, in network order.\r
733\r
734 @retval TRUE - Yes, link-local address\r
735 @retval FALSE - No\r
1204fe83 736\r
f6b7393c 737**/\r
738BOOLEAN\r
739NetIp6IsLinkLocalAddr (\r
740 IN EFI_IPv6_ADDRESS *Ip6\r
741 )\r
742{\r
743 UINT8 Index;\r
1204fe83 744\r
f6b7393c 745 ASSERT (Ip6 != NULL);\r
746\r
747 if (Ip6->Addr[0] != 0xFE) {\r
748 return FALSE;\r
749 }\r
1204fe83 750\r
f6b7393c 751 if (Ip6->Addr[1] != 0x80) {\r
752 return FALSE;\r
753 }\r
754\r
755 for (Index = 2; Index < 8; Index++) {\r
756 if (Ip6->Addr[Index] != 0) {\r
757 return FALSE;\r
758 }\r
759 }\r
760\r
761 return TRUE;\r
762}\r
763\r
764/**\r
765 Check whether the Ipv6 address1 and address2 are on the connected network.\r
766\r
767 @param[in] Ip1 - Ip6 address1, in network order.\r
768 @param[in] Ip2 - Ip6 address2, in network order.\r
769 @param[in] PrefixLength - The prefix length of the checking net.\r
770\r
771 @retval TRUE - Yes, connected.\r
772 @retval FALSE - No.\r
1204fe83 773\r
f6b7393c 774**/\r
775BOOLEAN\r
776NetIp6IsNetEqual (\r
777 EFI_IPv6_ADDRESS *Ip1,\r
778 EFI_IPv6_ADDRESS *Ip2,\r
779 UINT8 PrefixLength\r
780 )\r
781{\r
782 UINT8 Byte;\r
783 UINT8 Bit;\r
784 UINT8 Mask;\r
785\r
786 ASSERT (Ip1 != NULL && Ip2 != NULL);\r
1204fe83 787\r
f6b7393c 788 if (PrefixLength == 0) {\r
789 return TRUE;\r
790 }\r
791\r
792 Byte = (UINT8) (PrefixLength / 8);\r
793 Bit = (UINT8) (PrefixLength % 8);\r
1204fe83 794\r
f6b7393c 795 if (CompareMem (Ip1, Ip2, Byte) != 0) {\r
796 return FALSE;\r
797 }\r
798\r
799 if (Bit > 0) {\r
800 Mask = (UINT8) (0xFF << (8 - Bit));\r
801\r
802 if ((Ip1->Addr[Byte] & Mask) != (Ip2->Addr[Byte] & Mask)) {\r
803 return FALSE;\r
1204fe83 804 }\r
f6b7393c 805 }\r
1204fe83 806\r
f6b7393c 807 return TRUE;\r
808}\r
809\r
810\r
b45b45b2 811/**\r
812 Switches the endianess of an IPv6 address\r
813\r
814 This function swaps the bytes in a 128-bit IPv6 address to switch the value\r
815 from little endian to big endian or vice versa. The byte swapped value is\r
816 returned.\r
817\r
818 @param Ip6 Points to an IPv6 address\r
819\r
820 @return The byte swapped IPv6 address.\r
821\r
822**/\r
823EFI_IPv6_ADDRESS *\r
824Ip6Swap128 (\r
825 EFI_IPv6_ADDRESS *Ip6\r
826 )\r
827{\r
828 UINT64 High;\r
829 UINT64 Low;\r
830\r
831 CopyMem (&High, Ip6, sizeof (UINT64));\r
832 CopyMem (&Low, &Ip6->Addr[8], sizeof (UINT64));\r
833\r
834 High = SwapBytes64 (High);\r
835 Low = SwapBytes64 (Low);\r
836\r
837 CopyMem (Ip6, &Low, sizeof (UINT64));\r
838 CopyMem (&Ip6->Addr[8], &High, sizeof (UINT64));\r
839\r
840 return Ip6;\r
841}\r
842\r
da1d0201 843/**\r
844 Initialize a random seed using current time.\r
1204fe83 845\r
846 Get current time first. Then initialize a random seed based on some basic\r
847 mathematics operation on the hour, day, minute, second, nanosecond and year\r
b9008c87 848 of the current time.\r
1204fe83 849\r
da1d0201 850 @return The random seed initialized with current time.\r
851\r
852**/\r
853UINT32\r
7b414b4e 854EFIAPI\r
da1d0201 855NetRandomInitSeed (\r
856 VOID\r
857 )\r
858{\r
859 EFI_TIME Time;\r
860 UINT32 Seed;\r
861\r
862 gRT->GetTime (&Time, NULL);\r
36ee91ca 863 Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second);\r
da1d0201 864 Seed ^= Time.Nanosecond;\r
865 Seed ^= Time.Year << 7;\r
866\r
867 return Seed;\r
868}\r
869\r
870\r
871/**\r
b9008c87 872 Extract a UINT32 from a byte stream.\r
1204fe83 873\r
874 Copy a UINT32 from a byte stream, then converts it from Network\r
b9008c87 875 byte order to host byte order. Use this function to avoid alignment error.\r
da1d0201 876\r
3e7104c2 877 @param[in] Buf The buffer to extract the UINT32.\r
da1d0201 878\r
879 @return The UINT32 extracted.\r
880\r
881**/\r
882UINT32\r
7b414b4e 883EFIAPI\r
da1d0201 884NetGetUint32 (\r
885 IN UINT8 *Buf\r
886 )\r
887{\r
888 UINT32 Value;\r
889\r
e48e37fc 890 CopyMem (&Value, Buf, sizeof (UINT32));\r
da1d0201 891 return NTOHL (Value);\r
892}\r
893\r
894\r
895/**\r
1204fe83 896 Put a UINT32 to the byte stream in network byte order.\r
897\r
898 Converts a UINT32 from host byte order to network byte order. Then copy it to the\r
b9008c87 899 byte stream.\r
da1d0201 900\r
3e7104c2 901 @param[in, out] Buf The buffer to put the UINT32.\r
902 @param[in] Data The data to put.\r
1204fe83 903\r
da1d0201 904**/\r
905VOID\r
7b414b4e 906EFIAPI\r
da1d0201 907NetPutUint32 (\r
3e7104c2 908 IN OUT UINT8 *Buf,\r
909 IN UINT32 Data\r
da1d0201 910 )\r
911{\r
912 Data = HTONL (Data);\r
e48e37fc 913 CopyMem (Buf, &Data, sizeof (UINT32));\r
da1d0201 914}\r
915\r
916\r
917/**\r
b9008c87 918 Remove the first node entry on the list, and return the removed node entry.\r
1204fe83 919\r
b9008c87 920 Removes the first node Entry from a doubly linked list. It is up to the caller of\r
921 this function to release the memory used by the first node if that is required. On\r
1204fe83 922 exit, the removed node is returned.\r
b9008c87 923\r
924 If Head is NULL, then ASSERT().\r
925 If Head was not initialized, then ASSERT().\r
926 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the\r
927 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,\r
1204fe83 928 then ASSERT().\r
da1d0201 929\r
3e7104c2 930 @param[in, out] Head The list header.\r
da1d0201 931\r
b9008c87 932 @return The first node entry that is removed from the list, NULL if the list is empty.\r
da1d0201 933\r
934**/\r
e48e37fc 935LIST_ENTRY *\r
7b414b4e 936EFIAPI\r
da1d0201 937NetListRemoveHead (\r
3e7104c2 938 IN OUT LIST_ENTRY *Head\r
da1d0201 939 )\r
940{\r
e48e37fc 941 LIST_ENTRY *First;\r
da1d0201 942\r
943 ASSERT (Head != NULL);\r
944\r
e48e37fc 945 if (IsListEmpty (Head)) {\r
da1d0201 946 return NULL;\r
947 }\r
948\r
949 First = Head->ForwardLink;\r
950 Head->ForwardLink = First->ForwardLink;\r
951 First->ForwardLink->BackLink = Head;\r
952\r
953 DEBUG_CODE (\r
e48e37fc 954 First->ForwardLink = (LIST_ENTRY *) NULL;\r
955 First->BackLink = (LIST_ENTRY *) NULL;\r
da1d0201 956 );\r
957\r
958 return First;\r
959}\r
960\r
961\r
962/**\r
b9008c87 963 Remove the last node entry on the list and and return the removed node entry.\r
964\r
965 Removes the last node entry from a doubly linked list. It is up to the caller of\r
966 this function to release the memory used by the first node if that is required. On\r
1204fe83 967 exit, the removed node is returned.\r
da1d0201 968\r
b9008c87 969 If Head is NULL, then ASSERT().\r
970 If Head was not initialized, then ASSERT().\r
971 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the\r
972 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,\r
1204fe83 973 then ASSERT().\r
974\r
3e7104c2 975 @param[in, out] Head The list head.\r
da1d0201 976\r
b9008c87 977 @return The last node entry that is removed from the list, NULL if the list is empty.\r
da1d0201 978\r
979**/\r
e48e37fc 980LIST_ENTRY *\r
7b414b4e 981EFIAPI\r
da1d0201 982NetListRemoveTail (\r
3e7104c2 983 IN OUT LIST_ENTRY *Head\r
da1d0201 984 )\r
985{\r
e48e37fc 986 LIST_ENTRY *Last;\r
da1d0201 987\r
988 ASSERT (Head != NULL);\r
989\r
e48e37fc 990 if (IsListEmpty (Head)) {\r
da1d0201 991 return NULL;\r
992 }\r
993\r
994 Last = Head->BackLink;\r
995 Head->BackLink = Last->BackLink;\r
996 Last->BackLink->ForwardLink = Head;\r
997\r
998 DEBUG_CODE (\r
e48e37fc 999 Last->ForwardLink = (LIST_ENTRY *) NULL;\r
1000 Last->BackLink = (LIST_ENTRY *) NULL;\r
da1d0201 1001 );\r
1002\r
1003 return Last;\r
1004}\r
1005\r
1006\r
1007/**\r
b9008c87 1008 Insert a new node entry after a designated node entry of a doubly linked list.\r
1204fe83 1009\r
b9008c87 1010 Inserts a new node entry donated by NewEntry after the node entry donated by PrevEntry\r
1011 of the doubly linked list.\r
1204fe83 1012\r
3e7104c2 1013 @param[in, out] PrevEntry The previous entry to insert after.\r
1014 @param[in, out] NewEntry The new entry to insert.\r
da1d0201 1015\r
1016**/\r
1017VOID\r
7b414b4e 1018EFIAPI\r
da1d0201 1019NetListInsertAfter (\r
3e7104c2 1020 IN OUT LIST_ENTRY *PrevEntry,\r
1021 IN OUT LIST_ENTRY *NewEntry\r
da1d0201 1022 )\r
1023{\r
1024 NewEntry->BackLink = PrevEntry;\r
1025 NewEntry->ForwardLink = PrevEntry->ForwardLink;\r
1026 PrevEntry->ForwardLink->BackLink = NewEntry;\r
1027 PrevEntry->ForwardLink = NewEntry;\r
1028}\r
1029\r
1030\r
1031/**\r
b9008c87 1032 Insert a new node entry before a designated node entry of a doubly linked list.\r
1204fe83 1033\r
b9008c87 1034 Inserts a new node entry donated by NewEntry after the node entry donated by PostEntry\r
1035 of the doubly linked list.\r
1204fe83 1036\r
3e7104c2 1037 @param[in, out] PostEntry The entry to insert before.\r
1038 @param[in, out] NewEntry The new entry to insert.\r
da1d0201 1039\r
1040**/\r
1041VOID\r
7b414b4e 1042EFIAPI\r
da1d0201 1043NetListInsertBefore (\r
3e7104c2 1044 IN OUT LIST_ENTRY *PostEntry,\r
1045 IN OUT LIST_ENTRY *NewEntry\r
da1d0201 1046 )\r
1047{\r
1048 NewEntry->ForwardLink = PostEntry;\r
1049 NewEntry->BackLink = PostEntry->BackLink;\r
1050 PostEntry->BackLink->ForwardLink = NewEntry;\r
1051 PostEntry->BackLink = NewEntry;\r
1052}\r
1053\r
1054\r
1055/**\r
1056 Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.\r
1204fe83 1057\r
1058 Initialize the forward and backward links of two head nodes donated by Map->Used\r
b9008c87 1059 and Map->Recycled of two doubly linked lists.\r
1060 Initializes the count of the <Key, Value> pairs in the netmap to zero.\r
1204fe83 1061\r
b9008c87 1062 If Map is NULL, then ASSERT().\r
8f5e6151 1063 If the address of Map->Used is NULL, then ASSERT().\r
b9008c87 1064 If the address of Map->Recycled is NULl, then ASSERT().\r
1204fe83 1065\r
3e7104c2 1066 @param[in, out] Map The netmap to initialize.\r
da1d0201 1067\r
1068**/\r
1069VOID\r
7b414b4e 1070EFIAPI\r
da1d0201 1071NetMapInit (\r
3e7104c2 1072 IN OUT NET_MAP *Map\r
da1d0201 1073 )\r
1074{\r
1075 ASSERT (Map != NULL);\r
1076\r
e48e37fc 1077 InitializeListHead (&Map->Used);\r
1078 InitializeListHead (&Map->Recycled);\r
da1d0201 1079 Map->Count = 0;\r
1080}\r
1081\r
1082\r
1083/**\r
1084 To clean up the netmap, that is, release allocated memories.\r
1204fe83 1085\r
b9008c87 1086 Removes all nodes of the Used doubly linked list and free memory of all related netmap items.\r
1087 Removes all nodes of the Recycled doubly linked list and free memory of all related netmap items.\r
1088 The number of the <Key, Value> pairs in the netmap is set to be zero.\r
1204fe83 1089\r
b9008c87 1090 If Map is NULL, then ASSERT().\r
1204fe83 1091\r
3e7104c2 1092 @param[in, out] Map The netmap to clean up.\r
da1d0201 1093\r
1094**/\r
1095VOID\r
7b414b4e 1096EFIAPI\r
da1d0201 1097NetMapClean (\r
3e7104c2 1098 IN OUT NET_MAP *Map\r
da1d0201 1099 )\r
1100{\r
1101 NET_MAP_ITEM *Item;\r
e48e37fc 1102 LIST_ENTRY *Entry;\r
1103 LIST_ENTRY *Next;\r
da1d0201 1104\r
1105 ASSERT (Map != NULL);\r
1106\r
1107 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Used) {\r
1108 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
1109\r
e48e37fc 1110 RemoveEntryList (&Item->Link);\r
da1d0201 1111 Map->Count--;\r
1112\r
e48e37fc 1113 gBS->FreePool (Item);\r
da1d0201 1114 }\r
1115\r
e48e37fc 1116 ASSERT ((Map->Count == 0) && IsListEmpty (&Map->Used));\r
da1d0201 1117\r
1118 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Recycled) {\r
1119 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
1120\r
e48e37fc 1121 RemoveEntryList (&Item->Link);\r
1122 gBS->FreePool (Item);\r
da1d0201 1123 }\r
1124\r
e48e37fc 1125 ASSERT (IsListEmpty (&Map->Recycled));\r
da1d0201 1126}\r
1127\r
1128\r
1129/**\r
b9008c87 1130 Test whether the netmap is empty and return true if it is.\r
1204fe83 1131\r
b9008c87 1132 If the number of the <Key, Value> pairs in the netmap is zero, return TRUE.\r
1204fe83 1133\r
b9008c87 1134 If Map is NULL, then ASSERT().\r
1204fe83 1135\r
1136\r
3e7104c2 1137 @param[in] Map The net map to test.\r
da1d0201 1138\r
1139 @return TRUE if the netmap is empty, otherwise FALSE.\r
1140\r
1141**/\r
1142BOOLEAN\r
7b414b4e 1143EFIAPI\r
da1d0201 1144NetMapIsEmpty (\r
1145 IN NET_MAP *Map\r
1146 )\r
1147{\r
1148 ASSERT (Map != NULL);\r
1149 return (BOOLEAN) (Map->Count == 0);\r
1150}\r
1151\r
1152\r
1153/**\r
1154 Return the number of the <Key, Value> pairs in the netmap.\r
1155\r
3e7104c2 1156 @param[in] Map The netmap to get the entry number.\r
da1d0201 1157\r
1158 @return The entry number in the netmap.\r
1159\r
1160**/\r
1161UINTN\r
7b414b4e 1162EFIAPI\r
da1d0201 1163NetMapGetCount (\r
1164 IN NET_MAP *Map\r
1165 )\r
1166{\r
1167 return Map->Count;\r
1168}\r
1169\r
1170\r
1171/**\r
1204fe83 1172 Return one allocated item.\r
1173\r
1174 If the Recycled doubly linked list of the netmap is empty, it will try to allocate\r
b9008c87 1175 a batch of items if there are enough resources and add corresponding nodes to the begining\r
1176 of the Recycled doubly linked list of the netmap. Otherwise, it will directly remove\r
1177 the fist node entry of the Recycled doubly linked list and return the corresponding item.\r
1204fe83 1178\r
b9008c87 1179 If Map is NULL, then ASSERT().\r
1204fe83 1180\r
3e7104c2 1181 @param[in, out] Map The netmap to allocate item for.\r
da1d0201 1182\r
3e7104c2 1183 @return The allocated item. If NULL, the\r
1184 allocation failed due to resource limit.\r
da1d0201 1185\r
1186**/\r
da1d0201 1187NET_MAP_ITEM *\r
1188NetMapAllocItem (\r
3e7104c2 1189 IN OUT NET_MAP *Map\r
da1d0201 1190 )\r
1191{\r
1192 NET_MAP_ITEM *Item;\r
e48e37fc 1193 LIST_ENTRY *Head;\r
da1d0201 1194 UINTN Index;\r
1195\r
1196 ASSERT (Map != NULL);\r
1197\r
1198 Head = &Map->Recycled;\r
1199\r
e48e37fc 1200 if (IsListEmpty (Head)) {\r
da1d0201 1201 for (Index = 0; Index < NET_MAP_INCREAMENT; Index++) {\r
e48e37fc 1202 Item = AllocatePool (sizeof (NET_MAP_ITEM));\r
da1d0201 1203\r
1204 if (Item == NULL) {\r
1205 if (Index == 0) {\r
1206 return NULL;\r
1207 }\r
1208\r
1209 break;\r
1210 }\r
1211\r
e48e37fc 1212 InsertHeadList (Head, &Item->Link);\r
da1d0201 1213 }\r
1214 }\r
1215\r
1216 Item = NET_LIST_HEAD (Head, NET_MAP_ITEM, Link);\r
1217 NetListRemoveHead (Head);\r
1218\r
1219 return Item;\r
1220}\r
1221\r
1222\r
1223/**\r
1224 Allocate an item to save the <Key, Value> pair to the head of the netmap.\r
1204fe83 1225\r
b9008c87 1226 Allocate an item to save the <Key, Value> pair and add corresponding node entry\r
1204fe83 1227 to the beginning of the Used doubly linked list. The number of the <Key, Value>\r
b9008c87 1228 pairs in the netmap increase by 1.\r
da1d0201 1229\r
b9008c87 1230 If Map is NULL, then ASSERT().\r
1204fe83 1231\r
3e7104c2 1232 @param[in, out] Map The netmap to insert into.\r
1233 @param[in] Key The user's key.\r
1234 @param[in] Value The user's value for the key.\r
da1d0201 1235\r
3e7104c2 1236 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.\r
1237 @retval EFI_SUCCESS The item is inserted to the head.\r
da1d0201 1238\r
1239**/\r
1240EFI_STATUS\r
7b414b4e 1241EFIAPI\r
da1d0201 1242NetMapInsertHead (\r
3e7104c2 1243 IN OUT NET_MAP *Map,\r
da1d0201 1244 IN VOID *Key,\r
1245 IN VOID *Value OPTIONAL\r
1246 )\r
1247{\r
1248 NET_MAP_ITEM *Item;\r
1249\r
1250 ASSERT (Map != NULL);\r
1251\r
1252 Item = NetMapAllocItem (Map);\r
1253\r
1254 if (Item == NULL) {\r
1255 return EFI_OUT_OF_RESOURCES;\r
1256 }\r
1257\r
1258 Item->Key = Key;\r
1259 Item->Value = Value;\r
e48e37fc 1260 InsertHeadList (&Map->Used, &Item->Link);\r
da1d0201 1261\r
1262 Map->Count++;\r
1263 return EFI_SUCCESS;\r
1264}\r
1265\r
1266\r
1267/**\r
1268 Allocate an item to save the <Key, Value> pair to the tail of the netmap.\r
1269\r
b9008c87 1270 Allocate an item to save the <Key, Value> pair and add corresponding node entry\r
1204fe83 1271 to the tail of the Used doubly linked list. The number of the <Key, Value>\r
b9008c87 1272 pairs in the netmap increase by 1.\r
1273\r
1274 If Map is NULL, then ASSERT().\r
1204fe83 1275\r
3e7104c2 1276 @param[in, out] Map The netmap to insert into.\r
1277 @param[in] Key The user's key.\r
1278 @param[in] Value The user's value for the key.\r
da1d0201 1279\r
3e7104c2 1280 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.\r
1281 @retval EFI_SUCCESS The item is inserted to the tail.\r
da1d0201 1282\r
1283**/\r
1284EFI_STATUS\r
7b414b4e 1285EFIAPI\r
da1d0201 1286NetMapInsertTail (\r
3e7104c2 1287 IN OUT NET_MAP *Map,\r
da1d0201 1288 IN VOID *Key,\r
1289 IN VOID *Value OPTIONAL\r
1290 )\r
1291{\r
1292 NET_MAP_ITEM *Item;\r
1293\r
1294 ASSERT (Map != NULL);\r
1295\r
1296 Item = NetMapAllocItem (Map);\r
1297\r
1298 if (Item == NULL) {\r
1299 return EFI_OUT_OF_RESOURCES;\r
1300 }\r
1301\r
1302 Item->Key = Key;\r
1303 Item->Value = Value;\r
e48e37fc 1304 InsertTailList (&Map->Used, &Item->Link);\r
da1d0201 1305\r
1306 Map->Count++;\r
1307\r
1308 return EFI_SUCCESS;\r
1309}\r
1310\r
1311\r
1312/**\r
b9008c87 1313 Check whether the item is in the Map and return TRUE if it is.\r
da1d0201 1314\r
3e7104c2 1315 @param[in] Map The netmap to search within.\r
1316 @param[in] Item The item to search.\r
da1d0201 1317\r
1318 @return TRUE if the item is in the netmap, otherwise FALSE.\r
1319\r
1320**/\r
da1d0201 1321BOOLEAN\r
1322NetItemInMap (\r
1323 IN NET_MAP *Map,\r
1324 IN NET_MAP_ITEM *Item\r
1325 )\r
1326{\r
e48e37fc 1327 LIST_ENTRY *ListEntry;\r
da1d0201 1328\r
1329 NET_LIST_FOR_EACH (ListEntry, &Map->Used) {\r
1330 if (ListEntry == &Item->Link) {\r
1331 return TRUE;\r
1332 }\r
1333 }\r
1334\r
1335 return FALSE;\r
1336}\r
1337\r
1338\r
1339/**\r
b9008c87 1340 Find the key in the netmap and returns the point to the item contains the Key.\r
1204fe83 1341\r
1342 Iterate the Used doubly linked list of the netmap to get every item. Compare the key of every\r
b9008c87 1343 item with the key to search. It returns the point to the item contains the Key if found.\r
da1d0201 1344\r
b9008c87 1345 If Map is NULL, then ASSERT().\r
1204fe83 1346\r
3e7104c2 1347 @param[in] Map The netmap to search within.\r
1348 @param[in] Key The key to search.\r
da1d0201 1349\r
1350 @return The point to the item contains the Key, or NULL if Key isn't in the map.\r
1351\r
1352**/\r
1353NET_MAP_ITEM *\r
7b414b4e 1354EFIAPI\r
da1d0201 1355NetMapFindKey (\r
1356 IN NET_MAP *Map,\r
1357 IN VOID *Key\r
1358 )\r
1359{\r
e48e37fc 1360 LIST_ENTRY *Entry;\r
da1d0201 1361 NET_MAP_ITEM *Item;\r
1362\r
1363 ASSERT (Map != NULL);\r
1364\r
1365 NET_LIST_FOR_EACH (Entry, &Map->Used) {\r
1366 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
1367\r
1368 if (Item->Key == Key) {\r
1369 return Item;\r
1370 }\r
1371 }\r
1372\r
1373 return NULL;\r
1374}\r
1375\r
1376\r
1377/**\r
b9008c87 1378 Remove the node entry of the item from the netmap and return the key of the removed item.\r
1204fe83 1379\r
1380 Remove the node entry of the item from the Used doubly linked list of the netmap.\r
1381 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node\r
b9008c87 1382 entry of the item to the Recycled doubly linked list of the netmap. If Value is not NULL,\r
1383 Value will point to the value of the item. It returns the key of the removed item.\r
1204fe83 1384\r
b9008c87 1385 If Map is NULL, then ASSERT().\r
1386 If Item is NULL, then ASSERT().\r
1387 if item in not in the netmap, then ASSERT().\r
1204fe83 1388\r
3e7104c2 1389 @param[in, out] Map The netmap to remove the item from.\r
1390 @param[in, out] Item The item to remove.\r
1391 @param[out] Value The variable to receive the value if not NULL.\r
da1d0201 1392\r
3e7104c2 1393 @return The key of the removed item.\r
da1d0201 1394\r
1395**/\r
1396VOID *\r
7b414b4e 1397EFIAPI\r
da1d0201 1398NetMapRemoveItem (\r
3e7104c2 1399 IN OUT NET_MAP *Map,\r
1400 IN OUT NET_MAP_ITEM *Item,\r
1401 OUT VOID **Value OPTIONAL\r
da1d0201 1402 )\r
1403{\r
1404 ASSERT ((Map != NULL) && (Item != NULL));\r
1405 ASSERT (NetItemInMap (Map, Item));\r
1406\r
e48e37fc 1407 RemoveEntryList (&Item->Link);\r
da1d0201 1408 Map->Count--;\r
e48e37fc 1409 InsertHeadList (&Map->Recycled, &Item->Link);\r
da1d0201 1410\r
1411 if (Value != NULL) {\r
1412 *Value = Item->Value;\r
1413 }\r
1414\r
1415 return Item->Key;\r
1416}\r
1417\r
1418\r
1419/**\r
b9008c87 1420 Remove the first node entry on the netmap and return the key of the removed item.\r
da1d0201 1421\r
1204fe83 1422 Remove the first node entry from the Used doubly linked list of the netmap.\r
1423 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node\r
b9008c87 1424 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,\r
1425 parameter Value will point to the value of the item. It returns the key of the removed item.\r
1204fe83 1426\r
b9008c87 1427 If Map is NULL, then ASSERT().\r
1428 If the Used doubly linked list is empty, then ASSERT().\r
1204fe83 1429\r
3e7104c2 1430 @param[in, out] Map The netmap to remove the head from.\r
1431 @param[out] Value The variable to receive the value if not NULL.\r
da1d0201 1432\r
3e7104c2 1433 @return The key of the item removed.\r
da1d0201 1434\r
1435**/\r
1436VOID *\r
7b414b4e 1437EFIAPI\r
da1d0201 1438NetMapRemoveHead (\r
3e7104c2 1439 IN OUT NET_MAP *Map,\r
da1d0201 1440 OUT VOID **Value OPTIONAL\r
1441 )\r
1442{\r
1443 NET_MAP_ITEM *Item;\r
1444\r
1445 //\r
1446 // Often, it indicates a programming error to remove\r
1447 // the first entry in an empty list\r
1448 //\r
e48e37fc 1449 ASSERT (Map && !IsListEmpty (&Map->Used));\r
da1d0201 1450\r
1451 Item = NET_LIST_HEAD (&Map->Used, NET_MAP_ITEM, Link);\r
e48e37fc 1452 RemoveEntryList (&Item->Link);\r
da1d0201 1453 Map->Count--;\r
e48e37fc 1454 InsertHeadList (&Map->Recycled, &Item->Link);\r
da1d0201 1455\r
1456 if (Value != NULL) {\r
1457 *Value = Item->Value;\r
1458 }\r
1459\r
1460 return Item->Key;\r
1461}\r
1462\r
1463\r
1464/**\r
b9008c87 1465 Remove the last node entry on the netmap and return the key of the removed item.\r
da1d0201 1466\r
1204fe83 1467 Remove the last node entry from the Used doubly linked list of the netmap.\r
1468 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node\r
b9008c87 1469 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,\r
1470 parameter Value will point to the value of the item. It returns the key of the removed item.\r
1204fe83 1471\r
b9008c87 1472 If Map is NULL, then ASSERT().\r
1473 If the Used doubly linked list is empty, then ASSERT().\r
1204fe83 1474\r
3e7104c2 1475 @param[in, out] Map The netmap to remove the tail from.\r
1476 @param[out] Value The variable to receive the value if not NULL.\r
da1d0201 1477\r
3e7104c2 1478 @return The key of the item removed.\r
da1d0201 1479\r
1480**/\r
1481VOID *\r
7b414b4e 1482EFIAPI\r
da1d0201 1483NetMapRemoveTail (\r
3e7104c2 1484 IN OUT NET_MAP *Map,\r
da1d0201 1485 OUT VOID **Value OPTIONAL\r
1486 )\r
1487{\r
1488 NET_MAP_ITEM *Item;\r
1489\r
1490 //\r
1491 // Often, it indicates a programming error to remove\r
1492 // the last entry in an empty list\r
1493 //\r
e48e37fc 1494 ASSERT (Map && !IsListEmpty (&Map->Used));\r
da1d0201 1495\r
1496 Item = NET_LIST_TAIL (&Map->Used, NET_MAP_ITEM, Link);\r
e48e37fc 1497 RemoveEntryList (&Item->Link);\r
da1d0201 1498 Map->Count--;\r
e48e37fc 1499 InsertHeadList (&Map->Recycled, &Item->Link);\r
da1d0201 1500\r
1501 if (Value != NULL) {\r
1502 *Value = Item->Value;\r
1503 }\r
1504\r
1505 return Item->Key;\r
1506}\r
1507\r
1508\r
1509/**\r
b9008c87 1510 Iterate through the netmap and call CallBack for each item.\r
1204fe83 1511\r
b9008c87 1512 It will contiue the traverse if CallBack returns EFI_SUCCESS, otherwise, break\r
1204fe83 1513 from the loop. It returns the CallBack's last return value. This function is\r
b9008c87 1514 delete safe for the current item.\r
da1d0201 1515\r
b9008c87 1516 If Map is NULL, then ASSERT().\r
1517 If CallBack is NULL, then ASSERT().\r
1204fe83 1518\r
3e7104c2 1519 @param[in] Map The Map to iterate through.\r
1520 @param[in] CallBack The callback function to call for each item.\r
1521 @param[in] Arg The opaque parameter to the callback.\r
da1d0201 1522\r
3e7104c2 1523 @retval EFI_SUCCESS There is no item in the netmap or CallBack for each item\r
1524 return EFI_SUCCESS.\r
1525 @retval Others It returns the CallBack's last return value.\r
da1d0201 1526\r
1527**/\r
1528EFI_STATUS\r
7b414b4e 1529EFIAPI\r
da1d0201 1530NetMapIterate (\r
1531 IN NET_MAP *Map,\r
1532 IN NET_MAP_CALLBACK CallBack,\r
1533 IN VOID *Arg\r
1534 )\r
1535{\r
1536\r
e48e37fc 1537 LIST_ENTRY *Entry;\r
1538 LIST_ENTRY *Next;\r
1539 LIST_ENTRY *Head;\r
b9008c87 1540 NET_MAP_ITEM *Item;\r
1541 EFI_STATUS Result;\r
da1d0201 1542\r
1543 ASSERT ((Map != NULL) && (CallBack != NULL));\r
1544\r
1545 Head = &Map->Used;\r
1546\r
e48e37fc 1547 if (IsListEmpty (Head)) {\r
da1d0201 1548 return EFI_SUCCESS;\r
1549 }\r
1550\r
1551 NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {\r
1552 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
1553 Result = CallBack (Map, Item, Arg);\r
1554\r
1555 if (EFI_ERROR (Result)) {\r
1556 return Result;\r
1557 }\r
1558 }\r
1559\r
1560 return EFI_SUCCESS;\r
1561}\r
1562\r
1563\r
1564/**\r
1565 This is the default unload handle for all the network drivers.\r
1566\r
b9008c87 1567 Disconnect the driver specified by ImageHandle from all the devices in the handle database.\r
1568 Uninstall all the protocols installed in the driver entry point.\r
1204fe83 1569\r
3e7104c2 1570 @param[in] ImageHandle The drivers' driver image.\r
da1d0201 1571\r
1572 @retval EFI_SUCCESS The image is unloaded.\r
1573 @retval Others Failed to unload the image.\r
1574\r
1575**/\r
1576EFI_STATUS\r
1577EFIAPI\r
1578NetLibDefaultUnload (\r
1579 IN EFI_HANDLE ImageHandle\r
1580 )\r
1581{\r
1582 EFI_STATUS Status;\r
1583 EFI_HANDLE *DeviceHandleBuffer;\r
1584 UINTN DeviceHandleCount;\r
1585 UINTN Index;\r
1586 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
1587 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;\r
3012ce5c 1588 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;\r
da1d0201 1589\r
1590 //\r
1591 // Get the list of all the handles in the handle database.\r
1592 // If there is an error getting the list, then the unload\r
1593 // operation fails.\r
1594 //\r
1595 Status = gBS->LocateHandleBuffer (\r
1596 AllHandles,\r
1597 NULL,\r
1598 NULL,\r
1599 &DeviceHandleCount,\r
1600 &DeviceHandleBuffer\r
1601 );\r
1602\r
1603 if (EFI_ERROR (Status)) {\r
1604 return Status;\r
1605 }\r
1606\r
1607 //\r
1608 // Disconnect the driver specified by ImageHandle from all\r
1609 // the devices in the handle database.\r
1610 //\r
1611 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1612 Status = gBS->DisconnectController (\r
1613 DeviceHandleBuffer[Index],\r
1614 ImageHandle,\r
1615 NULL\r
1616 );\r
1617 }\r
1618\r
1619 //\r
1620 // Uninstall all the protocols installed in the driver entry point\r
1621 //\r
1622 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1623 Status = gBS->HandleProtocol (\r
1624 DeviceHandleBuffer[Index],\r
1625 &gEfiDriverBindingProtocolGuid,\r
1626 (VOID **) &DriverBinding\r
1627 );\r
1628\r
1629 if (EFI_ERROR (Status)) {\r
1630 continue;\r
1631 }\r
1632\r
1633 if (DriverBinding->ImageHandle != ImageHandle) {\r
1634 continue;\r
1635 }\r
1636\r
1637 gBS->UninstallProtocolInterface (\r
1638 ImageHandle,\r
1639 &gEfiDriverBindingProtocolGuid,\r
1640 DriverBinding\r
1641 );\r
1642 Status = gBS->HandleProtocol (\r
1643 DeviceHandleBuffer[Index],\r
1644 &gEfiComponentNameProtocolGuid,\r
1645 (VOID **) &ComponentName\r
1646 );\r
1647 if (!EFI_ERROR (Status)) {\r
1648 gBS->UninstallProtocolInterface (\r
1649 ImageHandle,\r
1650 &gEfiComponentNameProtocolGuid,\r
1651 ComponentName\r
1652 );\r
1653 }\r
1654\r
1655 Status = gBS->HandleProtocol (\r
1656 DeviceHandleBuffer[Index],\r
3012ce5c 1657 &gEfiComponentName2ProtocolGuid,\r
1658 (VOID **) &ComponentName2\r
da1d0201 1659 );\r
da1d0201 1660 if (!EFI_ERROR (Status)) {\r
1661 gBS->UninstallProtocolInterface (\r
3012ce5c 1662 ImageHandle,\r
1663 &gEfiComponentName2ProtocolGuid,\r
1664 ComponentName2\r
1665 );\r
da1d0201 1666 }\r
1667 }\r
1668\r
1669 //\r
1670 // Free the buffer containing the list of handles from the handle database\r
1671 //\r
1672 if (DeviceHandleBuffer != NULL) {\r
1673 gBS->FreePool (DeviceHandleBuffer);\r
1674 }\r
1675\r
1676 return EFI_SUCCESS;\r
1677}\r
1678\r
1679\r
1680\r
1681/**\r
1682 Create a child of the service that is identified by ServiceBindingGuid.\r
1204fe83 1683\r
b9008c87 1684 Get the ServiceBinding Protocol first, then use it to create a child.\r
da1d0201 1685\r
b9008c87 1686 If ServiceBindingGuid is NULL, then ASSERT().\r
1687 If ChildHandle is NULL, then ASSERT().\r
1204fe83 1688\r
3e7104c2 1689 @param[in] Controller The controller which has the service installed.\r
1690 @param[in] Image The image handle used to open service.\r
1691 @param[in] ServiceBindingGuid The service's Guid.\r
8f5e6151 1692 @param[in, out] ChildHandle The handle to receive the create child.\r
da1d0201 1693\r
1694 @retval EFI_SUCCESS The child is successfully created.\r
1695 @retval Others Failed to create the child.\r
1696\r
1697**/\r
1698EFI_STATUS\r
7b414b4e 1699EFIAPI\r
da1d0201 1700NetLibCreateServiceChild (\r
1701 IN EFI_HANDLE Controller,\r
1702 IN EFI_HANDLE Image,\r
1703 IN EFI_GUID *ServiceBindingGuid,\r
3e7104c2 1704 IN OUT EFI_HANDLE *ChildHandle\r
da1d0201 1705 )\r
1706{\r
1707 EFI_STATUS Status;\r
1708 EFI_SERVICE_BINDING_PROTOCOL *Service;\r
1709\r
1710\r
1711 ASSERT ((ServiceBindingGuid != NULL) && (ChildHandle != NULL));\r
1712\r
1713 //\r
1714 // Get the ServiceBinding Protocol\r
1715 //\r
1716 Status = gBS->OpenProtocol (\r
1717 Controller,\r
1718 ServiceBindingGuid,\r
1719 (VOID **) &Service,\r
1720 Image,\r
1721 Controller,\r
1722 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1723 );\r
1724\r
1725 if (EFI_ERROR (Status)) {\r
1726 return Status;\r
1727 }\r
1728\r
1729 //\r
1730 // Create a child\r
1731 //\r
1732 Status = Service->CreateChild (Service, ChildHandle);\r
1733 return Status;\r
1734}\r
1735\r
1736\r
1737/**\r
1738 Destory a child of the service that is identified by ServiceBindingGuid.\r
1204fe83 1739\r
b9008c87 1740 Get the ServiceBinding Protocol first, then use it to destroy a child.\r
1204fe83 1741\r
b9008c87 1742 If ServiceBindingGuid is NULL, then ASSERT().\r
1204fe83 1743\r
3e7104c2 1744 @param[in] Controller The controller which has the service installed.\r
1745 @param[in] Image The image handle used to open service.\r
1746 @param[in] ServiceBindingGuid The service's Guid.\r
8f5e6151 1747 @param[in] ChildHandle The child to destory.\r
da1d0201 1748\r
1749 @retval EFI_SUCCESS The child is successfully destoried.\r
1750 @retval Others Failed to destory the child.\r
1751\r
1752**/\r
1753EFI_STATUS\r
7b414b4e 1754EFIAPI\r
da1d0201 1755NetLibDestroyServiceChild (\r
1756 IN EFI_HANDLE Controller,\r
1757 IN EFI_HANDLE Image,\r
1758 IN EFI_GUID *ServiceBindingGuid,\r
1759 IN EFI_HANDLE ChildHandle\r
1760 )\r
1761{\r
1762 EFI_STATUS Status;\r
1763 EFI_SERVICE_BINDING_PROTOCOL *Service;\r
1764\r
1765 ASSERT (ServiceBindingGuid != NULL);\r
1766\r
1767 //\r
1768 // Get the ServiceBinding Protocol\r
1769 //\r
1770 Status = gBS->OpenProtocol (\r
1771 Controller,\r
1772 ServiceBindingGuid,\r
1773 (VOID **) &Service,\r
1774 Image,\r
1775 Controller,\r
1776 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1777 );\r
1778\r
1779 if (EFI_ERROR (Status)) {\r
1780 return Status;\r
1781 }\r
1782\r
1783 //\r
1784 // destory the child\r
1785 //\r
1786 Status = Service->DestroyChild (Service, ChildHandle);\r
1787 return Status;\r
1788}\r
1789\r
779ae357 1790/**\r
1791 Get handle with Simple Network Protocol installed on it.\r
1792\r
1793 There should be MNP Service Binding Protocol installed on the input ServiceHandle.\r
1794 If Simple Network Protocol is already installed on the ServiceHandle, the\r
1795 ServiceHandle will be returned. If SNP is not installed on the ServiceHandle,\r
1796 try to find its parent handle with SNP installed.\r
1797\r
1798 @param[in] ServiceHandle The handle where network service binding protocols are\r
1799 installed on.\r
1800 @param[out] Snp The pointer to store the address of the SNP instance.\r
1801 This is an optional parameter that may be NULL.\r
1802\r
1803 @return The SNP handle, or NULL if not found.\r
1804\r
1805**/\r
1806EFI_HANDLE\r
1807EFIAPI\r
1808NetLibGetSnpHandle (\r
1809 IN EFI_HANDLE ServiceHandle,\r
1810 OUT EFI_SIMPLE_NETWORK_PROTOCOL **Snp OPTIONAL\r
1811 )\r
1812{\r
1813 EFI_STATUS Status;\r
1814 EFI_SIMPLE_NETWORK_PROTOCOL *SnpInstance;\r
1815 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1816 EFI_HANDLE SnpHandle;\r
1817\r
1818 //\r
1819 // Try to open SNP from ServiceHandle\r
1820 //\r
1821 SnpInstance = NULL;\r
1822 Status = gBS->HandleProtocol (ServiceHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);\r
1823 if (!EFI_ERROR (Status)) {\r
1824 if (Snp != NULL) {\r
1825 *Snp = SnpInstance;\r
1826 }\r
1827 return ServiceHandle;\r
1828 }\r
1829\r
1830 //\r
1831 // Failed to open SNP, try to get SNP handle by LocateDevicePath()\r
1832 //\r
1833 DevicePath = DevicePathFromHandle (ServiceHandle);\r
1834 if (DevicePath == NULL) {\r
1835 return NULL;\r
1836 }\r
1837\r
1838 SnpHandle = NULL;\r
1839 Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &DevicePath, &SnpHandle);\r
1840 if (EFI_ERROR (Status)) {\r
1841 //\r
1842 // Failed to find SNP handle\r
1843 //\r
1844 return NULL;\r
1845 }\r
1846\r
1847 Status = gBS->HandleProtocol (SnpHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);\r
1848 if (!EFI_ERROR (Status)) {\r
1849 if (Snp != NULL) {\r
1850 *Snp = SnpInstance;\r
1851 }\r
1852 return SnpHandle;\r
1853 }\r
1854\r
1855 return NULL;\r
1856}\r
1857\r
1858/**\r
1859 Retrieve VLAN ID of a VLAN device handle.\r
1860\r
1861 Search VLAN device path node in Device Path of specified ServiceHandle and\r
1862 return its VLAN ID. If no VLAN device path node found, then this ServiceHandle\r
1863 is not a VLAN device handle, and 0 will be returned.\r
1864\r
1865 @param[in] ServiceHandle The handle where network service binding protocols are\r
1866 installed on.\r
1867\r
1868 @return VLAN ID of the device handle, or 0 if not a VLAN device.\r
1869\r
1870**/\r
1871UINT16\r
1872EFIAPI\r
1873NetLibGetVlanId (\r
1874 IN EFI_HANDLE ServiceHandle\r
1875 )\r
1876{\r
1877 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1878 EFI_DEVICE_PATH_PROTOCOL *Node;\r
1879\r
1880 DevicePath = DevicePathFromHandle (ServiceHandle);\r
1881 if (DevicePath == NULL) {\r
1882 return 0;\r
1883 }\r
1884\r
1885 Node = DevicePath;\r
1886 while (!IsDevicePathEnd (Node)) {\r
1887 if (Node->Type == MESSAGING_DEVICE_PATH && Node->SubType == MSG_VLAN_DP) {\r
1888 return ((VLAN_DEVICE_PATH *) Node)->VlanId;\r
1889 }\r
1890 Node = NextDevicePathNode (Node);\r
1891 }\r
1892\r
1893 return 0;\r
1894}\r
1895\r
1896/**\r
1897 Find VLAN device handle with specified VLAN ID.\r
1898\r
1899 The VLAN child device handle is created by VLAN Config Protocol on ControllerHandle.\r
1900 This function will append VLAN device path node to the parent device path,\r
1901 and then use LocateDevicePath() to find the correct VLAN device handle.\r
1902\r
1903 @param[in] ServiceHandle The handle where network service binding protocols are\r
1904 installed on.\r
1905 @param[in] VLanId The configured VLAN ID for the VLAN device.\r
1906\r
1907 @return The VLAN device handle, or NULL if not found.\r
1908\r
1909**/\r
1910EFI_HANDLE\r
1911EFIAPI\r
1912NetLibGetVlanHandle (\r
1913 IN EFI_HANDLE ControllerHandle,\r
1914 IN UINT16 VlanId\r
1915 )\r
1916{\r
1917 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
1918 EFI_DEVICE_PATH_PROTOCOL *VlanDevicePath;\r
1919 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1920 VLAN_DEVICE_PATH VlanNode;\r
1921 EFI_HANDLE Handle;\r
1922\r
1923 ParentDevicePath = DevicePathFromHandle (ControllerHandle);\r
1924 if (ParentDevicePath == NULL) {\r
1925 return NULL;\r
1926 }\r
1927\r
1928 //\r
1929 // Construct VLAN device path\r
1930 //\r
1931 CopyMem (&VlanNode, &mNetVlanDevicePathTemplate, sizeof (VLAN_DEVICE_PATH));\r
1932 VlanNode.VlanId = VlanId;\r
1933 VlanDevicePath = AppendDevicePathNode (\r
1934 ParentDevicePath,\r
1935 (EFI_DEVICE_PATH_PROTOCOL *) &VlanNode\r
1936 );\r
1937 if (VlanDevicePath == NULL) {\r
1938 return NULL;\r
1939 }\r
1940\r
1941 //\r
1942 // Find VLAN device handle\r
1943 //\r
1944 Handle = NULL;\r
1945 DevicePath = VlanDevicePath;\r
1946 gBS->LocateDevicePath (\r
1947 &gEfiDevicePathProtocolGuid,\r
1948 &DevicePath,\r
1949 &Handle\r
1950 );\r
1951 if (!IsDevicePathEnd (DevicePath)) {\r
1952 //\r
1953 // Device path is not exactly match\r
1954 //\r
1955 Handle = NULL;\r
1956 }\r
1957\r
1958 FreePool (VlanDevicePath);\r
1959 return Handle;\r
1960}\r
da1d0201 1961\r
1962/**\r
779ae357 1963 Get MAC address associated with the network service handle.\r
1964\r
1965 There should be MNP Service Binding Protocol installed on the input ServiceHandle.\r
1966 If SNP is installed on the ServiceHandle or its parent handle, MAC address will\r
1967 be retrieved from SNP. If no SNP found, try to get SNP mode data use MNP.\r
1968\r
1969 @param[in] ServiceHandle The handle where network service binding protocols are\r
1970 installed on.\r
1971 @param[out] MacAddress The pointer to store the returned MAC address.\r
1972 @param[out] AddressSize The length of returned MAC address.\r
1973\r
1974 @retval EFI_SUCCESS MAC address is returned successfully.\r
1975 @retval Others Failed to get SNP mode data.\r
1976\r
1977**/\r
1978EFI_STATUS\r
1979EFIAPI\r
1980NetLibGetMacAddress (\r
1981 IN EFI_HANDLE ServiceHandle,\r
1982 OUT EFI_MAC_ADDRESS *MacAddress,\r
1983 OUT UINTN *AddressSize\r
1984 )\r
1985{\r
1986 EFI_STATUS Status;\r
1987 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
1988 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
1989 EFI_SIMPLE_NETWORK_MODE SnpModeData;\r
1990 EFI_MANAGED_NETWORK_PROTOCOL *Mnp;\r
1991 EFI_SERVICE_BINDING_PROTOCOL *MnpSb;\r
1992 EFI_HANDLE *SnpHandle;\r
1993 EFI_HANDLE MnpChildHandle;\r
1994\r
1995 ASSERT (MacAddress != NULL);\r
1996 ASSERT (AddressSize != NULL);\r
1997\r
1998 //\r
1999 // Try to get SNP handle\r
2000 //\r
2001 Snp = NULL;\r
2002 SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);\r
2003 if (SnpHandle != NULL) {\r
2004 //\r
2005 // SNP found, use it directly\r
2006 //\r
2007 SnpMode = Snp->Mode;\r
2008 } else {\r
2009 //\r
2010 // Failed to get SNP handle, try to get MAC address from MNP\r
2011 //\r
2012 MnpChildHandle = NULL;\r
2013 Status = gBS->HandleProtocol (\r
2014 ServiceHandle,\r
2015 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
2016 (VOID **) &MnpSb\r
2017 );\r
2018 if (EFI_ERROR (Status)) {\r
2019 return Status;\r
2020 }\r
2021\r
2022 //\r
2023 // Create a MNP child\r
2024 //\r
2025 Status = MnpSb->CreateChild (MnpSb, &MnpChildHandle);\r
2026 if (EFI_ERROR (Status)) {\r
2027 return Status;\r
2028 }\r
2029\r
2030 //\r
2031 // Open MNP protocol\r
2032 //\r
2033 Status = gBS->HandleProtocol (\r
2034 MnpChildHandle,\r
2035 &gEfiManagedNetworkProtocolGuid,\r
2036 (VOID **) &Mnp\r
2037 );\r
2038 if (EFI_ERROR (Status)) {\r
2039 return Status;\r
2040 }\r
da1d0201 2041\r
779ae357 2042 //\r
2043 // Try to get SNP mode from MNP\r
2044 //\r
2045 Status = Mnp->GetModeData (Mnp, NULL, &SnpModeData);\r
2046 if (EFI_ERROR (Status)) {\r
2047 return Status;\r
2048 }\r
2049 SnpMode = &SnpModeData;\r
b9008c87 2050\r
779ae357 2051 //\r
2052 // Destroy the MNP child\r
2053 //\r
2054 MnpSb->DestroyChild (MnpSb, MnpChildHandle);\r
2055 }\r
b9008c87 2056\r
779ae357 2057 *AddressSize = SnpMode->HwAddressSize;\r
2058 CopyMem (MacAddress->Addr, SnpMode->CurrentAddress.Addr, SnpMode->HwAddressSize);\r
2059\r
2060 return EFI_SUCCESS;\r
2061}\r
2062\r
2063/**\r
2064 Convert MAC address of the NIC associated with specified Service Binding Handle\r
2065 to a unicode string. Callers are responsible for freeing the string storage.\r
2066\r
2067 Locate simple network protocol associated with the Service Binding Handle and\r
2068 get the mac address from SNP. Then convert the mac address into a unicode\r
2069 string. It takes 2 unicode characters to represent a 1 byte binary buffer.\r
2070 Plus one unicode character for the null-terminator.\r
2071\r
2072 @param[in] ServiceHandle The handle where network service binding protocol is\r
3e7104c2 2073 installed on.\r
2074 @param[in] ImageHandle The image handle used to act as the agent handle to\r
2075 get the simple network protocol.\r
2076 @param[out] MacString The pointer to store the address of the string\r
2077 representation of the mac address.\r
1204fe83 2078\r
3e7104c2 2079 @retval EFI_SUCCESS Convert the mac address a unicode string successfully.\r
da1d0201 2080 @retval EFI_OUT_OF_RESOURCES There are not enough memory resource.\r
3e7104c2 2081 @retval Others Failed to open the simple network protocol.\r
da1d0201 2082\r
2083**/\r
2084EFI_STATUS\r
7b414b4e 2085EFIAPI\r
da1d0201 2086NetLibGetMacString (\r
779ae357 2087 IN EFI_HANDLE ServiceHandle,\r
3e7104c2 2088 IN EFI_HANDLE ImageHandle,\r
2089 OUT CHAR16 **MacString\r
da1d0201 2090 )\r
2091{\r
2092 EFI_STATUS Status;\r
779ae357 2093 EFI_MAC_ADDRESS MacAddress;\r
1204fe83 2094 UINT8 *HwAddress;\r
779ae357 2095 UINTN HwAddressSize;\r
2096 UINT16 VlanId;\r
2097 CHAR16 *String;\r
da1d0201 2098 UINTN Index;\r
2099\r
779ae357 2100 ASSERT (MacString != NULL);\r
da1d0201 2101\r
2102 //\r
779ae357 2103 // Get MAC address of the network device\r
da1d0201 2104 //\r
779ae357 2105 Status = NetLibGetMacAddress (ServiceHandle, &MacAddress, &HwAddressSize);\r
da1d0201 2106 if (EFI_ERROR (Status)) {\r
2107 return Status;\r
2108 }\r
2109\r
da1d0201 2110 //\r
2111 // It takes 2 unicode characters to represent a 1 byte binary buffer.\r
779ae357 2112 // If VLAN is configured, it will need extra 5 characters like "\0005".\r
da1d0201 2113 // Plus one unicode character for the null-terminator.\r
2114 //\r
779ae357 2115 String = AllocateZeroPool ((2 * HwAddressSize + 5 + 1) * sizeof (CHAR16));\r
2116 if (String == NULL) {\r
da1d0201 2117 return EFI_OUT_OF_RESOURCES;\r
2118 }\r
779ae357 2119 *MacString = String;\r
da1d0201 2120\r
2121 //\r
779ae357 2122 // Convert the MAC address into a unicode string.\r
da1d0201 2123 //\r
779ae357 2124 HwAddress = &MacAddress.Addr[0];\r
2125 for (Index = 0; Index < HwAddressSize; Index++) {\r
2126 String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(HwAddress++), 2);\r
da1d0201 2127 }\r
2128\r
779ae357 2129 //\r
2130 // Append VLAN ID if any\r
2131 //\r
2132 VlanId = NetLibGetVlanId (ServiceHandle);\r
2133 if (VlanId != 0) {\r
2134 *String++ = L'\\';\r
2135 String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, VlanId, 4);\r
2136 }\r
da1d0201 2137\r
779ae357 2138 //\r
2139 // Null terminate the Unicode string\r
2140 //\r
2141 *String = L'\0';\r
da1d0201 2142\r
2143 return EFI_SUCCESS;\r
2144}\r
2145\r
2146/**\r
2147 Check the default address used by the IPv4 driver is static or dynamic (acquired\r
2148 from DHCP).\r
2149\r
1204fe83 2150 If the controller handle does not have the NIC Ip4 Config Protocol installed, the\r
b9008c87 2151 default address is static. If the EFI variable to save the configuration is not found,\r
1204fe83 2152 the default address is static. Otherwise, get the result from the EFI variable which\r
b9008c87 2153 saving the configuration.\r
1204fe83 2154\r
3e7104c2 2155 @param[in] Controller The controller handle which has the NIC Ip4 Config Protocol\r
2156 relative with the default address to judge.\r
da1d0201 2157\r
2158 @retval TRUE If the default address is static.\r
2159 @retval FALSE If the default address is acquired from DHCP.\r
2160\r
2161**/\r
da1d0201 2162BOOLEAN\r
2163NetLibDefaultAddressIsStatic (\r
2164 IN EFI_HANDLE Controller\r
2165 )\r
2166{\r
63886849 2167 EFI_STATUS Status;\r
2168 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;\r
2169 UINTN Len;\r
2170 NIC_IP4_CONFIG_INFO *ConfigInfo;\r
2171 BOOLEAN IsStatic;\r
2172 EFI_STRING ConfigHdr;\r
2173 EFI_STRING ConfigResp;\r
2174 EFI_STRING AccessProgress;\r
2175 EFI_STRING AccessResults;\r
2176 EFI_STRING String;\r
2177\r
2178 ConfigInfo = NULL;\r
2179 ConfigHdr = NULL;\r
2180 ConfigResp = NULL;\r
2181 AccessProgress = NULL;\r
2182 AccessResults = NULL;\r
2183 IsStatic = TRUE;\r
2184\r
2185 Status = gBS->LocateProtocol (\r
2186 &gEfiHiiConfigRoutingProtocolGuid,\r
2187 NULL,\r
2188 (VOID **) &HiiConfigRouting\r
2189 );\r
da1d0201 2190 if (EFI_ERROR (Status)) {\r
2191 return TRUE;\r
2192 }\r
2193\r
63886849 2194 //\r
2195 // Construct config request string header\r
2196 //\r
2197 ConfigHdr = HiiConstructConfigHdr (&gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE, Controller);\r
894d038a 2198 if (ConfigHdr == NULL) {\r
2199 return TRUE;\r
2200 }\r
1204fe83 2201\r
63886849 2202 Len = StrLen (ConfigHdr);\r
ce4106be 2203 ConfigResp = AllocateZeroPool ((Len + NIC_ITEM_CONFIG_SIZE * 2 + 100) * sizeof (CHAR16));\r
63886849 2204 if (ConfigResp == NULL) {\r
2205 goto ON_EXIT;\r
2206 }\r
2207 StrCpy (ConfigResp, ConfigHdr);\r
2208\r
2209 String = ConfigResp + Len;\r
2210 UnicodeSPrint (\r
1204fe83 2211 String,\r
2212 (8 + 4 + 7 + 4 + 1) * sizeof (CHAR16),\r
2213 L"&OFFSET=%04X&WIDTH=%04X",\r
2214 OFFSET_OF (NIC_IP4_CONFIG_INFO, Source),\r
63886849 2215 sizeof (UINT32)\r
2216 );\r
2217\r
2218 Status = HiiConfigRouting->ExtractConfig (\r
2219 HiiConfigRouting,\r
2220 ConfigResp,\r
2221 &AccessProgress,\r
2222 &AccessResults\r
2223 );\r
2224 if (EFI_ERROR (Status)) {\r
2225 goto ON_EXIT;\r
da1d0201 2226 }\r
2227\r
ce4106be 2228 ConfigInfo = AllocateZeroPool (sizeof (NIC_ITEM_CONFIG_SIZE));\r
da1d0201 2229 if (ConfigInfo == NULL) {\r
63886849 2230 goto ON_EXIT;\r
da1d0201 2231 }\r
2232\r
63886849 2233 ConfigInfo->Source = IP4_CONFIG_SOURCE_STATIC;\r
2234 Len = NIC_ITEM_CONFIG_SIZE;\r
2235 Status = HiiConfigRouting->ConfigToBlock (\r
2236 HiiConfigRouting,\r
2237 AccessResults,\r
2238 (UINT8 *) ConfigInfo,\r
2239 &Len,\r
2240 &AccessProgress\r
2241 );\r
da1d0201 2242 if (EFI_ERROR (Status)) {\r
2243 goto ON_EXIT;\r
2244 }\r
2245\r
2246 IsStatic = (BOOLEAN) (ConfigInfo->Source == IP4_CONFIG_SOURCE_STATIC);\r
1204fe83 2247\r
da1d0201 2248ON_EXIT:\r
2249\r
63886849 2250 if (AccessResults != NULL) {\r
2251 FreePool (AccessResults);\r
2252 }\r
2253 if (ConfigInfo != NULL) {\r
2254 FreePool (ConfigInfo);\r
2255 }\r
2256 if (ConfigResp != NULL) {\r
2257 FreePool (ConfigResp);\r
2258 }\r
2259 if (ConfigHdr != NULL) {\r
2260 FreePool (ConfigHdr);\r
2261 }\r
da1d0201 2262\r
2263 return IsStatic;\r
2264}\r
2265\r
2266/**\r
2267 Create an IPv4 device path node.\r
1204fe83 2268\r
b9008c87 2269 The header type of IPv4 device path node is MESSAGING_DEVICE_PATH.\r
2270 The header subtype of IPv4 device path node is MSG_IPv4_DP.\r
2271 The length of the IPv4 device path node in bytes is 19.\r
2272 Get other info from parameters to make up the whole IPv4 device path node.\r
da1d0201 2273\r
3e7104c2 2274 @param[in, out] Node Pointer to the IPv4 device path node.\r
f6b7393c 2275 @param[in] Controller The controller handle.\r
3e7104c2 2276 @param[in] LocalIp The local IPv4 address.\r
2277 @param[in] LocalPort The local port.\r
2278 @param[in] RemoteIp The remote IPv4 address.\r
2279 @param[in] RemotePort The remote port.\r
2280 @param[in] Protocol The protocol type in the IP header.\r
2281 @param[in] UseDefaultAddress Whether this instance is using default address or not.\r
da1d0201 2282\r
da1d0201 2283**/\r
2284VOID\r
7b414b4e 2285EFIAPI\r
da1d0201 2286NetLibCreateIPv4DPathNode (\r
2287 IN OUT IPv4_DEVICE_PATH *Node,\r
2288 IN EFI_HANDLE Controller,\r
2289 IN IP4_ADDR LocalIp,\r
2290 IN UINT16 LocalPort,\r
2291 IN IP4_ADDR RemoteIp,\r
2292 IN UINT16 RemotePort,\r
2293 IN UINT16 Protocol,\r
2294 IN BOOLEAN UseDefaultAddress\r
2295 )\r
2296{\r
2297 Node->Header.Type = MESSAGING_DEVICE_PATH;\r
2298 Node->Header.SubType = MSG_IPv4_DP;\r
2299 SetDevicePathNodeLength (&Node->Header, 19);\r
2300\r
e48e37fc 2301 CopyMem (&Node->LocalIpAddress, &LocalIp, sizeof (EFI_IPv4_ADDRESS));\r
2302 CopyMem (&Node->RemoteIpAddress, &RemoteIp, sizeof (EFI_IPv4_ADDRESS));\r
da1d0201 2303\r
2304 Node->LocalPort = LocalPort;\r
2305 Node->RemotePort = RemotePort;\r
2306\r
2307 Node->Protocol = Protocol;\r
2308\r
2309 if (!UseDefaultAddress) {\r
2310 Node->StaticIpAddress = TRUE;\r
2311 } else {\r
2312 Node->StaticIpAddress = NetLibDefaultAddressIsStatic (Controller);\r
2313 }\r
2314}\r
2315\r
f6b7393c 2316/**\r
2317 Create an IPv6 device path node.\r
1204fe83 2318\r
f6b7393c 2319 The header type of IPv6 device path node is MESSAGING_DEVICE_PATH.\r
2320 The header subtype of IPv6 device path node is MSG_IPv6_DP.\r
2321 Get other info from parameters to make up the whole IPv6 device path node.\r
2322\r
2323 @param[in, out] Node Pointer to the IPv6 device path node.\r
2324 @param[in] Controller The controller handle.\r
2325 @param[in] LocalIp The local IPv6 address.\r
2326 @param[in] LocalPort The local port.\r
2327 @param[in] RemoteIp The remote IPv6 address.\r
2328 @param[in] RemotePort The remote port.\r
2329 @param[in] Protocol The protocol type in the IP header.\r
2330\r
2331**/\r
2332VOID\r
2333EFIAPI\r
2334NetLibCreateIPv6DPathNode (\r
2335 IN OUT IPv6_DEVICE_PATH *Node,\r
2336 IN EFI_HANDLE Controller,\r
2337 IN EFI_IPv6_ADDRESS *LocalIp,\r
2338 IN UINT16 LocalPort,\r
2339 IN EFI_IPv6_ADDRESS *RemoteIp,\r
2340 IN UINT16 RemotePort,\r
2341 IN UINT16 Protocol\r
2342 )\r
2343{\r
2344 Node->Header.Type = MESSAGING_DEVICE_PATH;\r
2345 Node->Header.SubType = MSG_IPv6_DP;\r
2346 SetDevicePathNodeLength (&Node->Header, sizeof (IPv6_DEVICE_PATH));\r
2347\r
2348 CopyMem (&Node->LocalIpAddress, LocalIp, sizeof (EFI_IPv6_ADDRESS));\r
2349 CopyMem (&Node->RemoteIpAddress, RemoteIp, sizeof (EFI_IPv6_ADDRESS));\r
2350\r
2351 Node->LocalPort = LocalPort;\r
2352 Node->RemotePort = RemotePort;\r
2353\r
2354 Node->Protocol = Protocol;\r
2355 Node->StaticIpAddress = FALSE;\r
2356}\r
da1d0201 2357\r
2358/**\r
2359 Find the UNDI/SNP handle from controller and protocol GUID.\r
1204fe83 2360\r
da1d0201 2361 For example, IP will open a MNP child to transmit/receive\r
2362 packets, when MNP is stopped, IP should also be stopped. IP\r
2363 needs to find its own private data which is related the IP's\r
2364 service binding instance that is install on UNDI/SNP handle.\r
2365 Now, the controller is either a MNP or ARP child handle. But\r
2366 IP opens these handle BY_DRIVER, use that info, we can get the\r
2367 UNDI/SNP handle.\r
2368\r
3e7104c2 2369 @param[in] Controller Then protocol handle to check.\r
2370 @param[in] ProtocolGuid The protocol that is related with the handle.\r
da1d0201 2371\r
3e7104c2 2372 @return The UNDI/SNP handle or NULL for errors.\r
da1d0201 2373\r
2374**/\r
2375EFI_HANDLE\r
7b414b4e 2376EFIAPI\r
da1d0201 2377NetLibGetNicHandle (\r
2378 IN EFI_HANDLE Controller,\r
2379 IN EFI_GUID *ProtocolGuid\r
2380 )\r
2381{\r
2382 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenBuffer;\r
2383 EFI_HANDLE Handle;\r
2384 EFI_STATUS Status;\r
2385 UINTN OpenCount;\r
2386 UINTN Index;\r
2387\r
2388 Status = gBS->OpenProtocolInformation (\r
2389 Controller,\r
2390 ProtocolGuid,\r
2391 &OpenBuffer,\r
2392 &OpenCount\r
2393 );\r
2394\r
2395 if (EFI_ERROR (Status)) {\r
2396 return NULL;\r
2397 }\r
2398\r
2399 Handle = NULL;\r
2400\r
2401 for (Index = 0; Index < OpenCount; Index++) {\r
2402 if (OpenBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) {\r
2403 Handle = OpenBuffer[Index].ControllerHandle;\r
2404 break;\r
2405 }\r
2406 }\r
2407\r
2408 gBS->FreePool (OpenBuffer);\r
2409 return Handle;\r
2410}\r