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