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