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