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