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