]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeNetLib/DxeNetLib.c
MdeModulePkg: Remove trailing white space
[mirror_edk2.git] / MdeModulePkg / Library / DxeNetLib / DxeNetLib.c
CommitLineData
da1d0201 1/** @file\r
3e7104c2 2 Network library.\r
1204fe83 3\r
cf4a8fa4 4Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>\r
33ecfa8a 5(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
cd5ebaa0 6This program and the accompanying materials\r
da1d0201 7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
da1d0201 13**/\r
14\r
3e7104c2 15#include <Uefi.h>\r
da1d0201 16\r
57b301b5 17#include <IndustryStandard/SmBios.h>\r
18\r
752ef5d8 19#include <Protocol/DriverBinding.h>\r
da1d0201 20#include <Protocol/ServiceBinding.h>\r
21#include <Protocol/SimpleNetwork.h>\r
ca4e4323 22#include <Protocol/AdapterInformation.h>\r
1204fe83 23#include <Protocol/ManagedNetwork.h>\r
6c5c70d6 24#include <Protocol/Ip4Config2.h>\r
3012ce5c 25#include <Protocol/ComponentName.h>\r
26#include <Protocol/ComponentName2.h>\r
da1d0201 27\r
57b301b5 28#include <Guid/SmBios.h>\r
63886849 29\r
da1d0201 30#include <Library/NetLib.h>\r
31#include <Library/BaseLib.h>\r
32#include <Library/DebugLib.h>\r
33#include <Library/BaseMemoryLib.h>\r
34#include <Library/UefiBootServicesTableLib.h>\r
35#include <Library/UefiRuntimeServicesTableLib.h>\r
da1d0201 36#include <Library/MemoryAllocationLib.h>\r
1232b214 37#include <Library/DevicePathLib.h>\r
63886849 38#include <Library/PrintLib.h>\r
1dc1b43f 39#include <Library/UefiLib.h>\r
da1d0201 40\r
2a2f01b9 41#define NIC_ITEM_CONFIG_SIZE (sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE)\r
216f7970 42#define DEFAULT_ZERO_START ((UINTN) ~0)\r
63886849 43\r
da1d0201 44//\r
45// All the supported IP4 maskes in host byte order.\r
46//\r
1204fe83 47GLOBAL_REMOVE_IF_UNREFERENCED IP4_ADDR gIp4AllMasks[IP4_MASK_NUM] = {\r
da1d0201 48 0x00000000,\r
49 0x80000000,\r
50 0xC0000000,\r
51 0xE0000000,\r
52 0xF0000000,\r
53 0xF8000000,\r
54 0xFC000000,\r
55 0xFE000000,\r
56\r
57 0xFF000000,\r
58 0xFF800000,\r
59 0xFFC00000,\r
60 0xFFE00000,\r
61 0xFFF00000,\r
62 0xFFF80000,\r
63 0xFFFC0000,\r
64 0xFFFE0000,\r
65\r
66 0xFFFF0000,\r
67 0xFFFF8000,\r
68 0xFFFFC000,\r
69 0xFFFFE000,\r
70 0xFFFFF000,\r
71 0xFFFFF800,\r
72 0xFFFFFC00,\r
73 0xFFFFFE00,\r
74\r
75 0xFFFFFF00,\r
76 0xFFFFFF80,\r
77 0xFFFFFFC0,\r
78 0xFFFFFFE0,\r
79 0xFFFFFFF0,\r
80 0xFFFFFFF8,\r
81 0xFFFFFFFC,\r
82 0xFFFFFFFE,\r
83 0xFFFFFFFF,\r
84};\r
85\r
1204fe83 86GLOBAL_REMOVE_IF_UNREFERENCED EFI_IPv4_ADDRESS mZeroIp4Addr = {{0, 0, 0, 0}};\r
da1d0201 87\r
f6b7393c 88//\r
1204fe83 89// Any error level digitally larger than mNetDebugLevelMax\r
f6b7393c 90// will be silently discarded.\r
91//\r
1204fe83 92GLOBAL_REMOVE_IF_UNREFERENCED UINTN mNetDebugLevelMax = NETDEBUG_LEVEL_ERROR;\r
93GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogPacketSeq = 0xDEADBEEF;\r
f6b7393c 94\r
f6b7393c 95//\r
1204fe83 96// You can change mSyslogDstMac mSyslogDstIp and mSyslogSrcIp\r
97// here to direct the syslog packets to the syslog deamon. The\r
98// default is broadcast to both the ethernet and IP.\r
99//\r
100GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mSyslogDstMac[NET_ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
101GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogDstIp = 0xffffffff;\r
102GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mSyslogSrcIp = 0;\r
f6b7393c 103\r
1204fe83 104GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mMonthName[] = {\r
f6b7393c 105 "Jan",\r
106 "Feb",\r
107 "Mar",\r
108 "Apr",\r
109 "May",\r
110 "Jun",\r
111 "Jul",\r
112 "Aug",\r
113 "Sep",\r
114 "Oct",\r
115 "Nov",\r
116 "Dec"\r
117};\r
118\r
779ae357 119//\r
120// VLAN device path node template\r
121//\r
122GLOBAL_REMOVE_IF_UNREFERENCED VLAN_DEVICE_PATH mNetVlanDevicePathTemplate = {\r
123 {\r
124 MESSAGING_DEVICE_PATH,\r
125 MSG_VLAN_DP,\r
126 {\r
127 (UINT8) (sizeof (VLAN_DEVICE_PATH)),\r
128 (UINT8) ((sizeof (VLAN_DEVICE_PATH)) >> 8)\r
129 }\r
130 },\r
131 0\r
132};\r
133\r
f6b7393c 134/**\r
1204fe83 135 Locate the handles that support SNP, then open one of them\r
f6b7393c 136 to send the syslog packets. The caller isn't required to close\r
137 the SNP after use because the SNP is opened by HandleProtocol.\r
138\r
139 @return The point to SNP if one is properly openned. Otherwise NULL\r
140\r
141**/\r
142EFI_SIMPLE_NETWORK_PROTOCOL *\r
143SyslogLocateSnp (\r
144 VOID\r
145 )\r
146{\r
147 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
148 EFI_STATUS Status;\r
149 EFI_HANDLE *Handles;\r
150 UINTN HandleCount;\r
151 UINTN Index;\r
152\r
153 //\r
154 // Locate the handles which has SNP installed.\r
155 //\r
156 Handles = NULL;\r
157 Status = gBS->LocateHandleBuffer (\r
158 ByProtocol,\r
159 &gEfiSimpleNetworkProtocolGuid,\r
160 NULL,\r
161 &HandleCount,\r
162 &Handles\r
163 );\r
164\r
165 if (EFI_ERROR (Status) || (HandleCount == 0)) {\r
166 return NULL;\r
167 }\r
1204fe83 168\r
f6b7393c 169 //\r
170 // Try to open one of the ethernet SNP protocol to send packet\r
171 //\r
172 Snp = NULL;\r
1204fe83 173\r
f6b7393c 174 for (Index = 0; Index < HandleCount; Index++) {\r
175 Status = gBS->HandleProtocol (\r
176 Handles[Index],\r
177 &gEfiSimpleNetworkProtocolGuid,\r
178 (VOID **) &Snp\r
179 );\r
180\r
1204fe83 181 if ((Status == EFI_SUCCESS) && (Snp != NULL) &&\r
f6b7393c 182 (Snp->Mode->IfType == NET_IFTYPE_ETHERNET) &&\r
183 (Snp->Mode->MaxPacketSize >= NET_SYSLOG_PACKET_LEN)) {\r
1204fe83 184\r
f6b7393c 185 break;\r
186 }\r
187\r
188 Snp = NULL;\r
189 }\r
190\r
ad108abe 191 FreePool (Handles);\r
f6b7393c 192 return Snp;\r
193}\r
194\r
195/**\r
196 Transmit a syslog packet synchronously through SNP. The Packet\r
1204fe83 197 already has the ethernet header prepended. This function should\r
f6b7393c 198 fill in the source MAC because it will try to locate a SNP each\r
199 time it is called to avoid the problem if SNP is unloaded.\r
1204fe83 200 This code snip is copied from MNP.\r
cf4a8fa4 201 If Packet is NULL, then ASSERT().\r
1204fe83 202\r
203 @param[in] Packet The Syslog packet\r
204 @param[in] Length The length of the packet\r
f6b7393c 205\r
1204fe83 206 @retval EFI_DEVICE_ERROR Failed to locate a usable SNP protocol\r
207 @retval EFI_TIMEOUT Timeout happened to send the packet.\r
208 @retval EFI_SUCCESS Packet is sent.\r
f6b7393c 209\r
f6b7393c 210**/\r
211EFI_STATUS\r
212SyslogSendPacket (\r
213 IN CHAR8 *Packet,\r
214 IN UINT32 Length\r
215 )\r
216{\r
217 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
218 ETHER_HEAD *Ether;\r
219 EFI_STATUS Status;\r
220 EFI_EVENT TimeoutEvent;\r
221 UINT8 *TxBuf;\r
222\r
cf4a8fa4
WF
223 ASSERT (Packet != NULL);\r
224\r
f6b7393c 225 Snp = SyslogLocateSnp ();\r
226\r
227 if (Snp == NULL) {\r
228 return EFI_DEVICE_ERROR;\r
229 }\r
230\r
231 Ether = (ETHER_HEAD *) Packet;\r
232 CopyMem (Ether->SrcMac, Snp->Mode->CurrentAddress.Addr, NET_ETHER_ADDR_LEN);\r
233\r
234 //\r
235 // Start the timeout event.\r
236 //\r
237 Status = gBS->CreateEvent (\r
238 EVT_TIMER,\r
239 TPL_NOTIFY,\r
240 NULL,\r
241 NULL,\r
242 &TimeoutEvent\r
243 );\r
244\r
245 if (EFI_ERROR (Status)) {\r
246 return Status;\r
247 }\r
248\r
249 Status = gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);\r
250\r
251 if (EFI_ERROR (Status)) {\r
252 goto ON_EXIT;\r
253 }\r
254\r
255 for (;;) {\r
256 //\r
257 // Transmit the packet through SNP.\r
258 //\r
259 Status = Snp->Transmit (Snp, 0, Length, Packet, NULL, NULL, NULL);\r
260\r
261 if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {\r
262 Status = EFI_DEVICE_ERROR;\r
263 break;\r
264 }\r
1204fe83 265\r
f6b7393c 266 //\r
267 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.\r
268 // if Status is EFI_NOT_READY, the transmit engine of the network\r
269 // interface is busy. Both need to sync SNP.\r
270 //\r
271 TxBuf = NULL;\r
272\r
273 do {\r
274 //\r
275 // Get the recycled transmit buffer status.\r
276 //\r
277 Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf);\r
278\r
279 if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
280 Status = EFI_TIMEOUT;\r
281 break;\r
282 }\r
283\r
284 } while (TxBuf == NULL);\r
285\r
286 if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {\r
287 break;\r
288 }\r
1204fe83 289\r
f6b7393c 290 //\r
291 // Status is EFI_NOT_READY. Restart the timer event and\r
292 // call Snp->Transmit again.\r
293 //\r
294 gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);\r
295 }\r
296\r
297 gBS->SetTimer (TimeoutEvent, TimerCancel, 0);\r
298\r
299ON_EXIT:\r
300 gBS->CloseEvent (TimeoutEvent);\r
301 return Status;\r
302}\r
303\r
304/**\r
1204fe83 305 Build a syslog packet, including the Ethernet/Ip/Udp headers\r
306 and user's message.\r
f6b7393c 307\r
3b28e744 308 @param[in] Level Syslog severity level\r
1204fe83 309 @param[in] Module The module that generates the log\r
310 @param[in] File The file that contains the current log\r
311 @param[in] Line The line of code in the File that contains the current log\r
312 @param[in] Message The log message\r
313 @param[in] BufLen The lenght of the Buf\r
314 @param[out] Buf The buffer to put the packet data\r
f6b7393c 315\r
cf4a8fa4 316 @return The length of the syslog packet built, 0 represents no packet is built.\r
f6b7393c 317\r
318**/\r
319UINT32\r
320SyslogBuildPacket (\r
321 IN UINT32 Level,\r
322 IN UINT8 *Module,\r
323 IN UINT8 *File,\r
324 IN UINT32 Line,\r
325 IN UINT8 *Message,\r
326 IN UINT32 BufLen,\r
1204fe83 327 OUT CHAR8 *Buf\r
f6b7393c 328 )\r
329{\r
cf4a8fa4 330 EFI_STATUS Status;\r
f6b7393c 331 ETHER_HEAD *Ether;\r
332 IP4_HEAD *Ip4;\r
333 EFI_UDP_HEADER *Udp4;\r
334 EFI_TIME Time;\r
335 UINT32 Pri;\r
336 UINT32 Len;\r
337\r
338 //\r
1204fe83 339 // Fill in the Ethernet header. Leave alone the source MAC.\r
f6b7393c 340 // SyslogSendPacket will fill in the address for us.\r
341 //\r
342 Ether = (ETHER_HEAD *) Buf;\r
343 CopyMem (Ether->DstMac, mSyslogDstMac, NET_ETHER_ADDR_LEN);\r
344 ZeroMem (Ether->SrcMac, NET_ETHER_ADDR_LEN);\r
345\r
346 Ether->EtherType = HTONS (0x0800); // IPv4 protocol\r
347\r
348 Buf += sizeof (ETHER_HEAD);\r
349 BufLen -= sizeof (ETHER_HEAD);\r
350\r
351 //\r
352 // Fill in the IP header\r
353 //\r
354 Ip4 = (IP4_HEAD *) Buf;\r
355 Ip4->HeadLen = 5;\r
356 Ip4->Ver = 4;\r
357 Ip4->Tos = 0;\r
358 Ip4->TotalLen = 0;\r
359 Ip4->Id = (UINT16) mSyslogPacketSeq;\r
360 Ip4->Fragment = 0;\r
361 Ip4->Ttl = 16;\r
362 Ip4->Protocol = 0x11;\r
363 Ip4->Checksum = 0;\r
364 Ip4->Src = mSyslogSrcIp;\r
365 Ip4->Dst = mSyslogDstIp;\r
366\r
367 Buf += sizeof (IP4_HEAD);\r
368 BufLen -= sizeof (IP4_HEAD);\r
369\r
370 //\r
371 // Fill in the UDP header, Udp checksum is optional. Leave it zero.\r
372 //\r
373 Udp4 = (EFI_UDP_HEADER *) Buf;\r
374 Udp4->SrcPort = HTONS (514);\r
375 Udp4->DstPort = HTONS (514);\r
376 Udp4->Length = 0;\r
377 Udp4->Checksum = 0;\r
378\r
379 Buf += sizeof (EFI_UDP_HEADER);\r
380 BufLen -= sizeof (EFI_UDP_HEADER);\r
381\r
382 //\r
383 // Build the syslog message body with <PRI> Timestamp machine module Message\r
384 //\r
385 Pri = ((NET_SYSLOG_FACILITY & 31) << 3) | (Level & 7);\r
cf4a8fa4
WF
386 Status = gRT->GetTime (&Time, NULL);\r
387 if (EFI_ERROR (Status)) {\r
388 return 0;\r
389 }\r
f6b7393c 390\r
391 //\r
392 // Use %a to format the ASCII strings, %s to format UNICODE strings\r
393 //\r
394 Len = 0;\r
395 Len += (UINT32) AsciiSPrint (\r
396 Buf,\r
397 BufLen,\r
398 "<%d> %a %d %d:%d:%d ",\r
399 Pri,\r
1204fe83 400 mMonthName [Time.Month-1],\r
f6b7393c 401 Time.Day,\r
402 Time.Hour,\r
403 Time.Minute,\r
404 Time.Second\r
405 );\r
f6b7393c 406\r
407 Len += (UINT32) AsciiSPrint (\r
1204fe83 408 Buf + Len,\r
409 BufLen - Len,\r
410 "Tiano %a: %a (Line: %d File: %a)",\r
f6b7393c 411 Module,\r
412 Message,\r
413 Line,\r
414 File\r
415 );\r
c5fcec8c 416 Len ++;\r
f6b7393c 417\r
418 //\r
419 // OK, patch the IP length/checksum and UDP length fields.\r
420 //\r
421 Len += sizeof (EFI_UDP_HEADER);\r
422 Udp4->Length = HTONS ((UINT16) Len);\r
423\r
424 Len += sizeof (IP4_HEAD);\r
425 Ip4->TotalLen = HTONS ((UINT16) Len);\r
426 Ip4->Checksum = (UINT16) (~NetblockChecksum ((UINT8 *) Ip4, sizeof (IP4_HEAD)));\r
427\r
428 return Len + sizeof (ETHER_HEAD);\r
429}\r
430\r
431/**\r
1204fe83 432 Allocate a buffer, then format the message to it. This is a\r
433 help function for the NET_DEBUG_XXX macros. The PrintArg of\r
434 these macros treats the variable length print parameters as a\r
f6b7393c 435 single parameter, and pass it to the NetDebugASPrint. For\r
436 example, NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name))\r
1204fe83 437 if extracted to:\r
438\r
f6b7393c 439 NetDebugOutput (\r
1204fe83 440 NETDEBUG_LEVEL_TRACE,\r
441 "Tcp",\r
f6b7393c 442 __FILE__,\r
443 __LINE__,\r
1204fe83 444 NetDebugASPrint ("State transit to %a\n", Name)\r
445 )\r
446\r
cf4a8fa4
WF
447 If Format is NULL, then ASSERT().\r
448\r
f6b7393c 449 @param Format The ASCII format string.\r
1204fe83 450 @param ... The variable length parameter whose format is determined\r
f6b7393c 451 by the Format string.\r
452\r
453 @return The buffer containing the formatted message,\r
454 or NULL if failed to allocate memory.\r
455\r
456**/\r
457CHAR8 *\r
e798cd87 458EFIAPI\r
f6b7393c 459NetDebugASPrint (\r
460 IN CHAR8 *Format,\r
461 ...\r
462 )\r
463{\r
464 VA_LIST Marker;\r
465 CHAR8 *Buf;\r
466\r
cf4a8fa4
WF
467 ASSERT (Format != NULL);\r
468\r
f6b7393c 469 Buf = (CHAR8 *) AllocatePool (NET_DEBUG_MSG_LEN);\r
470\r
471 if (Buf == NULL) {\r
472 return NULL;\r
473 }\r
474\r
475 VA_START (Marker, Format);\r
476 AsciiVSPrint (Buf, NET_DEBUG_MSG_LEN, Format, Marker);\r
477 VA_END (Marker);\r
478\r
479 return Buf;\r
480}\r
481\r
482/**\r
483 Builds an UDP4 syslog packet and send it using SNP.\r
484\r
485 This function will locate a instance of SNP then send the message through it.\r
486 Because it isn't open the SNP BY_DRIVER, apply caution when using it.\r
487\r
3b28e744 488 @param Level The severity level of the message.\r
f6b7393c 489 @param Module The Moudle that generates the log.\r
490 @param File The file that contains the log.\r
491 @param Line The exact line that contains the log.\r
492 @param Message The user message to log.\r
493\r
494 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
cf4a8fa4
WF
495 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet.\r
496 @retval EFI_DEVICE_ERROR Device error occurs.\r
1204fe83 497 @retval EFI_SUCCESS The log is discard because that it is more verbose\r
f6b7393c 498 than the mNetDebugLevelMax. Or, it has been sent out.\r
1204fe83 499**/\r
f6b7393c 500EFI_STATUS\r
e798cd87 501EFIAPI\r
f6b7393c 502NetDebugOutput (\r
1204fe83 503 IN UINT32 Level,\r
f6b7393c 504 IN UINT8 *Module,\r
505 IN UINT8 *File,\r
506 IN UINT32 Line,\r
507 IN UINT8 *Message\r
508 )\r
509{\r
510 CHAR8 *Packet;\r
511 UINT32 Len;\r
512 EFI_STATUS Status;\r
513\r
514 //\r
515 // Check whether the message should be sent out\r
516 //\r
cf4a8fa4 517 if (Message == NULL || File == NULL || Module == NULL) {\r
f6b7393c 518 return EFI_INVALID_PARAMETER;\r
519 }\r
520\r
521 if (Level > mNetDebugLevelMax) {\r
522 Status = EFI_SUCCESS;\r
523 goto ON_EXIT;\r
524 }\r
1204fe83 525\r
f6b7393c 526 //\r
527 // Allocate a maxium of 1024 bytes, the caller should ensure\r
528 // that the message plus the ethernet/ip/udp header is shorter\r
529 // than this\r
530 //\r
531 Packet = (CHAR8 *) AllocatePool (NET_SYSLOG_PACKET_LEN);\r
532\r
533 if (Packet == NULL) {\r
534 Status = EFI_OUT_OF_RESOURCES;\r
535 goto ON_EXIT;\r
536 }\r
1204fe83 537\r
f6b7393c 538 //\r
539 // Build the message: Ethernet header + IP header + Udp Header + user data\r
540 //\r
541 Len = SyslogBuildPacket (\r
542 Level,\r
543 Module,\r
544 File,\r
545 Line,\r
546 Message,\r
547 NET_SYSLOG_PACKET_LEN,\r
548 Packet\r
549 );\r
cf4a8fa4
WF
550 if (Len == 0) {\r
551 Status = EFI_DEVICE_ERROR;\r
552 } else {\r
553 mSyslogPacketSeq++;\r
554 Status = SyslogSendPacket (Packet, Len);\r
555 }\r
f6b7393c 556\r
f6b7393c 557 FreePool (Packet);\r
558\r
559ON_EXIT:\r
560 FreePool (Message);\r
561 return Status;\r
562}\r
da1d0201 563/**\r
1204fe83 564 Return the length of the mask.\r
565\r
b9008c87 566 Return the length of the mask, the correct value is from 0 to 32.\r
567 If the mask is invalid, return the invalid length 33, which is IP4_MASK_NUM.\r
da1d0201 568 NetMask is in the host byte order.\r
569\r
3e7104c2 570 @param[in] NetMask The netmask to get the length from.\r
da1d0201 571\r
b9008c87 572 @return The length of the netmask, IP4_MASK_NUM if the mask is invalid.\r
1204fe83 573\r
da1d0201 574**/\r
575INTN\r
7b414b4e 576EFIAPI\r
da1d0201 577NetGetMaskLength (\r
578 IN IP4_ADDR NetMask\r
579 )\r
580{\r
581 INTN Index;\r
582\r
364f4efa 583 for (Index = 0; Index <= IP4_MASK_MAX; Index++) {\r
2a86ff1c 584 if (NetMask == gIp4AllMasks[Index]) {\r
da1d0201 585 break;\r
586 }\r
587 }\r
588\r
589 return Index;\r
590}\r
591\r
592\r
593\r
594/**\r
b9008c87 595 Return the class of the IP address, such as class A, B, C.\r
da1d0201 596 Addr is in host byte order.\r
1204fe83 597\r
3289dcba
FS
598 [ATTENTION]\r
599 Classful addressing (IP class A/B/C) has been deprecated according to RFC4632.\r
600 Caller of this function could only check the returned value against\r
601 IP4_ADDR_CLASSD (multicast) or IP4_ADDR_CLASSE (reserved) now.\r
602\r
b9008c87 603 The address of class A starts with 0.\r
604 If the address belong to class A, return IP4_ADDR_CLASSA.\r
1204fe83 605 The address of class B starts with 10.\r
b9008c87 606 If the address belong to class B, return IP4_ADDR_CLASSB.\r
1204fe83 607 The address of class C starts with 110.\r
b9008c87 608 If the address belong to class C, return IP4_ADDR_CLASSC.\r
1204fe83 609 The address of class D starts with 1110.\r
b9008c87 610 If the address belong to class D, return IP4_ADDR_CLASSD.\r
611 The address of class E starts with 1111.\r
612 If the address belong to class E, return IP4_ADDR_CLASSE.\r
da1d0201 613\r
1204fe83 614\r
3e7104c2 615 @param[in] Addr The address to get the class from.\r
da1d0201 616\r
3e7104c2 617 @return IP address class, such as IP4_ADDR_CLASSA.\r
da1d0201 618\r
619**/\r
620INTN\r
7b414b4e 621EFIAPI\r
da1d0201 622NetGetIpClass (\r
623 IN IP4_ADDR Addr\r
624 )\r
625{\r
626 UINT8 ByteOne;\r
627\r
628 ByteOne = (UINT8) (Addr >> 24);\r
629\r
630 if ((ByteOne & 0x80) == 0) {\r
631 return IP4_ADDR_CLASSA;\r
632\r
633 } else if ((ByteOne & 0xC0) == 0x80) {\r
634 return IP4_ADDR_CLASSB;\r
635\r
636 } else if ((ByteOne & 0xE0) == 0xC0) {\r
637 return IP4_ADDR_CLASSC;\r
638\r
639 } else if ((ByteOne & 0xF0) == 0xE0) {\r
640 return IP4_ADDR_CLASSD;\r
641\r
642 } else {\r
643 return IP4_ADDR_CLASSE;\r
644\r
645 }\r
646}\r
647\r
648\r
649/**\r
650 Check whether the IP is a valid unicast address according to\r
d1102dba 651 the netmask.\r
1204fe83 652\r
3289dcba 653 ASSERT if NetMask is zero.\r
d1102dba 654\r
29788f17
FS
655 If all bits of the host address of IP are 0 or 1, IP is also not a valid unicast address,\r
656 except when the originator is one of the endpoints of a point-to-point link with a 31-bit\r
12ae56cf
FS
657 mask (RFC3021), or a 32bit NetMask (all 0xFF) is used for special network environment (e.g.\r
658 PPP link).\r
4a76d9b9 659\r
3e7104c2 660 @param[in] Ip The IP to check against.\r
661 @param[in] NetMask The mask of the IP.\r
da1d0201 662\r
3e7104c2 663 @return TRUE if IP is a valid unicast address on the network, otherwise FALSE.\r
da1d0201 664\r
665**/\r
666BOOLEAN\r
7b414b4e 667EFIAPI\r
f6b7393c 668NetIp4IsUnicast (\r
da1d0201 669 IN IP4_ADDR Ip,\r
670 IN IP4_ADDR NetMask\r
671 )\r
672{\r
12ae56cf 673 INTN MaskLength;\r
4a76d9b9 674\r
3289dcba 675 ASSERT (NetMask != 0);\r
d1102dba 676\r
3289dcba 677 if (Ip == 0 || IP4_IS_LOCAL_BROADCAST (Ip)) {\r
da1d0201 678 return FALSE;\r
679 }\r
29788f17 680\r
12ae56cf
FS
681 MaskLength = NetGetMaskLength (NetMask);\r
682 ASSERT ((MaskLength >= 0) && (MaskLength <= IP4_MASK_NUM));\r
683 if (MaskLength < 31) {\r
29788f17
FS
684 if (((Ip &~NetMask) == ~NetMask) || ((Ip &~NetMask) == 0)) {\r
685 return FALSE;\r
686 }\r
da1d0201 687 }\r
688\r
689 return TRUE;\r
690}\r
691\r
fb115c61 692/**\r
693 Check whether the incoming IPv6 address is a valid unicast address.\r
694\r
cf4a8fa4
WF
695 ASSERT if Ip6 is NULL.\r
696\r
fb115c61 697 If the address is a multicast address has binary 0xFF at the start, it is not\r
698 a valid unicast address. If the address is unspecified ::, it is not a valid\r
699 unicast address to be assigned to any node. If the address is loopback address\r
700 ::1, it is also not a valid unicast address to be assigned to any physical\r
1204fe83 701 interface.\r
fb115c61 702\r
703 @param[in] Ip6 The IPv6 address to check against.\r
704\r
705 @return TRUE if Ip6 is a valid unicast address on the network, otherwise FALSE.\r
706\r
1204fe83 707**/\r
fb115c61 708BOOLEAN\r
e798cd87 709EFIAPI\r
f6b7393c 710NetIp6IsValidUnicast (\r
fb115c61 711 IN EFI_IPv6_ADDRESS *Ip6\r
1204fe83 712 )\r
fb115c61 713{\r
b45b45b2 714 UINT8 Byte;\r
715 UINT8 Index;\r
1204fe83 716\r
cf4a8fa4
WF
717 ASSERT (Ip6 != NULL);\r
718\r
fb115c61 719 if (Ip6->Addr[0] == 0xFF) {\r
720 return FALSE;\r
721 }\r
722\r
b45b45b2 723 for (Index = 0; Index < 15; Index++) {\r
724 if (Ip6->Addr[Index] != 0) {\r
fb115c61 725 return TRUE;\r
726 }\r
727 }\r
728\r
b45b45b2 729 Byte = Ip6->Addr[Index];\r
fb115c61 730\r
b45b45b2 731 if (Byte == 0x0 || Byte == 0x1) {\r
fb115c61 732 return FALSE;\r
733 }\r
734\r
1204fe83 735 return TRUE;\r
fb115c61 736}\r
da1d0201 737\r
f6b7393c 738/**\r
739 Check whether the incoming Ipv6 address is the unspecified address or not.\r
740\r
cf4a8fa4
WF
741 ASSERT if Ip6 is NULL.\r
742\r
f6b7393c 743 @param[in] Ip6 - Ip6 address, in network order.\r
744\r
745 @retval TRUE - Yes, unspecified\r
746 @retval FALSE - No\r
1204fe83 747\r
f6b7393c 748**/\r
749BOOLEAN\r
e798cd87 750EFIAPI\r
f6b7393c 751NetIp6IsUnspecifiedAddr (\r
752 IN EFI_IPv6_ADDRESS *Ip6\r
753 )\r
754{\r
755 UINT8 Index;\r
756\r
cf4a8fa4
WF
757 ASSERT (Ip6 != NULL);\r
758\r
f6b7393c 759 for (Index = 0; Index < 16; Index++) {\r
760 if (Ip6->Addr[Index] != 0) {\r
761 return FALSE;\r
762 }\r
763 }\r
764\r
765 return TRUE;\r
766}\r
767\r
768/**\r
769 Check whether the incoming Ipv6 address is a link-local address.\r
770\r
cf4a8fa4
WF
771 ASSERT if Ip6 is NULL.\r
772\r
f6b7393c 773 @param[in] Ip6 - Ip6 address, in network order.\r
774\r
775 @retval TRUE - Yes, link-local address\r
776 @retval FALSE - No\r
1204fe83 777\r
f6b7393c 778**/\r
779BOOLEAN\r
e798cd87 780EFIAPI\r
f6b7393c 781NetIp6IsLinkLocalAddr (\r
782 IN EFI_IPv6_ADDRESS *Ip6\r
783 )\r
784{\r
785 UINT8 Index;\r
1204fe83 786\r
f6b7393c 787 ASSERT (Ip6 != NULL);\r
788\r
789 if (Ip6->Addr[0] != 0xFE) {\r
790 return FALSE;\r
791 }\r
1204fe83 792\r
f6b7393c 793 if (Ip6->Addr[1] != 0x80) {\r
794 return FALSE;\r
795 }\r
796\r
797 for (Index = 2; Index < 8; Index++) {\r
798 if (Ip6->Addr[Index] != 0) {\r
799 return FALSE;\r
800 }\r
801 }\r
802\r
803 return TRUE;\r
804}\r
805\r
806/**\r
807 Check whether the Ipv6 address1 and address2 are on the connected network.\r
808\r
cf4a8fa4 809 ASSERT if Ip1 or Ip2 is NULL.\r
e0e26f9c 810 ASSERT if PrefixLength exceeds or equals to IP6_PREFIX_MAX.\r
cf4a8fa4 811\r
f6b7393c 812 @param[in] Ip1 - Ip6 address1, in network order.\r
813 @param[in] Ip2 - Ip6 address2, in network order.\r
814 @param[in] PrefixLength - The prefix length of the checking net.\r
815\r
816 @retval TRUE - Yes, connected.\r
817 @retval FALSE - No.\r
1204fe83 818\r
f6b7393c 819**/\r
820BOOLEAN\r
e798cd87 821EFIAPI\r
f6b7393c 822NetIp6IsNetEqual (\r
823 EFI_IPv6_ADDRESS *Ip1,\r
824 EFI_IPv6_ADDRESS *Ip2,\r
825 UINT8 PrefixLength\r
826 )\r
827{\r
828 UINT8 Byte;\r
829 UINT8 Bit;\r
830 UINT8 Mask;\r
831\r
e0e26f9c 832 ASSERT ((Ip1 != NULL) && (Ip2 != NULL) && (PrefixLength < IP6_PREFIX_MAX));\r
1204fe83 833\r
f6b7393c 834 if (PrefixLength == 0) {\r
835 return TRUE;\r
836 }\r
837\r
838 Byte = (UINT8) (PrefixLength / 8);\r
839 Bit = (UINT8) (PrefixLength % 8);\r
1204fe83 840\r
f6b7393c 841 if (CompareMem (Ip1, Ip2, Byte) != 0) {\r
842 return FALSE;\r
843 }\r
844\r
845 if (Bit > 0) {\r
846 Mask = (UINT8) (0xFF << (8 - Bit));\r
847\r
e0e26f9c
WF
848 ASSERT (Byte < 16);\r
849 if (Byte >= 16) {\r
850 return FALSE;\r
851 }\r
f6b7393c 852 if ((Ip1->Addr[Byte] & Mask) != (Ip2->Addr[Byte] & Mask)) {\r
853 return FALSE;\r
1204fe83 854 }\r
f6b7393c 855 }\r
1204fe83 856\r
f6b7393c 857 return TRUE;\r
858}\r
859\r
860\r
b45b45b2 861/**\r
862 Switches the endianess of an IPv6 address\r
863\r
cf4a8fa4
WF
864 ASSERT if Ip6 is NULL.\r
865\r
b45b45b2 866 This function swaps the bytes in a 128-bit IPv6 address to switch the value\r
867 from little endian to big endian or vice versa. The byte swapped value is\r
868 returned.\r
869\r
870 @param Ip6 Points to an IPv6 address\r
871\r
872 @return The byte swapped IPv6 address.\r
873\r
874**/\r
875EFI_IPv6_ADDRESS *\r
e798cd87 876EFIAPI\r
b45b45b2 877Ip6Swap128 (\r
878 EFI_IPv6_ADDRESS *Ip6\r
879 )\r
880{\r
881 UINT64 High;\r
882 UINT64 Low;\r
883\r
cf4a8fa4
WF
884 ASSERT (Ip6 != NULL);\r
885\r
b45b45b2 886 CopyMem (&High, Ip6, sizeof (UINT64));\r
887 CopyMem (&Low, &Ip6->Addr[8], sizeof (UINT64));\r
888\r
889 High = SwapBytes64 (High);\r
890 Low = SwapBytes64 (Low);\r
891\r
892 CopyMem (Ip6, &Low, sizeof (UINT64));\r
893 CopyMem (&Ip6->Addr[8], &High, sizeof (UINT64));\r
894\r
895 return Ip6;\r
896}\r
897\r
da1d0201 898/**\r
2bd25290 899 Initialize a random seed using current time and monotonic count.\r
1204fe83 900\r
d1102dba 901 Get current time and monotonic count first. Then initialize a random seed\r
2bd25290
FS
902 based on some basic mathematics operation on the hour, day, minute, second,\r
903 nanosecond and year of the current time and the monotonic count value.\r
1204fe83 904\r
da1d0201 905 @return The random seed initialized with current time.\r
906\r
907**/\r
908UINT32\r
7b414b4e 909EFIAPI\r
da1d0201 910NetRandomInitSeed (\r
911 VOID\r
912 )\r
913{\r
914 EFI_TIME Time;\r
915 UINT32 Seed;\r
2bd25290 916 UINT64 MonotonicCount;\r
da1d0201 917\r
918 gRT->GetTime (&Time, NULL);\r
bd42d976 919 Seed = (Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second);\r
da1d0201 920 Seed ^= Time.Nanosecond;\r
921 Seed ^= Time.Year << 7;\r
922\r
2bd25290
FS
923 gBS->GetNextMonotonicCount (&MonotonicCount);\r
924 Seed += (UINT32) MonotonicCount;\r
925\r
da1d0201 926 return Seed;\r
927}\r
928\r
929\r
930/**\r
b9008c87 931 Extract a UINT32 from a byte stream.\r
1204fe83 932\r
cf4a8fa4
WF
933 ASSERT if Buf is NULL.\r
934\r
1204fe83 935 Copy a UINT32 from a byte stream, then converts it from Network\r
b9008c87 936 byte order to host byte order. Use this function to avoid alignment error.\r
da1d0201 937\r
3e7104c2 938 @param[in] Buf The buffer to extract the UINT32.\r
da1d0201 939\r
940 @return The UINT32 extracted.\r
941\r
942**/\r
943UINT32\r
7b414b4e 944EFIAPI\r
da1d0201 945NetGetUint32 (\r
946 IN UINT8 *Buf\r
947 )\r
948{\r
949 UINT32 Value;\r
950\r
cf4a8fa4
WF
951 ASSERT (Buf != NULL);\r
952\r
e48e37fc 953 CopyMem (&Value, Buf, sizeof (UINT32));\r
da1d0201 954 return NTOHL (Value);\r
955}\r
956\r
957\r
958/**\r
1204fe83 959 Put a UINT32 to the byte stream in network byte order.\r
960\r
cf4a8fa4
WF
961 ASSERT if Buf is NULL.\r
962\r
1204fe83 963 Converts a UINT32 from host byte order to network byte order. Then copy it to the\r
b9008c87 964 byte stream.\r
da1d0201 965\r
3e7104c2 966 @param[in, out] Buf The buffer to put the UINT32.\r
3b1464d5 967 @param[in] Data The data to be converted and put into the byte stream.\r
1204fe83 968\r
da1d0201 969**/\r
970VOID\r
7b414b4e 971EFIAPI\r
da1d0201 972NetPutUint32 (\r
3e7104c2 973 IN OUT UINT8 *Buf,\r
974 IN UINT32 Data\r
da1d0201 975 )\r
976{\r
cf4a8fa4
WF
977 ASSERT (Buf != NULL);\r
978\r
da1d0201 979 Data = HTONL (Data);\r
e48e37fc 980 CopyMem (Buf, &Data, sizeof (UINT32));\r
da1d0201 981}\r
982\r
983\r
984/**\r
b9008c87 985 Remove the first node entry on the list, and return the removed node entry.\r
1204fe83 986\r
b9008c87 987 Removes the first node Entry from a doubly linked list. It is up to the caller of\r
988 this function to release the memory used by the first node if that is required. On\r
1204fe83 989 exit, the removed node is returned.\r
b9008c87 990\r
991 If Head is NULL, then ASSERT().\r
992 If Head was not initialized, then ASSERT().\r
993 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the\r
994 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,\r
1204fe83 995 then ASSERT().\r
da1d0201 996\r
3e7104c2 997 @param[in, out] Head The list header.\r
da1d0201 998\r
b9008c87 999 @return The first node entry that is removed from the list, NULL if the list is empty.\r
da1d0201 1000\r
1001**/\r
e48e37fc 1002LIST_ENTRY *\r
7b414b4e 1003EFIAPI\r
da1d0201 1004NetListRemoveHead (\r
3e7104c2 1005 IN OUT LIST_ENTRY *Head\r
da1d0201 1006 )\r
1007{\r
e48e37fc 1008 LIST_ENTRY *First;\r
da1d0201 1009\r
1010 ASSERT (Head != NULL);\r
1011\r
e48e37fc 1012 if (IsListEmpty (Head)) {\r
da1d0201 1013 return NULL;\r
1014 }\r
1015\r
1016 First = Head->ForwardLink;\r
1017 Head->ForwardLink = First->ForwardLink;\r
1018 First->ForwardLink->BackLink = Head;\r
1019\r
1020 DEBUG_CODE (\r
e48e37fc 1021 First->ForwardLink = (LIST_ENTRY *) NULL;\r
1022 First->BackLink = (LIST_ENTRY *) NULL;\r
da1d0201 1023 );\r
1024\r
1025 return First;\r
1026}\r
1027\r
1028\r
1029/**\r
b9008c87 1030 Remove the last node entry on the list and and return the removed node entry.\r
1031\r
1032 Removes the last node entry from a doubly linked list. It is up to the caller of\r
1033 this function to release the memory used by the first node if that is required. On\r
1204fe83 1034 exit, the removed node is returned.\r
da1d0201 1035\r
b9008c87 1036 If Head is NULL, then ASSERT().\r
1037 If Head was not initialized, then ASSERT().\r
1038 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the\r
1039 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,\r
1204fe83 1040 then ASSERT().\r
1041\r
3e7104c2 1042 @param[in, out] Head The list head.\r
da1d0201 1043\r
b9008c87 1044 @return The last node entry that is removed from the list, NULL if the list is empty.\r
da1d0201 1045\r
1046**/\r
e48e37fc 1047LIST_ENTRY *\r
7b414b4e 1048EFIAPI\r
da1d0201 1049NetListRemoveTail (\r
3e7104c2 1050 IN OUT LIST_ENTRY *Head\r
da1d0201 1051 )\r
1052{\r
e48e37fc 1053 LIST_ENTRY *Last;\r
da1d0201 1054\r
1055 ASSERT (Head != NULL);\r
1056\r
e48e37fc 1057 if (IsListEmpty (Head)) {\r
da1d0201 1058 return NULL;\r
1059 }\r
1060\r
1061 Last = Head->BackLink;\r
1062 Head->BackLink = Last->BackLink;\r
1063 Last->BackLink->ForwardLink = Head;\r
1064\r
1065 DEBUG_CODE (\r
e48e37fc 1066 Last->ForwardLink = (LIST_ENTRY *) NULL;\r
1067 Last->BackLink = (LIST_ENTRY *) NULL;\r
da1d0201 1068 );\r
1069\r
1070 return Last;\r
1071}\r
1072\r
1073\r
1074/**\r
b9008c87 1075 Insert a new node entry after a designated node entry of a doubly linked list.\r
1204fe83 1076\r
cf4a8fa4
WF
1077 ASSERT if PrevEntry or NewEntry is NULL.\r
1078\r
b9008c87 1079 Inserts a new node entry donated by NewEntry after the node entry donated by PrevEntry\r
1080 of the doubly linked list.\r
1204fe83 1081\r
3e7104c2 1082 @param[in, out] PrevEntry The previous entry to insert after.\r
1083 @param[in, out] NewEntry The new entry to insert.\r
da1d0201 1084\r
1085**/\r
1086VOID\r
7b414b4e 1087EFIAPI\r
da1d0201 1088NetListInsertAfter (\r
3e7104c2 1089 IN OUT LIST_ENTRY *PrevEntry,\r
1090 IN OUT LIST_ENTRY *NewEntry\r
da1d0201 1091 )\r
1092{\r
cf4a8fa4
WF
1093 ASSERT (PrevEntry != NULL && NewEntry != NULL);\r
1094\r
da1d0201 1095 NewEntry->BackLink = PrevEntry;\r
1096 NewEntry->ForwardLink = PrevEntry->ForwardLink;\r
1097 PrevEntry->ForwardLink->BackLink = NewEntry;\r
1098 PrevEntry->ForwardLink = NewEntry;\r
1099}\r
1100\r
1101\r
1102/**\r
b9008c87 1103 Insert a new node entry before a designated node entry of a doubly linked list.\r
1204fe83 1104\r
cf4a8fa4
WF
1105 ASSERT if PostEntry or NewEntry is NULL.\r
1106\r
b9008c87 1107 Inserts a new node entry donated by NewEntry after the node entry donated by PostEntry\r
1108 of the doubly linked list.\r
1204fe83 1109\r
3e7104c2 1110 @param[in, out] PostEntry The entry to insert before.\r
1111 @param[in, out] NewEntry The new entry to insert.\r
da1d0201 1112\r
1113**/\r
1114VOID\r
7b414b4e 1115EFIAPI\r
da1d0201 1116NetListInsertBefore (\r
3e7104c2 1117 IN OUT LIST_ENTRY *PostEntry,\r
1118 IN OUT LIST_ENTRY *NewEntry\r
da1d0201 1119 )\r
1120{\r
cf4a8fa4
WF
1121 ASSERT (PostEntry != NULL && NewEntry != NULL);\r
1122\r
da1d0201 1123 NewEntry->ForwardLink = PostEntry;\r
1124 NewEntry->BackLink = PostEntry->BackLink;\r
1125 PostEntry->BackLink->ForwardLink = NewEntry;\r
1126 PostEntry->BackLink = NewEntry;\r
1127}\r
1128\r
216f7970 1129/**\r
1130 Safe destroy nodes in a linked list, and return the length of the list after all possible operations finished.\r
1131\r
1132 Destroy network child instance list by list traversals is not safe due to graph dependencies between nodes.\r
1133 This function performs a safe traversal to destroy these nodes by checking to see if the node being destroyed\r
1134 has been removed from the list or not.\r
1135 If it has been removed, then restart the traversal from the head.\r
1136 If it hasn't been removed, then continue with the next node directly.\r
1137 This function will end the iterate and return the CallBack's last return value if error happens,\r
d1102dba 1138 or retrun EFI_SUCCESS if 2 complete passes are made with no changes in the number of children in the list.\r
216f7970 1139\r
1140 @param[in] List The head of the list.\r
1141 @param[in] CallBack Pointer to the callback function to destroy one node in the list.\r
1142 @param[in] Context Pointer to the callback function's context: corresponds to the\r
1143 parameter Context in NET_DESTROY_LINK_LIST_CALLBACK.\r
1144 @param[out] ListLength The length of the link list if the function returns successfully.\r
1145\r
1146 @retval EFI_SUCCESS Two complete passes are made with no changes in the number of children.\r
1147 @retval EFI_INVALID_PARAMETER The input parameter is invalid.\r
1148 @retval Others Return the CallBack's last return value.\r
1149\r
1150**/\r
1151EFI_STATUS\r
1152EFIAPI\r
1153NetDestroyLinkList (\r
1154 IN LIST_ENTRY *List,\r
1155 IN NET_DESTROY_LINK_LIST_CALLBACK CallBack,\r
1156 IN VOID *Context, OPTIONAL\r
1157 OUT UINTN *ListLength OPTIONAL\r
1f7eb561 1158 )\r
216f7970 1159{\r
1160 UINTN PreviousLength;\r
1161 LIST_ENTRY *Entry;\r
1162 LIST_ENTRY *Ptr;\r
1163 UINTN Length;\r
1164 EFI_STATUS Status;\r
1165\r
1166 if (List == NULL || CallBack == NULL) {\r
1167 return EFI_INVALID_PARAMETER;\r
1168 }\r
1169\r
1170 Length = 0;\r
1171 do {\r
1172 PreviousLength = Length;\r
1173 Entry = GetFirstNode (List);\r
1174 while (!IsNull (List, Entry)) {\r
1175 Status = CallBack (Entry, Context);\r
1176 if (EFI_ERROR (Status)) {\r
1177 return Status;\r
1178 }\r
1179 //\r
1180 // Walk through the list to see whether the Entry has been removed or not.\r
1181 // If the Entry still exists, just try to destroy the next one.\r
1182 // If not, go back to the start point to iterate the list again.\r
1183 //\r
1184 for (Ptr = List->ForwardLink; Ptr != List; Ptr = Ptr->ForwardLink) {\r
1185 if (Ptr == Entry) {\r
1186 break;\r
1187 }\r
1188 }\r
1189 if (Ptr == Entry) {\r
1190 Entry = GetNextNode (List, Entry);\r
1191 } else {\r
1192 Entry = GetFirstNode (List);\r
1193 }\r
1194 }\r
1195 for (Length = 0, Ptr = List->ForwardLink; Ptr != List; Length++, Ptr = Ptr->ForwardLink);\r
1196 } while (Length != PreviousLength);\r
1197\r
1198 if (ListLength != NULL) {\r
1199 *ListLength = Length;\r
1200 }\r
1201 return EFI_SUCCESS;\r
1202}\r
1203\r
1204/**\r
1205 This function checks the input Handle to see if it's one of these handles in ChildHandleBuffer.\r
1206\r
1207 @param[in] Handle Handle to be checked.\r
1208 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer.\r
1209 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
1210 if NumberOfChildren is 0.\r
1211\r
3b28e744 1212 @retval TRUE Found the input Handle in ChildHandleBuffer.\r
216f7970 1213 @retval FALSE Can't find the input Handle in ChildHandleBuffer.\r
1214\r
1215**/\r
1216BOOLEAN\r
f8c075d1 1217EFIAPI\r
216f7970 1218NetIsInHandleBuffer (\r
1219 IN EFI_HANDLE Handle,\r
1220 IN UINTN NumberOfChildren,\r
1221 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL\r
1f7eb561 1222 )\r
216f7970 1223{\r
1224 UINTN Index;\r
d1102dba 1225\r
216f7970 1226 if (NumberOfChildren == 0 || ChildHandleBuffer == NULL) {\r
1227 return FALSE;\r
1228 }\r
1229\r
1230 for (Index = 0; Index < NumberOfChildren; Index++) {\r
1231 if (Handle == ChildHandleBuffer[Index]) {\r
1232 return TRUE;\r
1233 }\r
1234 }\r
1235\r
1236 return FALSE;\r
1237}\r
1238\r
da1d0201 1239\r
1240/**\r
1241 Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.\r
1204fe83 1242\r
1243 Initialize the forward and backward links of two head nodes donated by Map->Used\r
b9008c87 1244 and Map->Recycled of two doubly linked lists.\r
1245 Initializes the count of the <Key, Value> pairs in the netmap to zero.\r
1204fe83 1246\r
b9008c87 1247 If Map is NULL, then ASSERT().\r
8f5e6151 1248 If the address of Map->Used is NULL, then ASSERT().\r
b9008c87 1249 If the address of Map->Recycled is NULl, then ASSERT().\r
1204fe83 1250\r
3e7104c2 1251 @param[in, out] Map The netmap to initialize.\r
da1d0201 1252\r
1253**/\r
1254VOID\r
7b414b4e 1255EFIAPI\r
da1d0201 1256NetMapInit (\r
3e7104c2 1257 IN OUT NET_MAP *Map\r
da1d0201 1258 )\r
1259{\r
1260 ASSERT (Map != NULL);\r
1261\r
e48e37fc 1262 InitializeListHead (&Map->Used);\r
1263 InitializeListHead (&Map->Recycled);\r
da1d0201 1264 Map->Count = 0;\r
1265}\r
1266\r
1267\r
1268/**\r
1269 To clean up the netmap, that is, release allocated memories.\r
1204fe83 1270\r
b9008c87 1271 Removes all nodes of the Used doubly linked list and free memory of all related netmap items.\r
1272 Removes all nodes of the Recycled doubly linked list and free memory of all related netmap items.\r
1273 The number of the <Key, Value> pairs in the netmap is set to be zero.\r
1204fe83 1274\r
b9008c87 1275 If Map is NULL, then ASSERT().\r
1204fe83 1276\r
3e7104c2 1277 @param[in, out] Map The netmap to clean up.\r
da1d0201 1278\r
1279**/\r
1280VOID\r
7b414b4e 1281EFIAPI\r
da1d0201 1282NetMapClean (\r
3e7104c2 1283 IN OUT NET_MAP *Map\r
da1d0201 1284 )\r
1285{\r
1286 NET_MAP_ITEM *Item;\r
e48e37fc 1287 LIST_ENTRY *Entry;\r
1288 LIST_ENTRY *Next;\r
da1d0201 1289\r
1290 ASSERT (Map != NULL);\r
1291\r
1292 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Used) {\r
1293 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
1294\r
e48e37fc 1295 RemoveEntryList (&Item->Link);\r
da1d0201 1296 Map->Count--;\r
1297\r
e48e37fc 1298 gBS->FreePool (Item);\r
da1d0201 1299 }\r
1300\r
e48e37fc 1301 ASSERT ((Map->Count == 0) && IsListEmpty (&Map->Used));\r
da1d0201 1302\r
1303 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Recycled) {\r
1304 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
1305\r
e48e37fc 1306 RemoveEntryList (&Item->Link);\r
1307 gBS->FreePool (Item);\r
da1d0201 1308 }\r
1309\r
e48e37fc 1310 ASSERT (IsListEmpty (&Map->Recycled));\r
da1d0201 1311}\r
1312\r
1313\r
1314/**\r
b9008c87 1315 Test whether the netmap is empty and return true if it is.\r
1204fe83 1316\r
b9008c87 1317 If the number of the <Key, Value> pairs in the netmap is zero, return TRUE.\r
1204fe83 1318\r
b9008c87 1319 If Map is NULL, then ASSERT().\r
1204fe83 1320\r
3e7104c2 1321 @param[in] Map The net map to test.\r
da1d0201 1322\r
1323 @return TRUE if the netmap is empty, otherwise FALSE.\r
1324\r
1325**/\r
1326BOOLEAN\r
7b414b4e 1327EFIAPI\r
da1d0201 1328NetMapIsEmpty (\r
1329 IN NET_MAP *Map\r
1330 )\r
1331{\r
1332 ASSERT (Map != NULL);\r
1333 return (BOOLEAN) (Map->Count == 0);\r
1334}\r
1335\r
1336\r
1337/**\r
1338 Return the number of the <Key, Value> pairs in the netmap.\r
1339\r
cf4a8fa4
WF
1340 If Map is NULL, then ASSERT().\r
1341\r
3e7104c2 1342 @param[in] Map The netmap to get the entry number.\r
da1d0201 1343\r
1344 @return The entry number in the netmap.\r
1345\r
1346**/\r
1347UINTN\r
7b414b4e 1348EFIAPI\r
da1d0201 1349NetMapGetCount (\r
1350 IN NET_MAP *Map\r
1351 )\r
1352{\r
cf4a8fa4 1353 ASSERT (Map != NULL);\r
da1d0201 1354 return Map->Count;\r
1355}\r
1356\r
1357\r
1358/**\r
1204fe83 1359 Return one allocated item.\r
1360\r
1361 If the Recycled doubly linked list of the netmap is empty, it will try to allocate\r
b9008c87 1362 a batch of items if there are enough resources and add corresponding nodes to the begining\r
1363 of the Recycled doubly linked list of the netmap. Otherwise, it will directly remove\r
1364 the fist node entry of the Recycled doubly linked list and return the corresponding item.\r
1204fe83 1365\r
b9008c87 1366 If Map is NULL, then ASSERT().\r
1204fe83 1367\r
3e7104c2 1368 @param[in, out] Map The netmap to allocate item for.\r
da1d0201 1369\r
3e7104c2 1370 @return The allocated item. If NULL, the\r
1371 allocation failed due to resource limit.\r
da1d0201 1372\r
1373**/\r
da1d0201 1374NET_MAP_ITEM *\r
1375NetMapAllocItem (\r
3e7104c2 1376 IN OUT NET_MAP *Map\r
da1d0201 1377 )\r
1378{\r
1379 NET_MAP_ITEM *Item;\r
e48e37fc 1380 LIST_ENTRY *Head;\r
da1d0201 1381 UINTN Index;\r
1382\r
1383 ASSERT (Map != NULL);\r
1384\r
1385 Head = &Map->Recycled;\r
1386\r
e48e37fc 1387 if (IsListEmpty (Head)) {\r
da1d0201 1388 for (Index = 0; Index < NET_MAP_INCREAMENT; Index++) {\r
e48e37fc 1389 Item = AllocatePool (sizeof (NET_MAP_ITEM));\r
da1d0201 1390\r
1391 if (Item == NULL) {\r
1392 if (Index == 0) {\r
1393 return NULL;\r
1394 }\r
1395\r
1396 break;\r
1397 }\r
1398\r
e48e37fc 1399 InsertHeadList (Head, &Item->Link);\r
da1d0201 1400 }\r
1401 }\r
1402\r
1403 Item = NET_LIST_HEAD (Head, NET_MAP_ITEM, Link);\r
1404 NetListRemoveHead (Head);\r
1405\r
1406 return Item;\r
1407}\r
1408\r
1409\r
1410/**\r
1411 Allocate an item to save the <Key, Value> pair to the head of the netmap.\r
1204fe83 1412\r
b9008c87 1413 Allocate an item to save the <Key, Value> pair and add corresponding node entry\r
1204fe83 1414 to the beginning of the Used doubly linked list. The number of the <Key, Value>\r
b9008c87 1415 pairs in the netmap increase by 1.\r
da1d0201 1416\r
b9008c87 1417 If Map is NULL, then ASSERT().\r
cf4a8fa4 1418 If Key is NULL, then ASSERT().\r
1204fe83 1419\r
3e7104c2 1420 @param[in, out] Map The netmap to insert into.\r
1421 @param[in] Key The user's key.\r
1422 @param[in] Value The user's value for the key.\r
da1d0201 1423\r
3e7104c2 1424 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.\r
1425 @retval EFI_SUCCESS The item is inserted to the head.\r
da1d0201 1426\r
1427**/\r
1428EFI_STATUS\r
7b414b4e 1429EFIAPI\r
da1d0201 1430NetMapInsertHead (\r
3e7104c2 1431 IN OUT NET_MAP *Map,\r
da1d0201 1432 IN VOID *Key,\r
1433 IN VOID *Value OPTIONAL\r
1434 )\r
1435{\r
1436 NET_MAP_ITEM *Item;\r
1437\r
cf4a8fa4 1438 ASSERT (Map != NULL && Key != NULL);\r
da1d0201 1439\r
1440 Item = NetMapAllocItem (Map);\r
1441\r
1442 if (Item == NULL) {\r
1443 return EFI_OUT_OF_RESOURCES;\r
1444 }\r
1445\r
1446 Item->Key = Key;\r
1447 Item->Value = Value;\r
e48e37fc 1448 InsertHeadList (&Map->Used, &Item->Link);\r
da1d0201 1449\r
1450 Map->Count++;\r
1451 return EFI_SUCCESS;\r
1452}\r
1453\r
1454\r
1455/**\r
1456 Allocate an item to save the <Key, Value> pair to the tail of the netmap.\r
1457\r
b9008c87 1458 Allocate an item to save the <Key, Value> pair and add corresponding node entry\r
1204fe83 1459 to the tail of the Used doubly linked list. The number of the <Key, Value>\r
b9008c87 1460 pairs in the netmap increase by 1.\r
1461\r
1462 If Map is NULL, then ASSERT().\r
cf4a8fa4 1463 If Key is NULL, then ASSERT().\r
1204fe83 1464\r
3e7104c2 1465 @param[in, out] Map The netmap to insert into.\r
1466 @param[in] Key The user's key.\r
1467 @param[in] Value The user's value for the key.\r
da1d0201 1468\r
3e7104c2 1469 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.\r
1470 @retval EFI_SUCCESS The item is inserted to the tail.\r
da1d0201 1471\r
1472**/\r
1473EFI_STATUS\r
7b414b4e 1474EFIAPI\r
da1d0201 1475NetMapInsertTail (\r
3e7104c2 1476 IN OUT NET_MAP *Map,\r
da1d0201 1477 IN VOID *Key,\r
1478 IN VOID *Value OPTIONAL\r
1479 )\r
1480{\r
1481 NET_MAP_ITEM *Item;\r
1482\r
cf4a8fa4 1483 ASSERT (Map != NULL && Key != NULL);\r
da1d0201 1484\r
1485 Item = NetMapAllocItem (Map);\r
1486\r
1487 if (Item == NULL) {\r
1488 return EFI_OUT_OF_RESOURCES;\r
1489 }\r
1490\r
1491 Item->Key = Key;\r
1492 Item->Value = Value;\r
e48e37fc 1493 InsertTailList (&Map->Used, &Item->Link);\r
da1d0201 1494\r
1495 Map->Count++;\r
1496\r
1497 return EFI_SUCCESS;\r
1498}\r
1499\r
1500\r
1501/**\r
b9008c87 1502 Check whether the item is in the Map and return TRUE if it is.\r
da1d0201 1503\r
cf4a8fa4
WF
1504 If Map is NULL, then ASSERT().\r
1505 If Item is NULL, then ASSERT().\r
1506\r
3e7104c2 1507 @param[in] Map The netmap to search within.\r
1508 @param[in] Item The item to search.\r
da1d0201 1509\r
1510 @return TRUE if the item is in the netmap, otherwise FALSE.\r
1511\r
1512**/\r
da1d0201 1513BOOLEAN\r
1514NetItemInMap (\r
1515 IN NET_MAP *Map,\r
1516 IN NET_MAP_ITEM *Item\r
1517 )\r
1518{\r
e48e37fc 1519 LIST_ENTRY *ListEntry;\r
da1d0201 1520\r
cf4a8fa4
WF
1521 ASSERT (Map != NULL && Item != NULL);\r
1522\r
da1d0201 1523 NET_LIST_FOR_EACH (ListEntry, &Map->Used) {\r
1524 if (ListEntry == &Item->Link) {\r
1525 return TRUE;\r
1526 }\r
1527 }\r
1528\r
1529 return FALSE;\r
1530}\r
1531\r
1532\r
1533/**\r
b9008c87 1534 Find the key in the netmap and returns the point to the item contains the Key.\r
1204fe83 1535\r
1536 Iterate the Used doubly linked list of the netmap to get every item. Compare the key of every\r
b9008c87 1537 item with the key to search. It returns the point to the item contains the Key if found.\r
da1d0201 1538\r
b9008c87 1539 If Map is NULL, then ASSERT().\r
cf4a8fa4 1540 If Key is NULL, then ASSERT().\r
1204fe83 1541\r
3e7104c2 1542 @param[in] Map The netmap to search within.\r
1543 @param[in] Key The key to search.\r
da1d0201 1544\r
1545 @return The point to the item contains the Key, or NULL if Key isn't in the map.\r
1546\r
1547**/\r
1548NET_MAP_ITEM *\r
7b414b4e 1549EFIAPI\r
da1d0201 1550NetMapFindKey (\r
1551 IN NET_MAP *Map,\r
1552 IN VOID *Key\r
1553 )\r
1554{\r
e48e37fc 1555 LIST_ENTRY *Entry;\r
da1d0201 1556 NET_MAP_ITEM *Item;\r
1557\r
cf4a8fa4 1558 ASSERT (Map != NULL && Key != NULL);\r
da1d0201 1559\r
1560 NET_LIST_FOR_EACH (Entry, &Map->Used) {\r
1561 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
1562\r
1563 if (Item->Key == Key) {\r
1564 return Item;\r
1565 }\r
1566 }\r
1567\r
1568 return NULL;\r
1569}\r
1570\r
1571\r
1572/**\r
b9008c87 1573 Remove the node entry of the item from the netmap and return the key of the removed item.\r
1204fe83 1574\r
1575 Remove the node entry of the item from the Used doubly linked list of the netmap.\r
1576 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node\r
b9008c87 1577 entry of the item to the Recycled doubly linked list of the netmap. If Value is not NULL,\r
1578 Value will point to the value of the item. It returns the key of the removed item.\r
1204fe83 1579\r
b9008c87 1580 If Map is NULL, then ASSERT().\r
1581 If Item is NULL, then ASSERT().\r
1582 if item in not in the netmap, then ASSERT().\r
1204fe83 1583\r
3e7104c2 1584 @param[in, out] Map The netmap to remove the item from.\r
1585 @param[in, out] Item The item to remove.\r
1586 @param[out] Value The variable to receive the value if not NULL.\r
da1d0201 1587\r
3e7104c2 1588 @return The key of the removed item.\r
da1d0201 1589\r
1590**/\r
1591VOID *\r
7b414b4e 1592EFIAPI\r
da1d0201 1593NetMapRemoveItem (\r
3e7104c2 1594 IN OUT NET_MAP *Map,\r
1595 IN OUT NET_MAP_ITEM *Item,\r
1596 OUT VOID **Value OPTIONAL\r
da1d0201 1597 )\r
1598{\r
1599 ASSERT ((Map != NULL) && (Item != NULL));\r
1600 ASSERT (NetItemInMap (Map, Item));\r
1601\r
e48e37fc 1602 RemoveEntryList (&Item->Link);\r
da1d0201 1603 Map->Count--;\r
e48e37fc 1604 InsertHeadList (&Map->Recycled, &Item->Link);\r
da1d0201 1605\r
1606 if (Value != NULL) {\r
1607 *Value = Item->Value;\r
1608 }\r
1609\r
1610 return Item->Key;\r
1611}\r
1612\r
1613\r
1614/**\r
b9008c87 1615 Remove the first node entry on the netmap and return the key of the removed item.\r
da1d0201 1616\r
1204fe83 1617 Remove the first node entry from the Used doubly linked list of the netmap.\r
1618 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node\r
b9008c87 1619 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,\r
1620 parameter Value will point to the value of the item. It returns the key of the removed item.\r
1204fe83 1621\r
b9008c87 1622 If Map is NULL, then ASSERT().\r
1623 If the Used doubly linked list is empty, then ASSERT().\r
1204fe83 1624\r
3e7104c2 1625 @param[in, out] Map The netmap to remove the head from.\r
1626 @param[out] Value The variable to receive the value if not NULL.\r
da1d0201 1627\r
3e7104c2 1628 @return The key of the item removed.\r
da1d0201 1629\r
1630**/\r
1631VOID *\r
7b414b4e 1632EFIAPI\r
da1d0201 1633NetMapRemoveHead (\r
3e7104c2 1634 IN OUT NET_MAP *Map,\r
da1d0201 1635 OUT VOID **Value OPTIONAL\r
1636 )\r
1637{\r
1638 NET_MAP_ITEM *Item;\r
1639\r
1640 //\r
1641 // Often, it indicates a programming error to remove\r
1642 // the first entry in an empty list\r
1643 //\r
e48e37fc 1644 ASSERT (Map && !IsListEmpty (&Map->Used));\r
da1d0201 1645\r
1646 Item = NET_LIST_HEAD (&Map->Used, NET_MAP_ITEM, Link);\r
e48e37fc 1647 RemoveEntryList (&Item->Link);\r
da1d0201 1648 Map->Count--;\r
e48e37fc 1649 InsertHeadList (&Map->Recycled, &Item->Link);\r
da1d0201 1650\r
1651 if (Value != NULL) {\r
1652 *Value = Item->Value;\r
1653 }\r
1654\r
1655 return Item->Key;\r
1656}\r
1657\r
1658\r
1659/**\r
b9008c87 1660 Remove the last node entry on the netmap and return the key of the removed item.\r
da1d0201 1661\r
1204fe83 1662 Remove the last node entry from the Used doubly linked list of the netmap.\r
1663 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node\r
b9008c87 1664 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,\r
1665 parameter Value will point to the value of the item. It returns the key of the removed item.\r
1204fe83 1666\r
b9008c87 1667 If Map is NULL, then ASSERT().\r
1668 If the Used doubly linked list is empty, then ASSERT().\r
1204fe83 1669\r
3e7104c2 1670 @param[in, out] Map The netmap to remove the tail from.\r
1671 @param[out] Value The variable to receive the value if not NULL.\r
da1d0201 1672\r
3e7104c2 1673 @return The key of the item removed.\r
da1d0201 1674\r
1675**/\r
1676VOID *\r
7b414b4e 1677EFIAPI\r
da1d0201 1678NetMapRemoveTail (\r
3e7104c2 1679 IN OUT NET_MAP *Map,\r
da1d0201 1680 OUT VOID **Value OPTIONAL\r
1681 )\r
1682{\r
1683 NET_MAP_ITEM *Item;\r
1684\r
1685 //\r
1686 // Often, it indicates a programming error to remove\r
1687 // the last entry in an empty list\r
1688 //\r
e48e37fc 1689 ASSERT (Map && !IsListEmpty (&Map->Used));\r
da1d0201 1690\r
1691 Item = NET_LIST_TAIL (&Map->Used, NET_MAP_ITEM, Link);\r
e48e37fc 1692 RemoveEntryList (&Item->Link);\r
da1d0201 1693 Map->Count--;\r
e48e37fc 1694 InsertHeadList (&Map->Recycled, &Item->Link);\r
da1d0201 1695\r
1696 if (Value != NULL) {\r
1697 *Value = Item->Value;\r
1698 }\r
1699\r
1700 return Item->Key;\r
1701}\r
1702\r
1703\r
1704/**\r
b9008c87 1705 Iterate through the netmap and call CallBack for each item.\r
1204fe83 1706\r
3b28e744 1707 It will continue the traverse if CallBack returns EFI_SUCCESS, otherwise, break\r
1204fe83 1708 from the loop. It returns the CallBack's last return value. This function is\r
b9008c87 1709 delete safe for the current item.\r
da1d0201 1710\r
b9008c87 1711 If Map is NULL, then ASSERT().\r
1712 If CallBack is NULL, then ASSERT().\r
1204fe83 1713\r
3e7104c2 1714 @param[in] Map The Map to iterate through.\r
1715 @param[in] CallBack The callback function to call for each item.\r
1716 @param[in] Arg The opaque parameter to the callback.\r
da1d0201 1717\r
3e7104c2 1718 @retval EFI_SUCCESS There is no item in the netmap or CallBack for each item\r
1719 return EFI_SUCCESS.\r
1720 @retval Others It returns the CallBack's last return value.\r
da1d0201 1721\r
1722**/\r
1723EFI_STATUS\r
7b414b4e 1724EFIAPI\r
da1d0201 1725NetMapIterate (\r
1726 IN NET_MAP *Map,\r
1727 IN NET_MAP_CALLBACK CallBack,\r
e2851998 1728 IN VOID *Arg OPTIONAL\r
da1d0201 1729 )\r
1730{\r
1731\r
e48e37fc 1732 LIST_ENTRY *Entry;\r
1733 LIST_ENTRY *Next;\r
1734 LIST_ENTRY *Head;\r
b9008c87 1735 NET_MAP_ITEM *Item;\r
1736 EFI_STATUS Result;\r
da1d0201 1737\r
1738 ASSERT ((Map != NULL) && (CallBack != NULL));\r
1739\r
1740 Head = &Map->Used;\r
1741\r
e48e37fc 1742 if (IsListEmpty (Head)) {\r
da1d0201 1743 return EFI_SUCCESS;\r
1744 }\r
1745\r
1746 NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {\r
1747 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
1748 Result = CallBack (Map, Item, Arg);\r
1749\r
1750 if (EFI_ERROR (Result)) {\r
1751 return Result;\r
1752 }\r
1753 }\r
1754\r
1755 return EFI_SUCCESS;\r
1756}\r
1757\r
1758\r
1759/**\r
1760 This is the default unload handle for all the network drivers.\r
1761\r
b9008c87 1762 Disconnect the driver specified by ImageHandle from all the devices in the handle database.\r
1763 Uninstall all the protocols installed in the driver entry point.\r
1204fe83 1764\r
3e7104c2 1765 @param[in] ImageHandle The drivers' driver image.\r
da1d0201 1766\r
1767 @retval EFI_SUCCESS The image is unloaded.\r
1768 @retval Others Failed to unload the image.\r
1769\r
1770**/\r
1771EFI_STATUS\r
1772EFIAPI\r
1773NetLibDefaultUnload (\r
1774 IN EFI_HANDLE ImageHandle\r
1775 )\r
1776{\r
1777 EFI_STATUS Status;\r
1778 EFI_HANDLE *DeviceHandleBuffer;\r
1779 UINTN DeviceHandleCount;\r
1780 UINTN Index;\r
6879581d 1781 UINTN Index2;\r
da1d0201 1782 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
1783 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;\r
3012ce5c 1784 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;\r
da1d0201 1785\r
1786 //\r
1787 // Get the list of all the handles in the handle database.\r
1788 // If there is an error getting the list, then the unload\r
1789 // operation fails.\r
1790 //\r
1791 Status = gBS->LocateHandleBuffer (\r
1792 AllHandles,\r
1793 NULL,\r
1794 NULL,\r
1795 &DeviceHandleCount,\r
1796 &DeviceHandleBuffer\r
1797 );\r
1798\r
1799 if (EFI_ERROR (Status)) {\r
1800 return Status;\r
1801 }\r
1802\r
da1d0201 1803 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1804 Status = gBS->HandleProtocol (\r
1805 DeviceHandleBuffer[Index],\r
1806 &gEfiDriverBindingProtocolGuid,\r
1807 (VOID **) &DriverBinding\r
1808 );\r
da1d0201 1809 if (EFI_ERROR (Status)) {\r
1810 continue;\r
1811 }\r
1812\r
1813 if (DriverBinding->ImageHandle != ImageHandle) {\r
1814 continue;\r
1815 }\r
d1102dba 1816\r
6879581d 1817 //\r
1818 // Disconnect the driver specified by ImageHandle from all\r
1819 // the devices in the handle database.\r
1820 //\r
1821 for (Index2 = 0; Index2 < DeviceHandleCount; Index2++) {\r
1822 Status = gBS->DisconnectController (\r
1823 DeviceHandleBuffer[Index2],\r
1824 DriverBinding->DriverBindingHandle,\r
1825 NULL\r
1826 );\r
1827 }\r
d1102dba 1828\r
6879581d 1829 //\r
1830 // Uninstall all the protocols installed in the driver entry point\r
d1102dba 1831 //\r
da1d0201 1832 gBS->UninstallProtocolInterface (\r
6879581d 1833 DriverBinding->DriverBindingHandle,\r
da1d0201 1834 &gEfiDriverBindingProtocolGuid,\r
1835 DriverBinding\r
1836 );\r
d1102dba 1837\r
da1d0201 1838 Status = gBS->HandleProtocol (\r
1839 DeviceHandleBuffer[Index],\r
1840 &gEfiComponentNameProtocolGuid,\r
1841 (VOID **) &ComponentName\r
1842 );\r
1843 if (!EFI_ERROR (Status)) {\r
1844 gBS->UninstallProtocolInterface (\r
6879581d 1845 DriverBinding->DriverBindingHandle,\r
da1d0201 1846 &gEfiComponentNameProtocolGuid,\r
1847 ComponentName\r
1848 );\r
1849 }\r
1850\r
1851 Status = gBS->HandleProtocol (\r
1852 DeviceHandleBuffer[Index],\r
3012ce5c 1853 &gEfiComponentName2ProtocolGuid,\r
1854 (VOID **) &ComponentName2\r
da1d0201 1855 );\r
da1d0201 1856 if (!EFI_ERROR (Status)) {\r
1857 gBS->UninstallProtocolInterface (\r
6879581d 1858 DriverBinding->DriverBindingHandle,\r
3012ce5c 1859 &gEfiComponentName2ProtocolGuid,\r
1860 ComponentName2\r
1861 );\r
da1d0201 1862 }\r
1863 }\r
1864\r
1865 //\r
1866 // Free the buffer containing the list of handles from the handle database\r
1867 //\r
1868 if (DeviceHandleBuffer != NULL) {\r
1869 gBS->FreePool (DeviceHandleBuffer);\r
1870 }\r
1871\r
1872 return EFI_SUCCESS;\r
1873}\r
1874\r
1875\r
1876\r
1877/**\r
1878 Create a child of the service that is identified by ServiceBindingGuid.\r
1204fe83 1879\r
b9008c87 1880 Get the ServiceBinding Protocol first, then use it to create a child.\r
da1d0201 1881\r
b9008c87 1882 If ServiceBindingGuid is NULL, then ASSERT().\r
1883 If ChildHandle is NULL, then ASSERT().\r
1204fe83 1884\r
3e7104c2 1885 @param[in] Controller The controller which has the service installed.\r
1886 @param[in] Image The image handle used to open service.\r
1887 @param[in] ServiceBindingGuid The service's Guid.\r
8f5e6151 1888 @param[in, out] ChildHandle The handle to receive the create child.\r
da1d0201 1889\r
1890 @retval EFI_SUCCESS The child is successfully created.\r
1891 @retval Others Failed to create the child.\r
1892\r
1893**/\r
1894EFI_STATUS\r
7b414b4e 1895EFIAPI\r
da1d0201 1896NetLibCreateServiceChild (\r
1897 IN EFI_HANDLE Controller,\r
1898 IN EFI_HANDLE Image,\r
1899 IN EFI_GUID *ServiceBindingGuid,\r
3e7104c2 1900 IN OUT EFI_HANDLE *ChildHandle\r
da1d0201 1901 )\r
1902{\r
1903 EFI_STATUS Status;\r
1904 EFI_SERVICE_BINDING_PROTOCOL *Service;\r
1905\r
1906\r
1907 ASSERT ((ServiceBindingGuid != NULL) && (ChildHandle != NULL));\r
1908\r
1909 //\r
1910 // Get the ServiceBinding Protocol\r
1911 //\r
1912 Status = gBS->OpenProtocol (\r
1913 Controller,\r
1914 ServiceBindingGuid,\r
1915 (VOID **) &Service,\r
1916 Image,\r
1917 Controller,\r
1918 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1919 );\r
1920\r
1921 if (EFI_ERROR (Status)) {\r
1922 return Status;\r
1923 }\r
1924\r
1925 //\r
1926 // Create a child\r
1927 //\r
1928 Status = Service->CreateChild (Service, ChildHandle);\r
1929 return Status;\r
1930}\r
1931\r
1932\r
1933/**\r
75dce340 1934 Destroy a child of the service that is identified by ServiceBindingGuid.\r
1204fe83 1935\r
b9008c87 1936 Get the ServiceBinding Protocol first, then use it to destroy a child.\r
1204fe83 1937\r
b9008c87 1938 If ServiceBindingGuid is NULL, then ASSERT().\r
1204fe83 1939\r
3e7104c2 1940 @param[in] Controller The controller which has the service installed.\r
1941 @param[in] Image The image handle used to open service.\r
1942 @param[in] ServiceBindingGuid The service's Guid.\r
75dce340 1943 @param[in] ChildHandle The child to destroy.\r
da1d0201 1944\r
75dce340 1945 @retval EFI_SUCCESS The child is successfully destroyed.\r
1946 @retval Others Failed to destroy the child.\r
da1d0201 1947\r
1948**/\r
1949EFI_STATUS\r
7b414b4e 1950EFIAPI\r
da1d0201 1951NetLibDestroyServiceChild (\r
1952 IN EFI_HANDLE Controller,\r
1953 IN EFI_HANDLE Image,\r
1954 IN EFI_GUID *ServiceBindingGuid,\r
1955 IN EFI_HANDLE ChildHandle\r
1956 )\r
1957{\r
1958 EFI_STATUS Status;\r
1959 EFI_SERVICE_BINDING_PROTOCOL *Service;\r
1960\r
1961 ASSERT (ServiceBindingGuid != NULL);\r
1962\r
1963 //\r
1964 // Get the ServiceBinding Protocol\r
1965 //\r
1966 Status = gBS->OpenProtocol (\r
1967 Controller,\r
1968 ServiceBindingGuid,\r
1969 (VOID **) &Service,\r
1970 Image,\r
1971 Controller,\r
1972 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1973 );\r
1974\r
1975 if (EFI_ERROR (Status)) {\r
1976 return Status;\r
1977 }\r
1978\r
1979 //\r
75dce340 1980 // destroy the child\r
da1d0201 1981 //\r
1982 Status = Service->DestroyChild (Service, ChildHandle);\r
1983 return Status;\r
1984}\r
1985\r
779ae357 1986/**\r
1987 Get handle with Simple Network Protocol installed on it.\r
1988\r
1989 There should be MNP Service Binding Protocol installed on the input ServiceHandle.\r
1990 If Simple Network Protocol is already installed on the ServiceHandle, the\r
1991 ServiceHandle will be returned. If SNP is not installed on the ServiceHandle,\r
1992 try to find its parent handle with SNP installed.\r
1993\r
1994 @param[in] ServiceHandle The handle where network service binding protocols are\r
1995 installed on.\r
1996 @param[out] Snp The pointer to store the address of the SNP instance.\r
1997 This is an optional parameter that may be NULL.\r
1998\r
1999 @return The SNP handle, or NULL if not found.\r
2000\r
2001**/\r
2002EFI_HANDLE\r
2003EFIAPI\r
2004NetLibGetSnpHandle (\r
2005 IN EFI_HANDLE ServiceHandle,\r
2006 OUT EFI_SIMPLE_NETWORK_PROTOCOL **Snp OPTIONAL\r
2007 )\r
2008{\r
2009 EFI_STATUS Status;\r
2010 EFI_SIMPLE_NETWORK_PROTOCOL *SnpInstance;\r
2011 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
2012 EFI_HANDLE SnpHandle;\r
2013\r
2014 //\r
2015 // Try to open SNP from ServiceHandle\r
2016 //\r
2017 SnpInstance = NULL;\r
2018 Status = gBS->HandleProtocol (ServiceHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);\r
2019 if (!EFI_ERROR (Status)) {\r
2020 if (Snp != NULL) {\r
2021 *Snp = SnpInstance;\r
2022 }\r
2023 return ServiceHandle;\r
2024 }\r
2025\r
2026 //\r
2027 // Failed to open SNP, try to get SNP handle by LocateDevicePath()\r
2028 //\r
2029 DevicePath = DevicePathFromHandle (ServiceHandle);\r
2030 if (DevicePath == NULL) {\r
2031 return NULL;\r
2032 }\r
2033\r
2034 SnpHandle = NULL;\r
2035 Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &DevicePath, &SnpHandle);\r
2036 if (EFI_ERROR (Status)) {\r
2037 //\r
2038 // Failed to find SNP handle\r
2039 //\r
2040 return NULL;\r
2041 }\r
2042\r
2043 Status = gBS->HandleProtocol (SnpHandle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &SnpInstance);\r
2044 if (!EFI_ERROR (Status)) {\r
2045 if (Snp != NULL) {\r
2046 *Snp = SnpInstance;\r
2047 }\r
2048 return SnpHandle;\r
2049 }\r
2050\r
2051 return NULL;\r
2052}\r
2053\r
2054/**\r
2055 Retrieve VLAN ID of a VLAN device handle.\r
2056\r
2057 Search VLAN device path node in Device Path of specified ServiceHandle and\r
2058 return its VLAN ID. If no VLAN device path node found, then this ServiceHandle\r
2059 is not a VLAN device handle, and 0 will be returned.\r
2060\r
2061 @param[in] ServiceHandle The handle where network service binding protocols are\r
2062 installed on.\r
2063\r
2064 @return VLAN ID of the device handle, or 0 if not a VLAN device.\r
2065\r
2066**/\r
2067UINT16\r
2068EFIAPI\r
2069NetLibGetVlanId (\r
2070 IN EFI_HANDLE ServiceHandle\r
2071 )\r
2072{\r
2073 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
2074 EFI_DEVICE_PATH_PROTOCOL *Node;\r
2075\r
2076 DevicePath = DevicePathFromHandle (ServiceHandle);\r
2077 if (DevicePath == NULL) {\r
2078 return 0;\r
2079 }\r
2080\r
2081 Node = DevicePath;\r
2082 while (!IsDevicePathEnd (Node)) {\r
2083 if (Node->Type == MESSAGING_DEVICE_PATH && Node->SubType == MSG_VLAN_DP) {\r
2084 return ((VLAN_DEVICE_PATH *) Node)->VlanId;\r
2085 }\r
2086 Node = NextDevicePathNode (Node);\r
2087 }\r
2088\r
2089 return 0;\r
2090}\r
2091\r
2092/**\r
2093 Find VLAN device handle with specified VLAN ID.\r
2094\r
2095 The VLAN child device handle is created by VLAN Config Protocol on ControllerHandle.\r
2096 This function will append VLAN device path node to the parent device path,\r
2097 and then use LocateDevicePath() to find the correct VLAN device handle.\r
2098\r
e2851998 2099 @param[in] ControllerHandle The handle where network service binding protocols are\r
779ae357 2100 installed on.\r
e2851998 2101 @param[in] VlanId The configured VLAN ID for the VLAN device.\r
779ae357 2102\r
2103 @return The VLAN device handle, or NULL if not found.\r
2104\r
2105**/\r
2106EFI_HANDLE\r
2107EFIAPI\r
2108NetLibGetVlanHandle (\r
2109 IN EFI_HANDLE ControllerHandle,\r
2110 IN UINT16 VlanId\r
2111 )\r
2112{\r
2113 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
2114 EFI_DEVICE_PATH_PROTOCOL *VlanDevicePath;\r
2115 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
2116 VLAN_DEVICE_PATH VlanNode;\r
2117 EFI_HANDLE Handle;\r
2118\r
2119 ParentDevicePath = DevicePathFromHandle (ControllerHandle);\r
2120 if (ParentDevicePath == NULL) {\r
2121 return NULL;\r
2122 }\r
2123\r
2124 //\r
2125 // Construct VLAN device path\r
2126 //\r
2127 CopyMem (&VlanNode, &mNetVlanDevicePathTemplate, sizeof (VLAN_DEVICE_PATH));\r
2128 VlanNode.VlanId = VlanId;\r
2129 VlanDevicePath = AppendDevicePathNode (\r
2130 ParentDevicePath,\r
2131 (EFI_DEVICE_PATH_PROTOCOL *) &VlanNode\r
2132 );\r
2133 if (VlanDevicePath == NULL) {\r
2134 return NULL;\r
2135 }\r
2136\r
2137 //\r
2138 // Find VLAN device handle\r
2139 //\r
2140 Handle = NULL;\r
2141 DevicePath = VlanDevicePath;\r
2142 gBS->LocateDevicePath (\r
2143 &gEfiDevicePathProtocolGuid,\r
2144 &DevicePath,\r
2145 &Handle\r
2146 );\r
2147 if (!IsDevicePathEnd (DevicePath)) {\r
2148 //\r
2149 // Device path is not exactly match\r
2150 //\r
2151 Handle = NULL;\r
2152 }\r
2153\r
2154 FreePool (VlanDevicePath);\r
2155 return Handle;\r
2156}\r
da1d0201 2157\r
2158/**\r
779ae357 2159 Get MAC address associated with the network service handle.\r
2160\r
cf4a8fa4
WF
2161 If MacAddress is NULL, then ASSERT().\r
2162 If AddressSize is NULL, then ASSERT().\r
2163\r
779ae357 2164 There should be MNP Service Binding Protocol installed on the input ServiceHandle.\r
2165 If SNP is installed on the ServiceHandle or its parent handle, MAC address will\r
2166 be retrieved from SNP. If no SNP found, try to get SNP mode data use MNP.\r
2167\r
2168 @param[in] ServiceHandle The handle where network service binding protocols are\r
2169 installed on.\r
2170 @param[out] MacAddress The pointer to store the returned MAC address.\r
2171 @param[out] AddressSize The length of returned MAC address.\r
2172\r
2173 @retval EFI_SUCCESS MAC address is returned successfully.\r
2174 @retval Others Failed to get SNP mode data.\r
2175\r
2176**/\r
2177EFI_STATUS\r
2178EFIAPI\r
2179NetLibGetMacAddress (\r
2180 IN EFI_HANDLE ServiceHandle,\r
2181 OUT EFI_MAC_ADDRESS *MacAddress,\r
2182 OUT UINTN *AddressSize\r
2183 )\r
2184{\r
2185 EFI_STATUS Status;\r
2186 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
2187 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
2188 EFI_SIMPLE_NETWORK_MODE SnpModeData;\r
2189 EFI_MANAGED_NETWORK_PROTOCOL *Mnp;\r
2190 EFI_SERVICE_BINDING_PROTOCOL *MnpSb;\r
2191 EFI_HANDLE *SnpHandle;\r
2192 EFI_HANDLE MnpChildHandle;\r
2193\r
2194 ASSERT (MacAddress != NULL);\r
2195 ASSERT (AddressSize != NULL);\r
2196\r
2197 //\r
2198 // Try to get SNP handle\r
2199 //\r
2200 Snp = NULL;\r
2201 SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);\r
2202 if (SnpHandle != NULL) {\r
2203 //\r
2204 // SNP found, use it directly\r
2205 //\r
2206 SnpMode = Snp->Mode;\r
2207 } else {\r
2208 //\r
2209 // Failed to get SNP handle, try to get MAC address from MNP\r
2210 //\r
2211 MnpChildHandle = NULL;\r
2212 Status = gBS->HandleProtocol (\r
2213 ServiceHandle,\r
2214 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
2215 (VOID **) &MnpSb\r
2216 );\r
2217 if (EFI_ERROR (Status)) {\r
2218 return Status;\r
2219 }\r
2220\r
2221 //\r
2222 // Create a MNP child\r
2223 //\r
2224 Status = MnpSb->CreateChild (MnpSb, &MnpChildHandle);\r
2225 if (EFI_ERROR (Status)) {\r
2226 return Status;\r
2227 }\r
2228\r
2229 //\r
2230 // Open MNP protocol\r
2231 //\r
2232 Status = gBS->HandleProtocol (\r
2233 MnpChildHandle,\r
2234 &gEfiManagedNetworkProtocolGuid,\r
2235 (VOID **) &Mnp\r
2236 );\r
2237 if (EFI_ERROR (Status)) {\r
e20d6513 2238 MnpSb->DestroyChild (MnpSb, MnpChildHandle);\r
779ae357 2239 return Status;\r
2240 }\r
da1d0201 2241\r
779ae357 2242 //\r
2243 // Try to get SNP mode from MNP\r
2244 //\r
2245 Status = Mnp->GetModeData (Mnp, NULL, &SnpModeData);\r
3ce454dd 2246 if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {\r
e20d6513 2247 MnpSb->DestroyChild (MnpSb, MnpChildHandle);\r
779ae357 2248 return Status;\r
2249 }\r
2250 SnpMode = &SnpModeData;\r
b9008c87 2251\r
779ae357 2252 //\r
2253 // Destroy the MNP child\r
2254 //\r
2255 MnpSb->DestroyChild (MnpSb, MnpChildHandle);\r
2256 }\r
b9008c87 2257\r
779ae357 2258 *AddressSize = SnpMode->HwAddressSize;\r
2259 CopyMem (MacAddress->Addr, SnpMode->CurrentAddress.Addr, SnpMode->HwAddressSize);\r
2260\r
2261 return EFI_SUCCESS;\r
2262}\r
2263\r
2264/**\r
2265 Convert MAC address of the NIC associated with specified Service Binding Handle\r
2266 to a unicode string. Callers are responsible for freeing the string storage.\r
2267\r
cf4a8fa4
WF
2268 If MacString is NULL, then ASSERT().\r
2269\r
779ae357 2270 Locate simple network protocol associated with the Service Binding Handle and\r
2271 get the mac address from SNP. Then convert the mac address into a unicode\r
2272 string. It takes 2 unicode characters to represent a 1 byte binary buffer.\r
2273 Plus one unicode character for the null-terminator.\r
2274\r
2275 @param[in] ServiceHandle The handle where network service binding protocol is\r
3e7104c2 2276 installed on.\r
2277 @param[in] ImageHandle The image handle used to act as the agent handle to\r
b00ed21a 2278 get the simple network protocol. This parameter is\r
2279 optional and may be NULL.\r
3e7104c2 2280 @param[out] MacString The pointer to store the address of the string\r
2281 representation of the mac address.\r
1204fe83 2282\r
3e7104c2 2283 @retval EFI_SUCCESS Convert the mac address a unicode string successfully.\r
da1d0201 2284 @retval EFI_OUT_OF_RESOURCES There are not enough memory resource.\r
3e7104c2 2285 @retval Others Failed to open the simple network protocol.\r
da1d0201 2286\r
2287**/\r
2288EFI_STATUS\r
7b414b4e 2289EFIAPI\r
da1d0201 2290NetLibGetMacString (\r
779ae357 2291 IN EFI_HANDLE ServiceHandle,\r
b00ed21a 2292 IN EFI_HANDLE ImageHandle, OPTIONAL\r
3e7104c2 2293 OUT CHAR16 **MacString\r
da1d0201 2294 )\r
2295{\r
2296 EFI_STATUS Status;\r
779ae357 2297 EFI_MAC_ADDRESS MacAddress;\r
1204fe83 2298 UINT8 *HwAddress;\r
779ae357 2299 UINTN HwAddressSize;\r
2300 UINT16 VlanId;\r
2301 CHAR16 *String;\r
da1d0201 2302 UINTN Index;\r
9f4048f7 2303 UINTN BufferSize;\r
da1d0201 2304\r
779ae357 2305 ASSERT (MacString != NULL);\r
da1d0201 2306\r
2307 //\r
779ae357 2308 // Get MAC address of the network device\r
da1d0201 2309 //\r
779ae357 2310 Status = NetLibGetMacAddress (ServiceHandle, &MacAddress, &HwAddressSize);\r
da1d0201 2311 if (EFI_ERROR (Status)) {\r
2312 return Status;\r
2313 }\r
2314\r
da1d0201 2315 //\r
2316 // It takes 2 unicode characters to represent a 1 byte binary buffer.\r
779ae357 2317 // If VLAN is configured, it will need extra 5 characters like "\0005".\r
da1d0201 2318 // Plus one unicode character for the null-terminator.\r
2319 //\r
9f4048f7
HW
2320 BufferSize = (2 * HwAddressSize + 5 + 1) * sizeof (CHAR16);\r
2321 String = AllocateZeroPool (BufferSize);\r
779ae357 2322 if (String == NULL) {\r
da1d0201 2323 return EFI_OUT_OF_RESOURCES;\r
2324 }\r
779ae357 2325 *MacString = String;\r
da1d0201 2326\r
2327 //\r
779ae357 2328 // Convert the MAC address into a unicode string.\r
da1d0201 2329 //\r
779ae357 2330 HwAddress = &MacAddress.Addr[0];\r
2331 for (Index = 0; Index < HwAddressSize; Index++) {\r
9f4048f7
HW
2332 UnicodeValueToStringS (\r
2333 String,\r
2334 BufferSize - ((UINTN)String - (UINTN)*MacString),\r
2335 PREFIX_ZERO | RADIX_HEX,\r
2336 *(HwAddress++),\r
2337 2\r
2338 );\r
2339 String += StrnLenS (String, (BufferSize - ((UINTN)String - (UINTN)*MacString)) / sizeof (CHAR16));\r
da1d0201 2340 }\r
2341\r
779ae357 2342 //\r
2343 // Append VLAN ID if any\r
2344 //\r
2345 VlanId = NetLibGetVlanId (ServiceHandle);\r
2346 if (VlanId != 0) {\r
2347 *String++ = L'\\';\r
9f4048f7
HW
2348 UnicodeValueToStringS (\r
2349 String,\r
2350 BufferSize - ((UINTN)String - (UINTN)*MacString),\r
2351 PREFIX_ZERO | RADIX_HEX,\r
2352 VlanId,\r
2353 4\r
2354 );\r
2355 String += StrnLenS (String, (BufferSize - ((UINTN)String - (UINTN)*MacString)) / sizeof (CHAR16));\r
779ae357 2356 }\r
da1d0201 2357\r
779ae357 2358 //\r
2359 // Null terminate the Unicode string\r
2360 //\r
2361 *String = L'\0';\r
da1d0201 2362\r
2363 return EFI_SUCCESS;\r
2364}\r
2365\r
dd29f3ed 2366/**\r
2367 Detect media status for specified network device.\r
2368\r
cf4a8fa4
WF
2369 If MediaPresent is NULL, then ASSERT().\r
2370\r
dd29f3ed 2371 The underlying UNDI driver may or may not support reporting media status from\r
2372 GET_STATUS command (PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED). This routine\r
2373 will try to invoke Snp->GetStatus() to get the media status: if media already\r
2374 present, it return directly; if media not present, it will stop SNP and then\r
2375 restart SNP to get the latest media status, this give chance to get the correct\r
2376 media status for old UNDI driver which doesn't support reporting media status\r
2377 from GET_STATUS command.\r
2378 Note: there will be two limitations for current algorithm:\r
2379 1) for UNDI with this capability, in case of cable is not attached, there will\r
2380 be an redundant Stop/Start() process;\r
3b1464d5 2381 2) for UNDI without this capability, in case that network cable is attached when\r
2382 Snp->Initialize() is invoked while network cable is unattached later,\r
2383 NetLibDetectMedia() will report MediaPresent as TRUE, causing upper layer\r
2384 apps to wait for timeout time.\r
dd29f3ed 2385\r
2386 @param[in] ServiceHandle The handle where network service binding protocols are\r
2387 installed on.\r
2388 @param[out] MediaPresent The pointer to store the media status.\r
2389\r
2390 @retval EFI_SUCCESS Media detection success.\r
2391 @retval EFI_INVALID_PARAMETER ServiceHandle is not valid network device handle.\r
2392 @retval EFI_UNSUPPORTED Network device does not support media detection.\r
2393 @retval EFI_DEVICE_ERROR SNP is in unknown state.\r
2394\r
2395**/\r
2396EFI_STATUS\r
2397EFIAPI\r
2398NetLibDetectMedia (\r
2399 IN EFI_HANDLE ServiceHandle,\r
2400 OUT BOOLEAN *MediaPresent\r
2401 )\r
2402{\r
2403 EFI_STATUS Status;\r
2404 EFI_HANDLE SnpHandle;\r
2405 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
2406 UINT32 InterruptStatus;\r
2407 UINT32 OldState;\r
2408 EFI_MAC_ADDRESS *MCastFilter;\r
2409 UINT32 MCastFilterCount;\r
2410 UINT32 EnableFilterBits;\r
2411 UINT32 DisableFilterBits;\r
2412 BOOLEAN ResetMCastFilters;\r
2413\r
2414 ASSERT (MediaPresent != NULL);\r
2415\r
2416 //\r
2417 // Get SNP handle\r
2418 //\r
2419 Snp = NULL;\r
2420 SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);\r
2421 if (SnpHandle == NULL) {\r
2422 return EFI_INVALID_PARAMETER;\r
2423 }\r
2424\r
2425 //\r
2426 // Check whether SNP support media detection\r
2427 //\r
2428 if (!Snp->Mode->MediaPresentSupported) {\r
2429 return EFI_UNSUPPORTED;\r
2430 }\r
2431\r
2432 //\r
2433 // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data\r
2434 //\r
2435 Status = Snp->GetStatus (Snp, &InterruptStatus, NULL);\r
2436 if (EFI_ERROR (Status)) {\r
2437 return Status;\r
2438 }\r
2439\r
2440 if (Snp->Mode->MediaPresent) {\r
2441 //\r
2442 // Media is present, return directly\r
2443 //\r
2444 *MediaPresent = TRUE;\r
2445 return EFI_SUCCESS;\r
2446 }\r
2447\r
2448 //\r
2449 // Till now, GetStatus() report no media; while, in case UNDI not support\r
2450 // reporting media status from GetStatus(), this media status may be incorrect.\r
2451 // So, we will stop SNP and then restart it to get the correct media status.\r
2452 //\r
2453 OldState = Snp->Mode->State;\r
2454 if (OldState >= EfiSimpleNetworkMaxState) {\r
2455 return EFI_DEVICE_ERROR;\r
2456 }\r
2457\r
2458 MCastFilter = NULL;\r
2459\r
2460 if (OldState == EfiSimpleNetworkInitialized) {\r
2461 //\r
2462 // SNP is already in use, need Shutdown/Stop and then Start/Initialize\r
2463 //\r
2464\r
2465 //\r
2466 // Backup current SNP receive filter settings\r
2467 //\r
2468 EnableFilterBits = Snp->Mode->ReceiveFilterSetting;\r
2469 DisableFilterBits = Snp->Mode->ReceiveFilterMask ^ EnableFilterBits;\r
2470\r
2471 ResetMCastFilters = TRUE;\r
2472 MCastFilterCount = Snp->Mode->MCastFilterCount;\r
2473 if (MCastFilterCount != 0) {\r
2474 MCastFilter = AllocateCopyPool (\r
2475 MCastFilterCount * sizeof (EFI_MAC_ADDRESS),\r
2476 Snp->Mode->MCastFilter\r
2477 );\r
2478 ASSERT (MCastFilter != NULL);\r
cf4a8fa4
WF
2479 if (MCastFilter == NULL) {\r
2480 Status = EFI_OUT_OF_RESOURCES;\r
2481 goto Exit;\r
2482 }\r
dd29f3ed 2483\r
2484 ResetMCastFilters = FALSE;\r
2485 }\r
2486\r
2487 //\r
2488 // Shutdown/Stop the simple network\r
2489 //\r
2490 Status = Snp->Shutdown (Snp);\r
2491 if (!EFI_ERROR (Status)) {\r
2492 Status = Snp->Stop (Snp);\r
2493 }\r
2494 if (EFI_ERROR (Status)) {\r
2495 goto Exit;\r
2496 }\r
2497\r
2498 //\r
2499 // Start/Initialize the simple network\r
2500 //\r
2501 Status = Snp->Start (Snp);\r
2502 if (!EFI_ERROR (Status)) {\r
2503 Status = Snp->Initialize (Snp, 0, 0);\r
2504 }\r
2505 if (EFI_ERROR (Status)) {\r
2506 goto Exit;\r
2507 }\r
2508\r
2509 //\r
2510 // Here we get the correct media status\r
2511 //\r
2512 *MediaPresent = Snp->Mode->MediaPresent;\r
2513\r
2514 //\r
2515 // Restore SNP receive filter settings\r
2516 //\r
2517 Status = Snp->ReceiveFilters (\r
2518 Snp,\r
2519 EnableFilterBits,\r
2520 DisableFilterBits,\r
2521 ResetMCastFilters,\r
2522 MCastFilterCount,\r
2523 MCastFilter\r
2524 );\r
2525\r
2526 if (MCastFilter != NULL) {\r
2527 FreePool (MCastFilter);\r
2528 }\r
2529\r
2530 return Status;\r
2531 }\r
2532\r
2533 //\r
2534 // SNP is not in use, it's in state of EfiSimpleNetworkStopped or EfiSimpleNetworkStarted\r
2535 //\r
2536 if (OldState == EfiSimpleNetworkStopped) {\r
2537 //\r
2538 // SNP not start yet, start it\r
2539 //\r
2540 Status = Snp->Start (Snp);\r
2541 if (EFI_ERROR (Status)) {\r
2542 goto Exit;\r
2543 }\r
2544 }\r
2545\r
2546 //\r
2547 // Initialize the simple network\r
2548 //\r
2549 Status = Snp->Initialize (Snp, 0, 0);\r
2550 if (EFI_ERROR (Status)) {\r
2551 Status = EFI_DEVICE_ERROR;\r
2552 goto Exit;\r
2553 }\r
2554\r
2555 //\r
2556 // Here we get the correct media status\r
2557 //\r
2558 *MediaPresent = Snp->Mode->MediaPresent;\r
2559\r
2560 //\r
2561 // Shut down the simple network\r
2562 //\r
2563 Snp->Shutdown (Snp);\r
2564\r
2565Exit:\r
2566 if (OldState == EfiSimpleNetworkStopped) {\r
2567 //\r
2568 // Original SNP sate is Stopped, restore to original state\r
2569 //\r
2570 Snp->Stop (Snp);\r
2571 }\r
2572\r
2573 if (MCastFilter != NULL) {\r
2574 FreePool (MCastFilter);\r
2575 }\r
2576\r
2577 return Status;\r
2578}\r
2579\r
ca4e4323 2580/**\r
2581\r
d1102dba
LG
2582 Detect media state for a network device. This routine will wait for a period of time at\r
2583 a specified checking interval when a certain network is under connecting until connection\r
ca4e4323 2584 process finishs or timeout. If Aip protocol is supported by low layer drivers, three kinds\r
2585 of media states can be detected: EFI_SUCCESS, EFI_NOT_READY and EFI_NO_MEDIA, represents\r
d1102dba
LG
2586 connected state, connecting state and no media state respectively. When function detects\r
2587 the current state is EFI_NOT_READY, it will loop to wait for next time's check until state\r
2588 turns to be EFI_SUCCESS or EFI_NO_MEDIA. If Aip protocol is not supported, function will\r
ca4e4323 2589 call NetLibDetectMedia() and return state directly.\r
2590\r
2591 @param[in] ServiceHandle The handle where network service binding protocols are\r
2592 installed on.\r
2593 @param[in] Timeout The maximum number of 100ns units to wait when network\r
2594 is connecting. Zero value means detect once and return\r
2595 immediately.\r
2596 @param[out] MediaState The pointer to the detected media state.\r
2597\r
2598 @retval EFI_SUCCESS Media detection success.\r
d1102dba 2599 @retval EFI_INVALID_PARAMETER ServiceHandle is not a valid network device handle or\r
ca4e4323 2600 MediaState pointer is NULL.\r
2601 @retval EFI_DEVICE_ERROR A device error occurred.\r
2602 @retval EFI_TIMEOUT Network is connecting but timeout.\r
2603\r
2604**/\r
ca4e4323 2605EFI_STATUS\r
2606EFIAPI\r
2607NetLibDetectMediaWaitTimeout (\r
2608 IN EFI_HANDLE ServiceHandle,\r
2609 IN UINT64 Timeout,\r
2610 OUT EFI_STATUS *MediaState\r
2611 )\r
2612{\r
2613 EFI_STATUS Status;\r
2614 EFI_HANDLE SnpHandle;\r
2615 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
2616 EFI_ADAPTER_INFORMATION_PROTOCOL *Aip;\r
2617 EFI_ADAPTER_INFO_MEDIA_STATE *MediaInfo;\r
2618 BOOLEAN MediaPresent;\r
2619 UINTN DataSize;\r
2620 EFI_STATUS TimerStatus;\r
2621 EFI_EVENT Timer;\r
2622 UINT64 TimeRemained;\r
2623\r
2624 if (MediaState == NULL) {\r
2625 return EFI_INVALID_PARAMETER;\r
2626 }\r
2627 *MediaState = EFI_SUCCESS;\r
2628 MediaInfo = NULL;\r
2629\r
2630 //\r
2631 // Get SNP handle\r
2632 //\r
2633 Snp = NULL;\r
2634 SnpHandle = NetLibGetSnpHandle (ServiceHandle, &Snp);\r
2635 if (SnpHandle == NULL) {\r
2636 return EFI_INVALID_PARAMETER;\r
2637 }\r
2638\r
2639 Status = gBS->HandleProtocol (\r
2640 SnpHandle,\r
2641 &gEfiAdapterInformationProtocolGuid,\r
2642 (VOID *) &Aip\r
2643 );\r
2644 if (EFI_ERROR (Status)) {\r
2645\r
2646 MediaPresent = TRUE;\r
2647 Status = NetLibDetectMedia (ServiceHandle, &MediaPresent);\r
2648 if (!EFI_ERROR (Status)) {\r
c5738e3c 2649 if (MediaPresent) {\r
ca4e4323 2650 *MediaState = EFI_SUCCESS;\r
2651 } else {\r
2652 *MediaState = EFI_NO_MEDIA;\r
2653 }\r
2654 }\r
2655\r
2656 //\r
2657 // NetLibDetectMedia doesn't support EFI_NOT_READY status, return now!\r
2658 //\r
2659 return Status;\r
2660 }\r
2661\r
2662 Status = Aip->GetInformation (\r
2663 Aip,\r
2664 &gEfiAdapterInfoMediaStateGuid,\r
2665 (VOID **) &MediaInfo,\r
2666 &DataSize\r
2667 );\r
2668 if (!EFI_ERROR (Status)) {\r
2669\r
2670 *MediaState = MediaInfo->MediaState;\r
2671 FreePool (MediaInfo);\r
2672 if (*MediaState != EFI_NOT_READY || Timeout < MEDIA_STATE_DETECT_TIME_INTERVAL) {\r
2673\r
2674 return EFI_SUCCESS;\r
2675 }\r
2676 } else {\r
2677\r
2678 if (MediaInfo != NULL) {\r
2679 FreePool (MediaInfo);\r
2680 }\r
5d0e003c 2681\r
2682 if (Status == EFI_UNSUPPORTED) {\r
2683\r
2684 //\r
2685 // If gEfiAdapterInfoMediaStateGuid is not supported, call NetLibDetectMedia to get media state!\r
2686 //\r
2687 MediaPresent = TRUE;\r
2688 Status = NetLibDetectMedia (ServiceHandle, &MediaPresent);\r
2689 if (!EFI_ERROR (Status)) {\r
c5738e3c 2690 if (MediaPresent) {\r
5d0e003c 2691 *MediaState = EFI_SUCCESS;\r
2692 } else {\r
2693 *MediaState = EFI_NO_MEDIA;\r
2694 }\r
2695 }\r
2696 return Status;\r
2697 }\r
2698\r
ca4e4323 2699 return Status;\r
2700 }\r
2701\r
2702 //\r
d1102dba 2703 // Loop to check media state\r
ca4e4323 2704 //\r
2705\r
2706 Timer = NULL;\r
2707 TimeRemained = Timeout;\r
2708 Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);\r
2709 if (EFI_ERROR (Status)) {\r
2710 return EFI_DEVICE_ERROR;\r
2711 }\r
2712\r
2713 do {\r
2714 Status = gBS->SetTimer (\r
2715 Timer,\r
2716 TimerRelative,\r
2717 MEDIA_STATE_DETECT_TIME_INTERVAL\r
2718 );\r
2719 if (EFI_ERROR (Status)) {\r
2720 gBS->CloseEvent(Timer);\r
2721 return EFI_DEVICE_ERROR;\r
2722 }\r
2723\r
2724 do {\r
2725 TimerStatus = gBS->CheckEvent (Timer);\r
2726 if (!EFI_ERROR (TimerStatus)) {\r
2727\r
2728 TimeRemained -= MEDIA_STATE_DETECT_TIME_INTERVAL;\r
2729 Status = Aip->GetInformation (\r
2730 Aip,\r
2731 &gEfiAdapterInfoMediaStateGuid,\r
2732 (VOID **) &MediaInfo,\r
2733 &DataSize\r
2734 );\r
2735 if (!EFI_ERROR (Status)) {\r
2736\r
2737 *MediaState = MediaInfo->MediaState;\r
2738 FreePool (MediaInfo);\r
2739 } else {\r
2740\r
2741 if (MediaInfo != NULL) {\r
2742 FreePool (MediaInfo);\r
2743 }\r
2744 gBS->CloseEvent(Timer);\r
2745 return Status;\r
2746 }\r
2747 }\r
2748 } while (TimerStatus == EFI_NOT_READY);\r
2749 } while (*MediaState == EFI_NOT_READY && TimeRemained >= MEDIA_STATE_DETECT_TIME_INTERVAL);\r
2750\r
2751 gBS->CloseEvent(Timer);\r
2752 if (*MediaState == EFI_NOT_READY && TimeRemained < MEDIA_STATE_DETECT_TIME_INTERVAL) {\r
2753 return EFI_TIMEOUT;\r
2754 } else {\r
2755 return EFI_SUCCESS;\r
2756 }\r
2757}\r
2758\r
da1d0201 2759/**\r
2760 Check the default address used by the IPv4 driver is static or dynamic (acquired\r
2761 from DHCP).\r
2762\r
6c5c70d6 2763 If the controller handle does not have the EFI_IP4_CONFIG2_PROTOCOL installed, the\r
d1102dba 2764 default address is static. If failed to get the policy from Ip4 Config2 Protocol,\r
6c5c70d6 2765 the default address is static. Otherwise, get the result from Ip4 Config2 Protocol.\r
1204fe83 2766\r
d1102dba 2767 @param[in] Controller The controller handle which has the EFI_IP4_CONFIG2_PROTOCOL\r
3e7104c2 2768 relative with the default address to judge.\r
da1d0201 2769\r
2770 @retval TRUE If the default address is static.\r
2771 @retval FALSE If the default address is acquired from DHCP.\r
2772\r
2773**/\r
da1d0201 2774BOOLEAN\r
2775NetLibDefaultAddressIsStatic (\r
2776 IN EFI_HANDLE Controller\r
2777 )\r
2778{\r
63886849 2779 EFI_STATUS Status;\r
6c5c70d6 2780 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;\r
d1102dba 2781 UINTN DataSize;\r
6c5c70d6 2782 EFI_IP4_CONFIG2_POLICY Policy;\r
63886849 2783 BOOLEAN IsStatic;\r
da1d0201 2784\r
6c5c70d6 2785 Ip4Config2 = NULL;\r
d1102dba 2786\r
6c5c70d6 2787 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);\r
2788\r
2789 IsStatic = TRUE;\r
1dc1b43f 2790\r
63886849 2791 //\r
6c5c70d6 2792 // Get Ip4Config2 policy.\r
63886849 2793 //\r
6c5c70d6 2794 Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);\r
63886849 2795 if (EFI_ERROR (Status)) {\r
2796 goto ON_EXIT;\r
da1d0201 2797 }\r
2798\r
6c5c70d6 2799 Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypePolicy, &DataSize, &Policy);\r
da1d0201 2800 if (EFI_ERROR (Status)) {\r
2801 goto ON_EXIT;\r
2802 }\r
d1102dba 2803\r
6c5c70d6 2804 IsStatic = (BOOLEAN) (Policy == Ip4Config2PolicyStatic);\r
1204fe83 2805\r
da1d0201 2806ON_EXIT:\r
d1102dba 2807\r
da1d0201 2808 return IsStatic;\r
2809}\r
2810\r
2811/**\r
2812 Create an IPv4 device path node.\r
1204fe83 2813\r
cf4a8fa4
WF
2814 If Node is NULL, then ASSERT().\r
2815\r
b9008c87 2816 The header type of IPv4 device path node is MESSAGING_DEVICE_PATH.\r
2817 The header subtype of IPv4 device path node is MSG_IPv4_DP.\r
b9008c87 2818 Get other info from parameters to make up the whole IPv4 device path node.\r
da1d0201 2819\r
3e7104c2 2820 @param[in, out] Node Pointer to the IPv4 device path node.\r
f6b7393c 2821 @param[in] Controller The controller handle.\r
3e7104c2 2822 @param[in] LocalIp The local IPv4 address.\r
2823 @param[in] LocalPort The local port.\r
2824 @param[in] RemoteIp The remote IPv4 address.\r
2825 @param[in] RemotePort The remote port.\r
2826 @param[in] Protocol The protocol type in the IP header.\r
2827 @param[in] UseDefaultAddress Whether this instance is using default address or not.\r
da1d0201 2828\r
da1d0201 2829**/\r
2830VOID\r
7b414b4e 2831EFIAPI\r
da1d0201 2832NetLibCreateIPv4DPathNode (\r
2833 IN OUT IPv4_DEVICE_PATH *Node,\r
2834 IN EFI_HANDLE Controller,\r
2835 IN IP4_ADDR LocalIp,\r
2836 IN UINT16 LocalPort,\r
2837 IN IP4_ADDR RemoteIp,\r
2838 IN UINT16 RemotePort,\r
2839 IN UINT16 Protocol,\r
2840 IN BOOLEAN UseDefaultAddress\r
2841 )\r
2842{\r
cf4a8fa4
WF
2843 ASSERT (Node != NULL);\r
2844\r
da1d0201 2845 Node->Header.Type = MESSAGING_DEVICE_PATH;\r
2846 Node->Header.SubType = MSG_IPv4_DP;\r
501793fa 2847 SetDevicePathNodeLength (&Node->Header, sizeof (IPv4_DEVICE_PATH));\r
da1d0201 2848\r
e48e37fc 2849 CopyMem (&Node->LocalIpAddress, &LocalIp, sizeof (EFI_IPv4_ADDRESS));\r
2850 CopyMem (&Node->RemoteIpAddress, &RemoteIp, sizeof (EFI_IPv4_ADDRESS));\r
da1d0201 2851\r
2852 Node->LocalPort = LocalPort;\r
2853 Node->RemotePort = RemotePort;\r
2854\r
2855 Node->Protocol = Protocol;\r
2856\r
2857 if (!UseDefaultAddress) {\r
2858 Node->StaticIpAddress = TRUE;\r
2859 } else {\r
2860 Node->StaticIpAddress = NetLibDefaultAddressIsStatic (Controller);\r
2861 }\r
501793fa
RN
2862\r
2863 //\r
2864 // Set the Gateway IP address to default value 0:0:0:0.\r
2865 // Set the Subnet mask to default value 255:255:255:0.\r
2866 //\r
2867 ZeroMem (&Node->GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS));\r
2868 SetMem (&Node->SubnetMask, sizeof (EFI_IPv4_ADDRESS), 0xff);\r
2869 Node->SubnetMask.Addr[3] = 0;\r
da1d0201 2870}\r
2871\r
f6b7393c 2872/**\r
2873 Create an IPv6 device path node.\r
1204fe83 2874\r
cf4a8fa4
WF
2875 If Node is NULL, then ASSERT().\r
2876 If LocalIp is NULL, then ASSERT().\r
2877 If RemoteIp is NULL, then ASSERT().\r
2878\r
f6b7393c 2879 The header type of IPv6 device path node is MESSAGING_DEVICE_PATH.\r
2880 The header subtype of IPv6 device path node is MSG_IPv6_DP.\r
2881 Get other info from parameters to make up the whole IPv6 device path node.\r
2882\r
2883 @param[in, out] Node Pointer to the IPv6 device path node.\r
2884 @param[in] Controller The controller handle.\r
2885 @param[in] LocalIp The local IPv6 address.\r
2886 @param[in] LocalPort The local port.\r
2887 @param[in] RemoteIp The remote IPv6 address.\r
2888 @param[in] RemotePort The remote port.\r
2889 @param[in] Protocol The protocol type in the IP header.\r
2890\r
2891**/\r
2892VOID\r
2893EFIAPI\r
2894NetLibCreateIPv6DPathNode (\r
2895 IN OUT IPv6_DEVICE_PATH *Node,\r
2896 IN EFI_HANDLE Controller,\r
2897 IN EFI_IPv6_ADDRESS *LocalIp,\r
2898 IN UINT16 LocalPort,\r
2899 IN EFI_IPv6_ADDRESS *RemoteIp,\r
2900 IN UINT16 RemotePort,\r
2901 IN UINT16 Protocol\r
2902 )\r
2903{\r
cf4a8fa4
WF
2904 ASSERT (Node != NULL && LocalIp != NULL && RemoteIp != NULL);\r
2905\r
f6b7393c 2906 Node->Header.Type = MESSAGING_DEVICE_PATH;\r
2907 Node->Header.SubType = MSG_IPv6_DP;\r
2908 SetDevicePathNodeLength (&Node->Header, sizeof (IPv6_DEVICE_PATH));\r
2909\r
2910 CopyMem (&Node->LocalIpAddress, LocalIp, sizeof (EFI_IPv6_ADDRESS));\r
2911 CopyMem (&Node->RemoteIpAddress, RemoteIp, sizeof (EFI_IPv6_ADDRESS));\r
2912\r
2913 Node->LocalPort = LocalPort;\r
2914 Node->RemotePort = RemotePort;\r
2915\r
2916 Node->Protocol = Protocol;\r
501793fa
RN
2917\r
2918 //\r
2919 // Set default value to IPAddressOrigin, PrefixLength.\r
2920 // Set the Gateway IP address to unspecified address.\r
2921 //\r
2922 Node->IpAddressOrigin = 0;\r
2923 Node->PrefixLength = IP6_PREFIX_LENGTH;\r
2924 ZeroMem (&Node->GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS));\r
f6b7393c 2925}\r
da1d0201 2926\r
2927/**\r
2928 Find the UNDI/SNP handle from controller and protocol GUID.\r
1204fe83 2929\r
cf4a8fa4
WF
2930 If ProtocolGuid is NULL, then ASSERT().\r
2931\r
da1d0201 2932 For example, IP will open a MNP child to transmit/receive\r
2933 packets, when MNP is stopped, IP should also be stopped. IP\r
2934 needs to find its own private data which is related the IP's\r
2935 service binding instance that is install on UNDI/SNP handle.\r
2936 Now, the controller is either a MNP or ARP child handle. But\r
2937 IP opens these handle BY_DRIVER, use that info, we can get the\r
2938 UNDI/SNP handle.\r
2939\r
3e7104c2 2940 @param[in] Controller Then protocol handle to check.\r
2941 @param[in] ProtocolGuid The protocol that is related with the handle.\r
da1d0201 2942\r
3e7104c2 2943 @return The UNDI/SNP handle or NULL for errors.\r
da1d0201 2944\r
2945**/\r
2946EFI_HANDLE\r
7b414b4e 2947EFIAPI\r
da1d0201 2948NetLibGetNicHandle (\r
2949 IN EFI_HANDLE Controller,\r
2950 IN EFI_GUID *ProtocolGuid\r
2951 )\r
2952{\r
2953 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenBuffer;\r
2954 EFI_HANDLE Handle;\r
2955 EFI_STATUS Status;\r
2956 UINTN OpenCount;\r
2957 UINTN Index;\r
2958\r
cf4a8fa4
WF
2959 ASSERT (ProtocolGuid != NULL);\r
2960\r
da1d0201 2961 Status = gBS->OpenProtocolInformation (\r
2962 Controller,\r
2963 ProtocolGuid,\r
2964 &OpenBuffer,\r
2965 &OpenCount\r
2966 );\r
2967\r
2968 if (EFI_ERROR (Status)) {\r
2969 return NULL;\r
2970 }\r
2971\r
2972 Handle = NULL;\r
2973\r
2974 for (Index = 0; Index < OpenCount; Index++) {\r
e2851998 2975 if ((OpenBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {\r
da1d0201 2976 Handle = OpenBuffer[Index].ControllerHandle;\r
2977 break;\r
2978 }\r
2979 }\r
2980\r
2981 gBS->FreePool (OpenBuffer);\r
2982 return Handle;\r
2983}\r
e4ef0031 2984\r
2985/**\r
2986 Convert one Null-terminated ASCII string (decimal dotted) to EFI_IPv4_ADDRESS.\r
2987\r
2988 @param[in] String The pointer to the Ascii string.\r
2989 @param[out] Ip4Address The pointer to the converted IPv4 address.\r
2990\r
dd29f3ed 2991 @retval EFI_SUCCESS Convert to IPv4 address successfully.\r
e4ef0031 2992 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip4Address is NULL.\r
2993\r
2994**/\r
2995EFI_STATUS\r
e798cd87 2996EFIAPI\r
e4ef0031 2997NetLibAsciiStrToIp4 (\r
2998 IN CONST CHAR8 *String,\r
2999 OUT EFI_IPv4_ADDRESS *Ip4Address\r
3000 )\r
3001{\r
9f5ca5ef
RN
3002 RETURN_STATUS Status;\r
3003 CHAR8 *EndPointer;\r
e4ef0031 3004\r
9f5ca5ef
RN
3005 Status = AsciiStrToIpv4Address (String, &EndPointer, Ip4Address, NULL);\r
3006 if (RETURN_ERROR (Status) || (*EndPointer != '\0')) {\r
e4ef0031 3007 return EFI_INVALID_PARAMETER;\r
9f5ca5ef
RN
3008 } else {\r
3009 return EFI_SUCCESS;\r
e4ef0031 3010 }\r
e4ef0031 3011}\r
3012\r
3013\r
3014/**\r
3015 Convert one Null-terminated ASCII string to EFI_IPv6_ADDRESS. The format of the\r
3b28e744 3016 string is defined in RFC 4291 - Text Representation of Addresses.\r
e4ef0031 3017\r
3018 @param[in] String The pointer to the Ascii string.\r
3019 @param[out] Ip6Address The pointer to the converted IPv6 address.\r
3020\r
dd29f3ed 3021 @retval EFI_SUCCESS Convert to IPv6 address successfully.\r
e4ef0031 3022 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.\r
3023\r
3024**/\r
3025EFI_STATUS\r
e798cd87 3026EFIAPI\r
e4ef0031 3027NetLibAsciiStrToIp6 (\r
3028 IN CONST CHAR8 *String,\r
3029 OUT EFI_IPv6_ADDRESS *Ip6Address\r
3030 )\r
3031{\r
9f5ca5ef
RN
3032 RETURN_STATUS Status;\r
3033 CHAR8 *EndPointer;\r
e4ef0031 3034\r
9f5ca5ef
RN
3035 Status = AsciiStrToIpv6Address (String, &EndPointer, Ip6Address, NULL);\r
3036 if (RETURN_ERROR (Status) || (*EndPointer != '\0')) {\r
e4ef0031 3037 return EFI_INVALID_PARAMETER;\r
9f5ca5ef
RN
3038 } else {\r
3039 return EFI_SUCCESS;\r
e4ef0031 3040 }\r
e4ef0031 3041}\r
3042\r
3043\r
3044/**\r
3045 Convert one Null-terminated Unicode string (decimal dotted) to EFI_IPv4_ADDRESS.\r
3046\r
3047 @param[in] String The pointer to the Ascii string.\r
3048 @param[out] Ip4Address The pointer to the converted IPv4 address.\r
3049\r
dd29f3ed 3050 @retval EFI_SUCCESS Convert to IPv4 address successfully.\r
e4ef0031 3051 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip4Address is NULL.\r
e4ef0031 3052\r
3053**/\r
3054EFI_STATUS\r
e798cd87 3055EFIAPI\r
e4ef0031 3056NetLibStrToIp4 (\r
3057 IN CONST CHAR16 *String,\r
3058 OUT EFI_IPv4_ADDRESS *Ip4Address\r
3059 )\r
3060{\r
9f5ca5ef
RN
3061 RETURN_STATUS Status;\r
3062 CHAR16 *EndPointer;\r
dd29f3ed 3063\r
9f5ca5ef
RN
3064 Status = StrToIpv4Address (String, &EndPointer, Ip4Address, NULL);\r
3065 if (RETURN_ERROR (Status) || (*EndPointer != L'\0')) {\r
e4ef0031 3066 return EFI_INVALID_PARAMETER;\r
9f5ca5ef
RN
3067 } else {\r
3068 return EFI_SUCCESS;\r
e4ef0031 3069 }\r
e4ef0031 3070}\r
3071\r
3072\r
3073/**\r
3074 Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS. The format of\r
3b28e744 3075 the string is defined in RFC 4291 - Text Representation of Addresses.\r
e4ef0031 3076\r
3077 @param[in] String The pointer to the Ascii string.\r
3078 @param[out] Ip6Address The pointer to the converted IPv6 address.\r
3079\r
dd29f3ed 3080 @retval EFI_SUCCESS Convert to IPv6 address successfully.\r
e4ef0031 3081 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.\r
e4ef0031 3082\r
3083**/\r
3084EFI_STATUS\r
e798cd87 3085EFIAPI\r
e4ef0031 3086NetLibStrToIp6 (\r
3087 IN CONST CHAR16 *String,\r
3088 OUT EFI_IPv6_ADDRESS *Ip6Address\r
dd29f3ed 3089 )\r
e4ef0031 3090{\r
9f5ca5ef
RN
3091 RETURN_STATUS Status;\r
3092 CHAR16 *EndPointer;\r
dd29f3ed 3093\r
9f5ca5ef
RN
3094 Status = StrToIpv6Address (String, &EndPointer, Ip6Address, NULL);\r
3095 if (RETURN_ERROR (Status) || (*EndPointer != L'\0')) {\r
e4ef0031 3096 return EFI_INVALID_PARAMETER;\r
9f5ca5ef
RN
3097 } else {\r
3098 return EFI_SUCCESS;\r
e4ef0031 3099 }\r
e4ef0031 3100}\r
3101\r
3102/**\r
3103 Convert one Null-terminated Unicode string to EFI_IPv6_ADDRESS and prefix length.\r
3b28e744 3104 The format of the string is defined in RFC 4291 - Text Representation of Addresses\r
e4ef0031 3105 Prefixes: ipv6-address/prefix-length.\r
3106\r
3107 @param[in] String The pointer to the Ascii string.\r
3108 @param[out] Ip6Address The pointer to the converted IPv6 address.\r
3109 @param[out] PrefixLength The pointer to the converted prefix length.\r
3110\r
dd29f3ed 3111 @retval EFI_SUCCESS Convert to IPv6 address successfully.\r
e4ef0031 3112 @retval EFI_INVALID_PARAMETER The string is mal-formated or Ip6Address is NULL.\r
e4ef0031 3113\r
3114**/\r
3115EFI_STATUS\r
e798cd87 3116EFIAPI\r
e4ef0031 3117NetLibStrToIp6andPrefix (\r
3118 IN CONST CHAR16 *String,\r
3119 OUT EFI_IPv6_ADDRESS *Ip6Address,\r
3120 OUT UINT8 *PrefixLength\r
dd29f3ed 3121 )\r
e4ef0031 3122{\r
9f5ca5ef
RN
3123 RETURN_STATUS Status;\r
3124 CHAR16 *EndPointer;\r
e4ef0031 3125\r
9f5ca5ef
RN
3126 Status = StrToIpv6Address (String, &EndPointer, Ip6Address, PrefixLength);\r
3127 if (RETURN_ERROR (Status) || (*EndPointer != L'\0')) {\r
3128 return EFI_INVALID_PARAMETER;\r
e4ef0031 3129 } else {\r
9f5ca5ef 3130 return EFI_SUCCESS;\r
e4ef0031 3131 }\r
e4ef0031 3132}\r
3133\r
216f7970 3134/**\r
3135\r
3136 Convert one EFI_IPv6_ADDRESS to Null-terminated Unicode string.\r
3137 The text representation of address is defined in RFC 4291.\r
d1102dba 3138\r
216f7970 3139 @param[in] Ip6Address The pointer to the IPv6 address.\r
3140 @param[out] String The buffer to return the converted string.\r
3141 @param[in] StringSize The length in bytes of the input String.\r
d1102dba 3142\r
216f7970 3143 @retval EFI_SUCCESS Convert to string successfully.\r
3144 @retval EFI_INVALID_PARAMETER The input parameter is invalid.\r
d1102dba 3145 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small for the result. BufferSize has been\r
216f7970 3146 updated with the size needed to complete the request.\r
3147**/\r
3148EFI_STATUS\r
3149EFIAPI\r
3150NetLibIp6ToStr (\r
3151 IN EFI_IPv6_ADDRESS *Ip6Address,\r
3152 OUT CHAR16 *String,\r
3153 IN UINTN StringSize\r
3154 )\r
3155{\r
3156 UINT16 Ip6Addr[8];\r
3157 UINTN Index;\r
3158 UINTN LongestZerosStart;\r
3159 UINTN LongestZerosLength;\r
3160 UINTN CurrentZerosStart;\r
3161 UINTN CurrentZerosLength;\r
3162 CHAR16 Buffer[sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];\r
3163 CHAR16 *Ptr;\r
3164\r
3165 if (Ip6Address == NULL || String == NULL || StringSize == 0) {\r
3166 return EFI_INVALID_PARAMETER;\r
3167 }\r
3168\r
3169 //\r
3170 // Convert the UINT8 array to an UINT16 array for easy handling.\r
d1102dba 3171 //\r
216f7970 3172 ZeroMem (Ip6Addr, sizeof (Ip6Addr));\r
3173 for (Index = 0; Index < 16; Index++) {\r
3174 Ip6Addr[Index / 2] |= (Ip6Address->Addr[Index] << ((1 - (Index % 2)) << 3));\r
3175 }\r
57b301b5 3176\r
216f7970 3177 //\r
3178 // Find the longest zeros and mark it.\r
3179 //\r
3180 CurrentZerosStart = DEFAULT_ZERO_START;\r
3181 CurrentZerosLength = 0;\r
3182 LongestZerosStart = DEFAULT_ZERO_START;\r
3183 LongestZerosLength = 0;\r
3184 for (Index = 0; Index < 8; Index++) {\r
3185 if (Ip6Addr[Index] == 0) {\r
3186 if (CurrentZerosStart == DEFAULT_ZERO_START) {\r
3187 CurrentZerosStart = Index;\r
3188 CurrentZerosLength = 1;\r
3189 } else {\r
3190 CurrentZerosLength++;\r
3191 }\r
3192 } else {\r
3193 if (CurrentZerosStart != DEFAULT_ZERO_START) {\r
3194 if (CurrentZerosLength > 2 && (LongestZerosStart == (DEFAULT_ZERO_START) || CurrentZerosLength > LongestZerosLength)) {\r
3195 LongestZerosStart = CurrentZerosStart;\r
3196 LongestZerosLength = CurrentZerosLength;\r
3197 }\r
3198 CurrentZerosStart = DEFAULT_ZERO_START;\r
3199 CurrentZerosLength = 0;\r
3200 }\r
3201 }\r
3202 }\r
d1102dba 3203\r
216f7970 3204 if (CurrentZerosStart != DEFAULT_ZERO_START && CurrentZerosLength > 2) {\r
3205 if (LongestZerosStart == DEFAULT_ZERO_START || LongestZerosLength < CurrentZerosLength) {\r
3206 LongestZerosStart = CurrentZerosStart;\r
3207 LongestZerosLength = CurrentZerosLength;\r
3208 }\r
3209 }\r
3210\r
3211 Ptr = Buffer;\r
3212 for (Index = 0; Index < 8; Index++) {\r
3213 if (LongestZerosStart != DEFAULT_ZERO_START && Index >= LongestZerosStart && Index < LongestZerosStart + LongestZerosLength) {\r
3214 if (Index == LongestZerosStart) {\r
3215 *Ptr++ = L':';\r
3216 }\r
3217 continue;\r
3218 }\r
3219 if (Index != 0) {\r
3220 *Ptr++ = L':';\r
3221 }\r
3222 Ptr += UnicodeSPrint(Ptr, 10, L"%x", Ip6Addr[Index]);\r
3223 }\r
d1102dba 3224\r
216f7970 3225 if (LongestZerosStart != DEFAULT_ZERO_START && LongestZerosStart + LongestZerosLength == 8) {\r
3226 *Ptr++ = L':';\r
3227 }\r
3228 *Ptr = L'\0';\r
3229\r
3230 if ((UINTN)Ptr - (UINTN)Buffer > StringSize) {\r
3231 return EFI_BUFFER_TOO_SMALL;\r
3232 }\r
3233\r
206b5f51 3234 StrCpyS (String, StringSize / sizeof (CHAR16), Buffer);\r
216f7970 3235\r
3236 return EFI_SUCCESS;\r
3237}\r
57b301b5 3238\r
3239/**\r
3240 This function obtains the system guid from the smbios table.\r
3241\r
cf4a8fa4
WF
3242 If SystemGuid is NULL, then ASSERT().\r
3243\r
57b301b5 3244 @param[out] SystemGuid The pointer of the returned system guid.\r
3245\r
3246 @retval EFI_SUCCESS Successfully obtained the system guid.\r
3247 @retval EFI_NOT_FOUND Did not find the SMBIOS table.\r
3248\r
3249**/\r
3250EFI_STATUS\r
3251EFIAPI\r
3252NetLibGetSystemGuid (\r
3253 OUT EFI_GUID *SystemGuid\r
3254 )\r
3255{\r
33ecfa8a
SEHM
3256 EFI_STATUS Status;\r
3257 SMBIOS_TABLE_ENTRY_POINT *SmbiosTable;\r
3258 SMBIOS_TABLE_3_0_ENTRY_POINT *Smbios30Table;\r
3259 SMBIOS_STRUCTURE_POINTER Smbios;\r
3260 SMBIOS_STRUCTURE_POINTER SmbiosEnd;\r
3261 CHAR8 *String;\r
57b301b5 3262\r
cf4a8fa4
WF
3263 ASSERT (SystemGuid != NULL);\r
3264\r
57b301b5 3265 SmbiosTable = NULL;\r
33ecfa8a
SEHM
3266 Status = EfiGetSystemConfigurationTable (&gEfiSmbios3TableGuid, (VOID **) &Smbios30Table);\r
3267 if (!(EFI_ERROR (Status) || Smbios30Table == NULL)) {\r
3268 Smbios.Hdr = (SMBIOS_STRUCTURE *) (UINTN) Smbios30Table->TableAddress;\r
3269 SmbiosEnd.Raw = (UINT8 *) (UINTN) (Smbios30Table->TableAddress + Smbios30Table->TableMaximumSize);\r
3270 } else {\r
3271 Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SmbiosTable);\r
3272 if (EFI_ERROR (Status) || SmbiosTable == NULL) {\r
3273 return EFI_NOT_FOUND;\r
3274 }\r
3275 Smbios.Hdr = (SMBIOS_STRUCTURE *) (UINTN) SmbiosTable->TableAddress;\r
16f69227 3276 SmbiosEnd.Raw = (UINT8 *) ((UINTN) SmbiosTable->TableAddress + SmbiosTable->TableLength);\r
57b301b5 3277 }\r
3278\r
57b301b5 3279 do {\r
3280 if (Smbios.Hdr->Type == 1) {\r
3281 if (Smbios.Hdr->Length < 0x19) {\r
3282 //\r
3283 // Older version did not support UUID.\r
3284 //\r
3285 return EFI_NOT_FOUND;\r
3286 }\r
d1102dba 3287\r
57b301b5 3288 //\r
3289 // SMBIOS tables are byte packed so we need to do a byte copy to\r
3290 // prevend alignment faults on Itanium-based platform.\r
3291 //\r
3292 CopyMem (SystemGuid, &Smbios.Type1->Uuid, sizeof (EFI_GUID));\r
3293 return EFI_SUCCESS;\r
3294 }\r
3295\r
3296 //\r
3297 // Go to the next SMBIOS structure. Each SMBIOS structure may include 2 parts:\r
3298 // 1. Formatted section; 2. Unformatted string section. So, 2 steps are needed\r
3299 // to skip one SMBIOS structure.\r
3300 //\r
d1102dba 3301\r
57b301b5 3302 //\r
3303 // Step 1: Skip over formatted section.\r
3304 //\r
3305 String = (CHAR8 *) (Smbios.Raw + Smbios.Hdr->Length);\r
d1102dba 3306\r
57b301b5 3307 //\r
3308 // Step 2: Skip over unformated string section.\r
3309 //\r
3310 do {\r
3311 //\r
3312 // Each string is terminated with a NULL(00h) BYTE and the sets of strings\r
3313 // is terminated with an additional NULL(00h) BYTE.\r
3314 //\r
3315 for ( ; *String != 0; String++) {\r
3316 }\r
3317\r
3318 if (*(UINT8*)++String == 0) {\r
3319 //\r
3320 // Pointer to the next SMBIOS structure.\r
3321 //\r
3322 Smbios.Raw = (UINT8 *)++String;\r
3323 break;\r
d1102dba 3324 }\r
57b301b5 3325 } while (TRUE);\r
3326 } while (Smbios.Raw < SmbiosEnd.Raw);\r
3327 return EFI_NOT_FOUND;\r
3328}\r
dba6e9a9
JW
3329\r
3330/**\r
cf4a8fa4
WF
3331 Create Dns QName according the queried domain name.\r
3332\r
3333 If DomainName is NULL, then ASSERT().\r
d1102dba
LG
3334\r
3335 QName is a domain name represented as a sequence of labels,\r
3336 where each label consists of a length octet followed by that\r
3337 number of octets. The QName terminates with the zero\r
3338 length octet for the null label of the root. Caller should\r
dba6e9a9
JW
3339 take responsibility to free the buffer in returned pointer.\r
3340\r
d1102dba 3341 @param DomainName The pointer to the queried domain name string.\r
dba6e9a9
JW
3342\r
3343 @retval NULL Failed to fill QName.\r
3344 @return QName filled successfully.\r
d1102dba
LG
3345\r
3346**/\r
dba6e9a9
JW
3347CHAR8 *\r
3348EFIAPI\r
3349NetLibCreateDnsQName (\r
3350 IN CHAR16 *DomainName\r
3351 )\r
3352{\r
3353 CHAR8 *QueryName;\r
3354 UINTN QueryNameSize;\r
3355 CHAR8 *Header;\r
3356 CHAR8 *Tail;\r
3357 UINTN Len;\r
3358 UINTN Index;\r
3359\r
cf4a8fa4
WF
3360 ASSERT (DomainName != NULL);\r
3361\r
dba6e9a9
JW
3362 QueryName = NULL;\r
3363 QueryNameSize = 0;\r
3364 Header = NULL;\r
3365 Tail = NULL;\r
3366\r
3367 //\r
d1102dba 3368 // One byte for first label length, one byte for terminated length zero.\r
dba6e9a9
JW
3369 //\r
3370 QueryNameSize = StrLen (DomainName) + 2;\r
d1102dba 3371\r
dba6e9a9
JW
3372 if (QueryNameSize > DNS_MAX_NAME_SIZE) {\r
3373 return NULL;\r
3374 }\r
3375\r
3376 QueryName = AllocateZeroPool (QueryNameSize);\r
3377 if (QueryName == NULL) {\r
3378 return NULL;\r
3379 }\r
d1102dba 3380\r
dba6e9a9
JW
3381 Header = QueryName;\r
3382 Tail = Header + 1;\r
3383 Len = 0;\r
3384 for (Index = 0; DomainName[Index] != 0; Index++) {\r
3385 *Tail = (CHAR8) DomainName[Index];\r
3386 if (*Tail == '.') {\r
3387 *Header = (CHAR8) Len;\r
3388 Header = Tail;\r
3389 Tail ++;\r
3390 Len = 0;\r
3391 } else {\r
3392 Tail++;\r
3393 Len++;\r
3394 }\r
3395 }\r
3396 *Header = (CHAR8) Len;\r
3397 *Tail = 0;\r
3398\r
3399 return QueryName;\r
3b28e744 3400}\r