added comments for CAPSULE_HOB_INFO in CapsuleVendor.h (MdeModuleModulePkg).
[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
da1d0201 84/**\r
b9008c87 85 Return the length of the mask. \r
86 \r
87 Return the length of the mask, the correct value is from 0 to 32.\r
88 If the mask is invalid, return the invalid length 33, which is IP4_MASK_NUM.\r
da1d0201 89 NetMask is in the host byte order.\r
90\r
3e7104c2 91 @param[in] NetMask The netmask to get the length from.\r
da1d0201 92\r
b9008c87 93 @return The length of the netmask, IP4_MASK_NUM if the mask is invalid.\r
3e7104c2 94 \r
da1d0201 95**/\r
96INTN\r
7b414b4e 97EFIAPI\r
da1d0201 98NetGetMaskLength (\r
99 IN IP4_ADDR NetMask\r
100 )\r
101{\r
102 INTN Index;\r
103\r
104 for (Index = 0; Index < IP4_MASK_NUM; Index++) {\r
2a86ff1c 105 if (NetMask == gIp4AllMasks[Index]) {\r
da1d0201 106 break;\r
107 }\r
108 }\r
109\r
110 return Index;\r
111}\r
112\r
113\r
114\r
115/**\r
b9008c87 116 Return the class of the IP address, such as class A, B, C.\r
da1d0201 117 Addr is in host byte order.\r
b9008c87 118 \r
119 The address of class A starts with 0.\r
120 If the address belong to class A, return IP4_ADDR_CLASSA.\r
121 The address of class B starts with 10. \r
122 If the address belong to class B, return IP4_ADDR_CLASSB.\r
123 The address of class C starts with 110. \r
124 If the address belong to class C, return IP4_ADDR_CLASSC.\r
125 The address of class D starts with 1110. \r
126 If the address belong to class D, return IP4_ADDR_CLASSD.\r
127 The address of class E starts with 1111.\r
128 If the address belong to class E, return IP4_ADDR_CLASSE.\r
da1d0201 129\r
b9008c87 130 \r
3e7104c2 131 @param[in] Addr The address to get the class from.\r
da1d0201 132\r
3e7104c2 133 @return IP address class, such as IP4_ADDR_CLASSA.\r
da1d0201 134\r
135**/\r
136INTN\r
7b414b4e 137EFIAPI\r
da1d0201 138NetGetIpClass (\r
139 IN IP4_ADDR Addr\r
140 )\r
141{\r
142 UINT8 ByteOne;\r
143\r
144 ByteOne = (UINT8) (Addr >> 24);\r
145\r
146 if ((ByteOne & 0x80) == 0) {\r
147 return IP4_ADDR_CLASSA;\r
148\r
149 } else if ((ByteOne & 0xC0) == 0x80) {\r
150 return IP4_ADDR_CLASSB;\r
151\r
152 } else if ((ByteOne & 0xE0) == 0xC0) {\r
153 return IP4_ADDR_CLASSC;\r
154\r
155 } else if ((ByteOne & 0xF0) == 0xE0) {\r
156 return IP4_ADDR_CLASSD;\r
157\r
158 } else {\r
159 return IP4_ADDR_CLASSE;\r
160\r
161 }\r
162}\r
163\r
164\r
165/**\r
166 Check whether the IP is a valid unicast address according to\r
b9008c87 167 the netmask. If NetMask is zero, use the IP address's class to get the default mask.\r
168 \r
169 If Ip is 0, IP is not a valid unicast address.\r
170 Class D address is used for multicasting and class E address is reserved for future. If Ip\r
171 belongs to class D or class E, IP is not a valid unicast address. \r
172 If all bits of the host address of IP are 0 or 1, IP is also not a valid unicast address.\r
da1d0201 173\r
3e7104c2 174 @param[in] Ip The IP to check against.\r
175 @param[in] NetMask The mask of the IP.\r
da1d0201 176\r
3e7104c2 177 @return TRUE if IP is a valid unicast address on the network, otherwise FALSE.\r
da1d0201 178\r
179**/\r
180BOOLEAN\r
7b414b4e 181EFIAPI\r
da1d0201 182Ip4IsUnicast (\r
183 IN IP4_ADDR Ip,\r
184 IN IP4_ADDR NetMask\r
185 )\r
186{\r
187 INTN Class;\r
188\r
189 Class = NetGetIpClass (Ip);\r
190\r
191 if ((Ip == 0) || (Class >= IP4_ADDR_CLASSD)) {\r
192 return FALSE;\r
193 }\r
194\r
195 if (NetMask == 0) {\r
2a86ff1c 196 NetMask = gIp4AllMasks[Class << 3];\r
da1d0201 197 }\r
198\r
199 if (((Ip &~NetMask) == ~NetMask) || ((Ip &~NetMask) == 0)) {\r
200 return FALSE;\r
201 }\r
202\r
203 return TRUE;\r
204}\r
205\r
fb115c61 206/**\r
207 Check whether the incoming IPv6 address is a valid unicast address.\r
208\r
209 If the address is a multicast address has binary 0xFF at the start, it is not\r
210 a valid unicast address. If the address is unspecified ::, it is not a valid\r
211 unicast address to be assigned to any node. If the address is loopback address\r
212 ::1, it is also not a valid unicast address to be assigned to any physical\r
213 interface. \r
214\r
215 @param[in] Ip6 The IPv6 address to check against.\r
216\r
217 @return TRUE if Ip6 is a valid unicast address on the network, otherwise FALSE.\r
218\r
219**/ \r
220BOOLEAN\r
221Ip6IsValidUnicast (\r
222 IN EFI_IPv6_ADDRESS *Ip6\r
223 ) \r
224{\r
b45b45b2 225 UINT8 Byte;\r
226 UINT8 Index;\r
fb115c61 227 \r
228 if (Ip6->Addr[0] == 0xFF) {\r
229 return FALSE;\r
230 }\r
231\r
b45b45b2 232 for (Index = 0; Index < 15; Index++) {\r
233 if (Ip6->Addr[Index] != 0) {\r
fb115c61 234 return TRUE;\r
235 }\r
236 }\r
237\r
b45b45b2 238 Byte = Ip6->Addr[Index];\r
fb115c61 239\r
b45b45b2 240 if (Byte == 0x0 || Byte == 0x1) {\r
fb115c61 241 return FALSE;\r
242 }\r
243\r
244 return TRUE; \r
245}\r
da1d0201 246\r
b45b45b2 247/**\r
248 Switches the endianess of an IPv6 address\r
249\r
250 This function swaps the bytes in a 128-bit IPv6 address to switch the value\r
251 from little endian to big endian or vice versa. The byte swapped value is\r
252 returned.\r
253\r
254 @param Ip6 Points to an IPv6 address\r
255\r
256 @return The byte swapped IPv6 address.\r
257\r
258**/\r
259EFI_IPv6_ADDRESS *\r
260Ip6Swap128 (\r
261 EFI_IPv6_ADDRESS *Ip6\r
262 )\r
263{\r
264 UINT64 High;\r
265 UINT64 Low;\r
266\r
267 CopyMem (&High, Ip6, sizeof (UINT64));\r
268 CopyMem (&Low, &Ip6->Addr[8], sizeof (UINT64));\r
269\r
270 High = SwapBytes64 (High);\r
271 Low = SwapBytes64 (Low);\r
272\r
273 CopyMem (Ip6, &Low, sizeof (UINT64));\r
274 CopyMem (&Ip6->Addr[8], &High, sizeof (UINT64));\r
275\r
276 return Ip6;\r
277}\r
278\r
da1d0201 279/**\r
280 Initialize a random seed using current time.\r
b9008c87 281 \r
282 Get current time first. Then initialize a random seed based on some basic \r
283 mathematics operation on the hour, day, minute, second, nanosecond and year \r
284 of the current time.\r
285 \r
da1d0201 286 @return The random seed initialized with current time.\r
287\r
288**/\r
289UINT32\r
7b414b4e 290EFIAPI\r
da1d0201 291NetRandomInitSeed (\r
292 VOID\r
293 )\r
294{\r
295 EFI_TIME Time;\r
296 UINT32 Seed;\r
297\r
298 gRT->GetTime (&Time, NULL);\r
36ee91ca 299 Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second);\r
da1d0201 300 Seed ^= Time.Nanosecond;\r
301 Seed ^= Time.Year << 7;\r
302\r
303 return Seed;\r
304}\r
305\r
306\r
307/**\r
b9008c87 308 Extract a UINT32 from a byte stream.\r
309 \r
310 Copy a UINT32 from a byte stream, then converts it from Network \r
311 byte order to host byte order. Use this function to avoid alignment error.\r
da1d0201 312\r
3e7104c2 313 @param[in] Buf The buffer to extract the UINT32.\r
da1d0201 314\r
315 @return The UINT32 extracted.\r
316\r
317**/\r
318UINT32\r
7b414b4e 319EFIAPI\r
da1d0201 320NetGetUint32 (\r
321 IN UINT8 *Buf\r
322 )\r
323{\r
324 UINT32 Value;\r
325\r
e48e37fc 326 CopyMem (&Value, Buf, sizeof (UINT32));\r
da1d0201 327 return NTOHL (Value);\r
328}\r
329\r
330\r
331/**\r
b9008c87 332 Put a UINT32 to the byte stream in network byte order. \r
333 \r
334 Converts a UINT32 from host byte order to network byte order. Then copy it to the \r
335 byte stream.\r
da1d0201 336\r
3e7104c2 337 @param[in, out] Buf The buffer to put the UINT32.\r
338 @param[in] Data The data to put.\r
339 \r
da1d0201 340**/\r
341VOID\r
7b414b4e 342EFIAPI\r
da1d0201 343NetPutUint32 (\r
3e7104c2 344 IN OUT UINT8 *Buf,\r
345 IN UINT32 Data\r
da1d0201 346 )\r
347{\r
348 Data = HTONL (Data);\r
e48e37fc 349 CopyMem (Buf, &Data, sizeof (UINT32));\r
da1d0201 350}\r
351\r
352\r
353/**\r
b9008c87 354 Remove the first node entry on the list, and return the removed node entry.\r
355 \r
356 Removes the first node Entry from a doubly linked list. It is up to the caller of\r
357 this function to release the memory used by the first node if that is required. On\r
358 exit, the removed node is returned. \r
359\r
360 If Head is NULL, then ASSERT().\r
361 If Head was not initialized, then ASSERT().\r
362 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the\r
363 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,\r
364 then ASSERT(). \r
da1d0201 365\r
3e7104c2 366 @param[in, out] Head The list header.\r
da1d0201 367\r
b9008c87 368 @return The first node entry that is removed from the list, NULL if the list is empty.\r
da1d0201 369\r
370**/\r
e48e37fc 371LIST_ENTRY *\r
7b414b4e 372EFIAPI\r
da1d0201 373NetListRemoveHead (\r
3e7104c2 374 IN OUT LIST_ENTRY *Head\r
da1d0201 375 )\r
376{\r
e48e37fc 377 LIST_ENTRY *First;\r
da1d0201 378\r
379 ASSERT (Head != NULL);\r
380\r
e48e37fc 381 if (IsListEmpty (Head)) {\r
da1d0201 382 return NULL;\r
383 }\r
384\r
385 First = Head->ForwardLink;\r
386 Head->ForwardLink = First->ForwardLink;\r
387 First->ForwardLink->BackLink = Head;\r
388\r
389 DEBUG_CODE (\r
e48e37fc 390 First->ForwardLink = (LIST_ENTRY *) NULL;\r
391 First->BackLink = (LIST_ENTRY *) NULL;\r
da1d0201 392 );\r
393\r
394 return First;\r
395}\r
396\r
397\r
398/**\r
b9008c87 399 Remove the last node entry on the list and and return the removed node entry.\r
400\r
401 Removes the last node entry from a doubly linked list. It is up to the caller of\r
402 this function to release the memory used by the first node if that is required. On\r
403 exit, the removed node is returned. \r
da1d0201 404\r
b9008c87 405 If Head is NULL, then ASSERT().\r
406 If Head was not initialized, then ASSERT().\r
407 If PcdMaximumLinkedListLength is not zero, and the number of nodes in the\r
408 linked list including the head node is greater than or equal to PcdMaximumLinkedListLength,\r
409 then ASSERT(). \r
410 \r
3e7104c2 411 @param[in, out] Head The list head.\r
da1d0201 412\r
b9008c87 413 @return The last node entry that is removed from the list, NULL if the list is empty.\r
da1d0201 414\r
415**/\r
e48e37fc 416LIST_ENTRY *\r
7b414b4e 417EFIAPI\r
da1d0201 418NetListRemoveTail (\r
3e7104c2 419 IN OUT LIST_ENTRY *Head\r
da1d0201 420 )\r
421{\r
e48e37fc 422 LIST_ENTRY *Last;\r
da1d0201 423\r
424 ASSERT (Head != NULL);\r
425\r
e48e37fc 426 if (IsListEmpty (Head)) {\r
da1d0201 427 return NULL;\r
428 }\r
429\r
430 Last = Head->BackLink;\r
431 Head->BackLink = Last->BackLink;\r
432 Last->BackLink->ForwardLink = Head;\r
433\r
434 DEBUG_CODE (\r
e48e37fc 435 Last->ForwardLink = (LIST_ENTRY *) NULL;\r
436 Last->BackLink = (LIST_ENTRY *) NULL;\r
da1d0201 437 );\r
438\r
439 return Last;\r
440}\r
441\r
442\r
443/**\r
b9008c87 444 Insert a new node entry after a designated node entry of a doubly linked list.\r
445 \r
446 Inserts a new node entry donated by NewEntry after the node entry donated by PrevEntry\r
447 of the doubly linked list.\r
448 \r
3e7104c2 449 @param[in, out] PrevEntry The previous entry to insert after.\r
450 @param[in, out] NewEntry The new entry to insert.\r
da1d0201 451\r
452**/\r
453VOID\r
7b414b4e 454EFIAPI\r
da1d0201 455NetListInsertAfter (\r
3e7104c2 456 IN OUT LIST_ENTRY *PrevEntry,\r
457 IN OUT LIST_ENTRY *NewEntry\r
da1d0201 458 )\r
459{\r
460 NewEntry->BackLink = PrevEntry;\r
461 NewEntry->ForwardLink = PrevEntry->ForwardLink;\r
462 PrevEntry->ForwardLink->BackLink = NewEntry;\r
463 PrevEntry->ForwardLink = NewEntry;\r
464}\r
465\r
466\r
467/**\r
b9008c87 468 Insert a new node entry before a designated node entry of a doubly linked list.\r
469 \r
470 Inserts a new node entry donated by NewEntry after the node entry donated by PostEntry\r
471 of the doubly linked list.\r
472 \r
3e7104c2 473 @param[in, out] PostEntry The entry to insert before.\r
474 @param[in, out] NewEntry The new entry to insert.\r
da1d0201 475\r
476**/\r
477VOID\r
7b414b4e 478EFIAPI\r
da1d0201 479NetListInsertBefore (\r
3e7104c2 480 IN OUT LIST_ENTRY *PostEntry,\r
481 IN OUT LIST_ENTRY *NewEntry\r
da1d0201 482 )\r
483{\r
484 NewEntry->ForwardLink = PostEntry;\r
485 NewEntry->BackLink = PostEntry->BackLink;\r
486 PostEntry->BackLink->ForwardLink = NewEntry;\r
487 PostEntry->BackLink = NewEntry;\r
488}\r
489\r
490\r
491/**\r
492 Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.\r
b9008c87 493 \r
494 Initialize the forward and backward links of two head nodes donated by Map->Used \r
495 and Map->Recycled of two doubly linked lists.\r
496 Initializes the count of the <Key, Value> pairs in the netmap to zero.\r
497 \r
498 If Map is NULL, then ASSERT().\r
8f5e6151 499 If the address of Map->Used is NULL, then ASSERT().\r
b9008c87 500 If the address of Map->Recycled is NULl, then ASSERT().\r
501 \r
3e7104c2 502 @param[in, out] Map The netmap to initialize.\r
da1d0201 503\r
504**/\r
505VOID\r
7b414b4e 506EFIAPI\r
da1d0201 507NetMapInit (\r
3e7104c2 508 IN OUT NET_MAP *Map\r
da1d0201 509 )\r
510{\r
511 ASSERT (Map != NULL);\r
512\r
e48e37fc 513 InitializeListHead (&Map->Used);\r
514 InitializeListHead (&Map->Recycled);\r
da1d0201 515 Map->Count = 0;\r
516}\r
517\r
518\r
519/**\r
520 To clean up the netmap, that is, release allocated memories.\r
b9008c87 521 \r
522 Removes all nodes of the Used doubly linked list and free memory of all related netmap items.\r
523 Removes all nodes of the Recycled doubly linked list and free memory of all related netmap items.\r
524 The number of the <Key, Value> pairs in the netmap is set to be zero.\r
525 \r
526 If Map is NULL, then ASSERT().\r
527 \r
3e7104c2 528 @param[in, out] Map The netmap to clean up.\r
da1d0201 529\r
530**/\r
531VOID\r
7b414b4e 532EFIAPI\r
da1d0201 533NetMapClean (\r
3e7104c2 534 IN OUT NET_MAP *Map\r
da1d0201 535 )\r
536{\r
537 NET_MAP_ITEM *Item;\r
e48e37fc 538 LIST_ENTRY *Entry;\r
539 LIST_ENTRY *Next;\r
da1d0201 540\r
541 ASSERT (Map != NULL);\r
542\r
543 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Used) {\r
544 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
545\r
e48e37fc 546 RemoveEntryList (&Item->Link);\r
da1d0201 547 Map->Count--;\r
548\r
e48e37fc 549 gBS->FreePool (Item);\r
da1d0201 550 }\r
551\r
e48e37fc 552 ASSERT ((Map->Count == 0) && IsListEmpty (&Map->Used));\r
da1d0201 553\r
554 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Recycled) {\r
555 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
556\r
e48e37fc 557 RemoveEntryList (&Item->Link);\r
558 gBS->FreePool (Item);\r
da1d0201 559 }\r
560\r
e48e37fc 561 ASSERT (IsListEmpty (&Map->Recycled));\r
da1d0201 562}\r
563\r
564\r
565/**\r
b9008c87 566 Test whether the netmap is empty and return true if it is.\r
567 \r
568 If the number of the <Key, Value> pairs in the netmap is zero, return TRUE.\r
569 \r
570 If Map is NULL, then ASSERT().\r
571 \r
572 \r
3e7104c2 573 @param[in] Map The net map to test.\r
da1d0201 574\r
575 @return TRUE if the netmap is empty, otherwise FALSE.\r
576\r
577**/\r
578BOOLEAN\r
7b414b4e 579EFIAPI\r
da1d0201 580NetMapIsEmpty (\r
581 IN NET_MAP *Map\r
582 )\r
583{\r
584 ASSERT (Map != NULL);\r
585 return (BOOLEAN) (Map->Count == 0);\r
586}\r
587\r
588\r
589/**\r
590 Return the number of the <Key, Value> pairs in the netmap.\r
591\r
3e7104c2 592 @param[in] Map The netmap to get the entry number.\r
da1d0201 593\r
594 @return The entry number in the netmap.\r
595\r
596**/\r
597UINTN\r
7b414b4e 598EFIAPI\r
da1d0201 599NetMapGetCount (\r
600 IN NET_MAP *Map\r
601 )\r
602{\r
603 return Map->Count;\r
604}\r
605\r
606\r
607/**\r
b9008c87 608 Return one allocated item. \r
609 \r
610 If the Recycled doubly linked list of the netmap is empty, it will try to allocate \r
611 a batch of items if there are enough resources and add corresponding nodes to the begining\r
612 of the Recycled doubly linked list of the netmap. Otherwise, it will directly remove\r
613 the fist node entry of the Recycled doubly linked list and return the corresponding item.\r
614 \r
615 If Map is NULL, then ASSERT().\r
616 \r
3e7104c2 617 @param[in, out] Map The netmap to allocate item for.\r
da1d0201 618\r
3e7104c2 619 @return The allocated item. If NULL, the\r
620 allocation failed due to resource limit.\r
da1d0201 621\r
622**/\r
da1d0201 623NET_MAP_ITEM *\r
624NetMapAllocItem (\r
3e7104c2 625 IN OUT NET_MAP *Map\r
da1d0201 626 )\r
627{\r
628 NET_MAP_ITEM *Item;\r
e48e37fc 629 LIST_ENTRY *Head;\r
da1d0201 630 UINTN Index;\r
631\r
632 ASSERT (Map != NULL);\r
633\r
634 Head = &Map->Recycled;\r
635\r
e48e37fc 636 if (IsListEmpty (Head)) {\r
da1d0201 637 for (Index = 0; Index < NET_MAP_INCREAMENT; Index++) {\r
e48e37fc 638 Item = AllocatePool (sizeof (NET_MAP_ITEM));\r
da1d0201 639\r
640 if (Item == NULL) {\r
641 if (Index == 0) {\r
642 return NULL;\r
643 }\r
644\r
645 break;\r
646 }\r
647\r
e48e37fc 648 InsertHeadList (Head, &Item->Link);\r
da1d0201 649 }\r
650 }\r
651\r
652 Item = NET_LIST_HEAD (Head, NET_MAP_ITEM, Link);\r
653 NetListRemoveHead (Head);\r
654\r
655 return Item;\r
656}\r
657\r
658\r
659/**\r
660 Allocate an item to save the <Key, Value> pair to the head of the netmap.\r
b9008c87 661 \r
662 Allocate an item to save the <Key, Value> pair and add corresponding node entry\r
663 to the beginning of the Used doubly linked list. The number of the <Key, Value> \r
664 pairs in the netmap increase by 1.\r
da1d0201 665\r
b9008c87 666 If Map is NULL, then ASSERT().\r
667 \r
3e7104c2 668 @param[in, out] Map The netmap to insert into.\r
669 @param[in] Key The user's key.\r
670 @param[in] Value The user's value for the key.\r
da1d0201 671\r
3e7104c2 672 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.\r
673 @retval EFI_SUCCESS The item is inserted to the head.\r
da1d0201 674\r
675**/\r
676EFI_STATUS\r
7b414b4e 677EFIAPI\r
da1d0201 678NetMapInsertHead (\r
3e7104c2 679 IN OUT NET_MAP *Map,\r
da1d0201 680 IN VOID *Key,\r
681 IN VOID *Value OPTIONAL\r
682 )\r
683{\r
684 NET_MAP_ITEM *Item;\r
685\r
686 ASSERT (Map != NULL);\r
687\r
688 Item = NetMapAllocItem (Map);\r
689\r
690 if (Item == NULL) {\r
691 return EFI_OUT_OF_RESOURCES;\r
692 }\r
693\r
694 Item->Key = Key;\r
695 Item->Value = Value;\r
e48e37fc 696 InsertHeadList (&Map->Used, &Item->Link);\r
da1d0201 697\r
698 Map->Count++;\r
699 return EFI_SUCCESS;\r
700}\r
701\r
702\r
703/**\r
704 Allocate an item to save the <Key, Value> pair to the tail of the netmap.\r
705\r
b9008c87 706 Allocate an item to save the <Key, Value> pair and add corresponding node entry\r
707 to the tail of the Used doubly linked list. The number of the <Key, Value> \r
708 pairs in the netmap increase by 1.\r
709\r
710 If Map is NULL, then ASSERT().\r
711 \r
3e7104c2 712 @param[in, out] Map The netmap to insert into.\r
713 @param[in] Key The user's key.\r
714 @param[in] Value The user's value for the key.\r
da1d0201 715\r
3e7104c2 716 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.\r
717 @retval EFI_SUCCESS The item is inserted to the tail.\r
da1d0201 718\r
719**/\r
720EFI_STATUS\r
7b414b4e 721EFIAPI\r
da1d0201 722NetMapInsertTail (\r
3e7104c2 723 IN OUT NET_MAP *Map,\r
da1d0201 724 IN VOID *Key,\r
725 IN VOID *Value OPTIONAL\r
726 )\r
727{\r
728 NET_MAP_ITEM *Item;\r
729\r
730 ASSERT (Map != NULL);\r
731\r
732 Item = NetMapAllocItem (Map);\r
733\r
734 if (Item == NULL) {\r
735 return EFI_OUT_OF_RESOURCES;\r
736 }\r
737\r
738 Item->Key = Key;\r
739 Item->Value = Value;\r
e48e37fc 740 InsertTailList (&Map->Used, &Item->Link);\r
da1d0201 741\r
742 Map->Count++;\r
743\r
744 return EFI_SUCCESS;\r
745}\r
746\r
747\r
748/**\r
b9008c87 749 Check whether the item is in the Map and return TRUE if it is.\r
da1d0201 750\r
3e7104c2 751 @param[in] Map The netmap to search within.\r
752 @param[in] Item The item to search.\r
da1d0201 753\r
754 @return TRUE if the item is in the netmap, otherwise FALSE.\r
755\r
756**/\r
da1d0201 757BOOLEAN\r
758NetItemInMap (\r
759 IN NET_MAP *Map,\r
760 IN NET_MAP_ITEM *Item\r
761 )\r
762{\r
e48e37fc 763 LIST_ENTRY *ListEntry;\r
da1d0201 764\r
765 NET_LIST_FOR_EACH (ListEntry, &Map->Used) {\r
766 if (ListEntry == &Item->Link) {\r
767 return TRUE;\r
768 }\r
769 }\r
770\r
771 return FALSE;\r
772}\r
773\r
774\r
775/**\r
b9008c87 776 Find the key in the netmap and returns the point to the item contains the Key.\r
777 \r
778 Iterate the Used doubly linked list of the netmap to get every item. Compare the key of every \r
779 item with the key to search. It returns the point to the item contains the Key if found.\r
da1d0201 780\r
b9008c87 781 If Map is NULL, then ASSERT().\r
782 \r
3e7104c2 783 @param[in] Map The netmap to search within.\r
784 @param[in] Key The key to search.\r
da1d0201 785\r
786 @return The point to the item contains the Key, or NULL if Key isn't in the map.\r
787\r
788**/\r
789NET_MAP_ITEM *\r
7b414b4e 790EFIAPI\r
da1d0201 791NetMapFindKey (\r
792 IN NET_MAP *Map,\r
793 IN VOID *Key\r
794 )\r
795{\r
e48e37fc 796 LIST_ENTRY *Entry;\r
da1d0201 797 NET_MAP_ITEM *Item;\r
798\r
799 ASSERT (Map != NULL);\r
800\r
801 NET_LIST_FOR_EACH (Entry, &Map->Used) {\r
802 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
803\r
804 if (Item->Key == Key) {\r
805 return Item;\r
806 }\r
807 }\r
808\r
809 return NULL;\r
810}\r
811\r
812\r
813/**\r
b9008c87 814 Remove the node entry of the item from the netmap and return the key of the removed item.\r
815 \r
816 Remove the node entry of the item from the Used doubly linked list of the netmap. \r
817 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node \r
818 entry of the item to the Recycled doubly linked list of the netmap. If Value is not NULL,\r
819 Value will point to the value of the item. It returns the key of the removed item.\r
820 \r
821 If Map is NULL, then ASSERT().\r
822 If Item is NULL, then ASSERT().\r
823 if item in not in the netmap, then ASSERT().\r
824 \r
3e7104c2 825 @param[in, out] Map The netmap to remove the item from.\r
826 @param[in, out] Item The item to remove.\r
827 @param[out] Value The variable to receive the value if not NULL.\r
da1d0201 828\r
3e7104c2 829 @return The key of the removed item.\r
da1d0201 830\r
831**/\r
832VOID *\r
7b414b4e 833EFIAPI\r
da1d0201 834NetMapRemoveItem (\r
3e7104c2 835 IN OUT NET_MAP *Map,\r
836 IN OUT NET_MAP_ITEM *Item,\r
837 OUT VOID **Value OPTIONAL\r
da1d0201 838 )\r
839{\r
840 ASSERT ((Map != NULL) && (Item != NULL));\r
841 ASSERT (NetItemInMap (Map, Item));\r
842\r
e48e37fc 843 RemoveEntryList (&Item->Link);\r
da1d0201 844 Map->Count--;\r
e48e37fc 845 InsertHeadList (&Map->Recycled, &Item->Link);\r
da1d0201 846\r
847 if (Value != NULL) {\r
848 *Value = Item->Value;\r
849 }\r
850\r
851 return Item->Key;\r
852}\r
853\r
854\r
855/**\r
b9008c87 856 Remove the first node entry on the netmap and return the key of the removed item.\r
da1d0201 857\r
b9008c87 858 Remove the first node entry from the Used doubly linked list of the netmap. \r
859 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node \r
860 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,\r
861 parameter Value will point to the value of the item. It returns the key of the removed item.\r
862 \r
863 If Map is NULL, then ASSERT().\r
864 If the Used doubly linked list is empty, then ASSERT().\r
865 \r
3e7104c2 866 @param[in, out] Map The netmap to remove the head from.\r
867 @param[out] Value The variable to receive the value if not NULL.\r
da1d0201 868\r
3e7104c2 869 @return The key of the item removed.\r
da1d0201 870\r
871**/\r
872VOID *\r
7b414b4e 873EFIAPI\r
da1d0201 874NetMapRemoveHead (\r
3e7104c2 875 IN OUT NET_MAP *Map,\r
da1d0201 876 OUT VOID **Value OPTIONAL\r
877 )\r
878{\r
879 NET_MAP_ITEM *Item;\r
880\r
881 //\r
882 // Often, it indicates a programming error to remove\r
883 // the first entry in an empty list\r
884 //\r
e48e37fc 885 ASSERT (Map && !IsListEmpty (&Map->Used));\r
da1d0201 886\r
887 Item = NET_LIST_HEAD (&Map->Used, NET_MAP_ITEM, Link);\r
e48e37fc 888 RemoveEntryList (&Item->Link);\r
da1d0201 889 Map->Count--;\r
e48e37fc 890 InsertHeadList (&Map->Recycled, &Item->Link);\r
da1d0201 891\r
892 if (Value != NULL) {\r
893 *Value = Item->Value;\r
894 }\r
895\r
896 return Item->Key;\r
897}\r
898\r
899\r
900/**\r
b9008c87 901 Remove the last node entry on the netmap and return the key of the removed item.\r
da1d0201 902\r
b9008c87 903 Remove the last node entry from the Used doubly linked list of the netmap. \r
904 The number of the <Key, Value> pairs in the netmap decrease by 1. Then add the node \r
905 entry to the Recycled doubly linked list of the netmap. If parameter Value is not NULL,\r
906 parameter Value will point to the value of the item. It returns the key of the removed item.\r
907 \r
908 If Map is NULL, then ASSERT().\r
909 If the Used doubly linked list is empty, then ASSERT().\r
910 \r
3e7104c2 911 @param[in, out] Map The netmap to remove the tail from.\r
912 @param[out] Value The variable to receive the value if not NULL.\r
da1d0201 913\r
3e7104c2 914 @return The key of the item removed.\r
da1d0201 915\r
916**/\r
917VOID *\r
7b414b4e 918EFIAPI\r
da1d0201 919NetMapRemoveTail (\r
3e7104c2 920 IN OUT NET_MAP *Map,\r
da1d0201 921 OUT VOID **Value OPTIONAL\r
922 )\r
923{\r
924 NET_MAP_ITEM *Item;\r
925\r
926 //\r
927 // Often, it indicates a programming error to remove\r
928 // the last entry in an empty list\r
929 //\r
e48e37fc 930 ASSERT (Map && !IsListEmpty (&Map->Used));\r
da1d0201 931\r
932 Item = NET_LIST_TAIL (&Map->Used, NET_MAP_ITEM, Link);\r
e48e37fc 933 RemoveEntryList (&Item->Link);\r
da1d0201 934 Map->Count--;\r
e48e37fc 935 InsertHeadList (&Map->Recycled, &Item->Link);\r
da1d0201 936\r
937 if (Value != NULL) {\r
938 *Value = Item->Value;\r
939 }\r
940\r
941 return Item->Key;\r
942}\r
943\r
944\r
945/**\r
b9008c87 946 Iterate through the netmap and call CallBack for each item.\r
947 \r
948 It will contiue the traverse if CallBack returns EFI_SUCCESS, otherwise, break\r
949 from the loop. It returns the CallBack's last return value. This function is \r
950 delete safe for the current item.\r
da1d0201 951\r
b9008c87 952 If Map is NULL, then ASSERT().\r
953 If CallBack is NULL, then ASSERT().\r
954 \r
3e7104c2 955 @param[in] Map The Map to iterate through.\r
956 @param[in] CallBack The callback function to call for each item.\r
957 @param[in] Arg The opaque parameter to the callback.\r
da1d0201 958\r
3e7104c2 959 @retval EFI_SUCCESS There is no item in the netmap or CallBack for each item\r
960 return EFI_SUCCESS.\r
961 @retval Others It returns the CallBack's last return value.\r
da1d0201 962\r
963**/\r
964EFI_STATUS\r
7b414b4e 965EFIAPI\r
da1d0201 966NetMapIterate (\r
967 IN NET_MAP *Map,\r
968 IN NET_MAP_CALLBACK CallBack,\r
969 IN VOID *Arg\r
970 )\r
971{\r
972\r
e48e37fc 973 LIST_ENTRY *Entry;\r
974 LIST_ENTRY *Next;\r
975 LIST_ENTRY *Head;\r
b9008c87 976 NET_MAP_ITEM *Item;\r
977 EFI_STATUS Result;\r
da1d0201 978\r
979 ASSERT ((Map != NULL) && (CallBack != NULL));\r
980\r
981 Head = &Map->Used;\r
982\r
e48e37fc 983 if (IsListEmpty (Head)) {\r
da1d0201 984 return EFI_SUCCESS;\r
985 }\r
986\r
987 NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {\r
988 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
989 Result = CallBack (Map, Item, Arg);\r
990\r
991 if (EFI_ERROR (Result)) {\r
992 return Result;\r
993 }\r
994 }\r
995\r
996 return EFI_SUCCESS;\r
997}\r
998\r
999\r
1000/**\r
1001 This is the default unload handle for all the network drivers.\r
1002\r
b9008c87 1003 Disconnect the driver specified by ImageHandle from all the devices in the handle database.\r
1004 Uninstall all the protocols installed in the driver entry point.\r
1005 \r
3e7104c2 1006 @param[in] ImageHandle The drivers' driver image.\r
da1d0201 1007\r
1008 @retval EFI_SUCCESS The image is unloaded.\r
1009 @retval Others Failed to unload the image.\r
1010\r
1011**/\r
1012EFI_STATUS\r
1013EFIAPI\r
1014NetLibDefaultUnload (\r
1015 IN EFI_HANDLE ImageHandle\r
1016 )\r
1017{\r
1018 EFI_STATUS Status;\r
1019 EFI_HANDLE *DeviceHandleBuffer;\r
1020 UINTN DeviceHandleCount;\r
1021 UINTN Index;\r
1022 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
1023 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;\r
3012ce5c 1024 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;\r
da1d0201 1025\r
1026 //\r
1027 // Get the list of all the handles in the handle database.\r
1028 // If there is an error getting the list, then the unload\r
1029 // operation fails.\r
1030 //\r
1031 Status = gBS->LocateHandleBuffer (\r
1032 AllHandles,\r
1033 NULL,\r
1034 NULL,\r
1035 &DeviceHandleCount,\r
1036 &DeviceHandleBuffer\r
1037 );\r
1038\r
1039 if (EFI_ERROR (Status)) {\r
1040 return Status;\r
1041 }\r
1042\r
1043 //\r
1044 // Disconnect the driver specified by ImageHandle from all\r
1045 // the devices in the handle database.\r
1046 //\r
1047 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1048 Status = gBS->DisconnectController (\r
1049 DeviceHandleBuffer[Index],\r
1050 ImageHandle,\r
1051 NULL\r
1052 );\r
1053 }\r
1054\r
1055 //\r
1056 // Uninstall all the protocols installed in the driver entry point\r
1057 //\r
1058 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
1059 Status = gBS->HandleProtocol (\r
1060 DeviceHandleBuffer[Index],\r
1061 &gEfiDriverBindingProtocolGuid,\r
1062 (VOID **) &DriverBinding\r
1063 );\r
1064\r
1065 if (EFI_ERROR (Status)) {\r
1066 continue;\r
1067 }\r
1068\r
1069 if (DriverBinding->ImageHandle != ImageHandle) {\r
1070 continue;\r
1071 }\r
1072\r
1073 gBS->UninstallProtocolInterface (\r
1074 ImageHandle,\r
1075 &gEfiDriverBindingProtocolGuid,\r
1076 DriverBinding\r
1077 );\r
1078 Status = gBS->HandleProtocol (\r
1079 DeviceHandleBuffer[Index],\r
1080 &gEfiComponentNameProtocolGuid,\r
1081 (VOID **) &ComponentName\r
1082 );\r
1083 if (!EFI_ERROR (Status)) {\r
1084 gBS->UninstallProtocolInterface (\r
1085 ImageHandle,\r
1086 &gEfiComponentNameProtocolGuid,\r
1087 ComponentName\r
1088 );\r
1089 }\r
1090\r
1091 Status = gBS->HandleProtocol (\r
1092 DeviceHandleBuffer[Index],\r
3012ce5c 1093 &gEfiComponentName2ProtocolGuid,\r
1094 (VOID **) &ComponentName2\r
da1d0201 1095 );\r
da1d0201 1096 if (!EFI_ERROR (Status)) {\r
1097 gBS->UninstallProtocolInterface (\r
3012ce5c 1098 ImageHandle,\r
1099 &gEfiComponentName2ProtocolGuid,\r
1100 ComponentName2\r
1101 );\r
da1d0201 1102 }\r
1103 }\r
1104\r
1105 //\r
1106 // Free the buffer containing the list of handles from the handle database\r
1107 //\r
1108 if (DeviceHandleBuffer != NULL) {\r
1109 gBS->FreePool (DeviceHandleBuffer);\r
1110 }\r
1111\r
1112 return EFI_SUCCESS;\r
1113}\r
1114\r
1115\r
1116\r
1117/**\r
1118 Create a child of the service that is identified by ServiceBindingGuid.\r
b9008c87 1119 \r
1120 Get the ServiceBinding Protocol first, then use it to create a child.\r
da1d0201 1121\r
b9008c87 1122 If ServiceBindingGuid is NULL, then ASSERT().\r
1123 If ChildHandle is NULL, then ASSERT().\r
1124 \r
3e7104c2 1125 @param[in] Controller The controller which has the service installed.\r
1126 @param[in] Image The image handle used to open service.\r
1127 @param[in] ServiceBindingGuid The service's Guid.\r
8f5e6151 1128 @param[in, out] ChildHandle The handle to receive the create child.\r
da1d0201 1129\r
1130 @retval EFI_SUCCESS The child is successfully created.\r
1131 @retval Others Failed to create the child.\r
1132\r
1133**/\r
1134EFI_STATUS\r
7b414b4e 1135EFIAPI\r
da1d0201 1136NetLibCreateServiceChild (\r
1137 IN EFI_HANDLE Controller,\r
1138 IN EFI_HANDLE Image,\r
1139 IN EFI_GUID *ServiceBindingGuid,\r
3e7104c2 1140 IN OUT EFI_HANDLE *ChildHandle\r
da1d0201 1141 )\r
1142{\r
1143 EFI_STATUS Status;\r
1144 EFI_SERVICE_BINDING_PROTOCOL *Service;\r
1145\r
1146\r
1147 ASSERT ((ServiceBindingGuid != NULL) && (ChildHandle != NULL));\r
1148\r
1149 //\r
1150 // Get the ServiceBinding Protocol\r
1151 //\r
1152 Status = gBS->OpenProtocol (\r
1153 Controller,\r
1154 ServiceBindingGuid,\r
1155 (VOID **) &Service,\r
1156 Image,\r
1157 Controller,\r
1158 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1159 );\r
1160\r
1161 if (EFI_ERROR (Status)) {\r
1162 return Status;\r
1163 }\r
1164\r
1165 //\r
1166 // Create a child\r
1167 //\r
1168 Status = Service->CreateChild (Service, ChildHandle);\r
1169 return Status;\r
1170}\r
1171\r
1172\r
1173/**\r
1174 Destory a child of the service that is identified by ServiceBindingGuid.\r
b9008c87 1175 \r
1176 Get the ServiceBinding Protocol first, then use it to destroy a child.\r
1177 \r
1178 If ServiceBindingGuid is NULL, then ASSERT().\r
1179 \r
3e7104c2 1180 @param[in] Controller The controller which has the service installed.\r
1181 @param[in] Image The image handle used to open service.\r
1182 @param[in] ServiceBindingGuid The service's Guid.\r
8f5e6151 1183 @param[in] ChildHandle The child to destory.\r
da1d0201 1184\r
1185 @retval EFI_SUCCESS The child is successfully destoried.\r
1186 @retval Others Failed to destory the child.\r
1187\r
1188**/\r
1189EFI_STATUS\r
7b414b4e 1190EFIAPI\r
da1d0201 1191NetLibDestroyServiceChild (\r
1192 IN EFI_HANDLE Controller,\r
1193 IN EFI_HANDLE Image,\r
1194 IN EFI_GUID *ServiceBindingGuid,\r
1195 IN EFI_HANDLE ChildHandle\r
1196 )\r
1197{\r
1198 EFI_STATUS Status;\r
1199 EFI_SERVICE_BINDING_PROTOCOL *Service;\r
1200\r
1201 ASSERT (ServiceBindingGuid != NULL);\r
1202\r
1203 //\r
1204 // Get the ServiceBinding Protocol\r
1205 //\r
1206 Status = gBS->OpenProtocol (\r
1207 Controller,\r
1208 ServiceBindingGuid,\r
1209 (VOID **) &Service,\r
1210 Image,\r
1211 Controller,\r
1212 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1213 );\r
1214\r
1215 if (EFI_ERROR (Status)) {\r
1216 return Status;\r
1217 }\r
1218\r
1219 //\r
1220 // destory the child\r
1221 //\r
1222 Status = Service->DestroyChild (Service, ChildHandle);\r
1223 return Status;\r
1224}\r
1225\r
1226\r
1227/**\r
1228 Convert the mac address of the simple network protocol installed on\r
1229 SnpHandle to a unicode string. Callers are responsible for freeing the\r
1230 string storage.\r
1231\r
b9008c87 1232 Get the mac address of the Simple Network protocol from the SnpHandle. Then convert\r
1233 the mac address into a unicode string. It takes 2 unicode characters to represent \r
1234 a 1 byte binary buffer. Plus one unicode character for the null-terminator.\r
1235\r
1236\r
3e7104c2 1237 @param[in] SnpHandle The handle where the simple network protocol is\r
1238 installed on.\r
1239 @param[in] ImageHandle The image handle used to act as the agent handle to\r
1240 get the simple network protocol.\r
1241 @param[out] MacString The pointer to store the address of the string\r
1242 representation of the mac address.\r
1243 \r
1244 @retval EFI_SUCCESS Convert the mac address a unicode string successfully.\r
da1d0201 1245 @retval EFI_OUT_OF_RESOURCES There are not enough memory resource.\r
3e7104c2 1246 @retval Others Failed to open the simple network protocol.\r
da1d0201 1247\r
1248**/\r
1249EFI_STATUS\r
7b414b4e 1250EFIAPI\r
da1d0201 1251NetLibGetMacString (\r
3e7104c2 1252 IN EFI_HANDLE SnpHandle,\r
1253 IN EFI_HANDLE ImageHandle,\r
1254 OUT CHAR16 **MacString\r
da1d0201 1255 )\r
1256{\r
1257 EFI_STATUS Status;\r
1258 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
1259 EFI_SIMPLE_NETWORK_MODE *Mode;\r
1260 CHAR16 *MacAddress;\r
1261 UINTN Index;\r
1262\r
1263 *MacString = NULL;\r
1264\r
1265 //\r
1266 // Get the Simple Network protocol from the SnpHandle.\r
1267 //\r
1268 Status = gBS->OpenProtocol (\r
1269 SnpHandle,\r
1270 &gEfiSimpleNetworkProtocolGuid,\r
1271 (VOID **) &Snp,\r
1272 ImageHandle,\r
1273 SnpHandle,\r
1274 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1275 );\r
1276 if (EFI_ERROR (Status)) {\r
1277 return Status;\r
1278 }\r
1279\r
1280 Mode = Snp->Mode;\r
1281\r
1282 //\r
1283 // It takes 2 unicode characters to represent a 1 byte binary buffer.\r
1284 // Plus one unicode character for the null-terminator.\r
1285 //\r
e48e37fc 1286 MacAddress = AllocatePool ((2 * Mode->HwAddressSize + 1) * sizeof (CHAR16));\r
da1d0201 1287 if (MacAddress == NULL) {\r
1288 return EFI_OUT_OF_RESOURCES;\r
1289 }\r
1290\r
1291 //\r
1292 // Convert the mac address into a unicode string.\r
1293 //\r
1294 for (Index = 0; Index < Mode->HwAddressSize; Index++) {\r
ac7e320c
LG
1295 MacAddress[Index * 2] = (CHAR16) mNetLibHexStr[(Mode->CurrentAddress.Addr[Index] >> 4) & 0x0F];\r
1296 MacAddress[Index * 2 + 1] = (CHAR16) mNetLibHexStr[Mode->CurrentAddress.Addr[Index] & 0x0F];\r
da1d0201 1297 }\r
1298\r
1299 MacAddress[Mode->HwAddressSize * 2] = L'\0';\r
1300\r
1301 *MacString = MacAddress;\r
1302\r
1303 return EFI_SUCCESS;\r
1304}\r
1305\r
1306/**\r
1307 Check the default address used by the IPv4 driver is static or dynamic (acquired\r
1308 from DHCP).\r
1309\r
b9008c87 1310 If the controller handle does not have the NIC Ip4 Config Protocol installed, the \r
1311 default address is static. If the EFI variable to save the configuration is not found,\r
1312 the default address is static. Otherwise, get the result from the EFI variable which \r
1313 saving the configuration.\r
1314 \r
3e7104c2 1315 @param[in] Controller The controller handle which has the NIC Ip4 Config Protocol\r
1316 relative with the default address to judge.\r
da1d0201 1317\r
1318 @retval TRUE If the default address is static.\r
1319 @retval FALSE If the default address is acquired from DHCP.\r
1320\r
1321**/\r
da1d0201 1322BOOLEAN\r
1323NetLibDefaultAddressIsStatic (\r
1324 IN EFI_HANDLE Controller\r
1325 )\r
1326{\r
63886849 1327 EFI_STATUS Status;\r
1328 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;\r
1329 UINTN Len;\r
1330 NIC_IP4_CONFIG_INFO *ConfigInfo;\r
1331 BOOLEAN IsStatic;\r
1332 EFI_STRING ConfigHdr;\r
1333 EFI_STRING ConfigResp;\r
1334 EFI_STRING AccessProgress;\r
1335 EFI_STRING AccessResults;\r
1336 EFI_STRING String;\r
1337\r
1338 ConfigInfo = NULL;\r
1339 ConfigHdr = NULL;\r
1340 ConfigResp = NULL;\r
1341 AccessProgress = NULL;\r
1342 AccessResults = NULL;\r
1343 IsStatic = TRUE;\r
1344\r
1345 Status = gBS->LocateProtocol (\r
1346 &gEfiHiiConfigRoutingProtocolGuid,\r
1347 NULL,\r
1348 (VOID **) &HiiConfigRouting\r
1349 );\r
da1d0201 1350 if (EFI_ERROR (Status)) {\r
1351 return TRUE;\r
1352 }\r
1353\r
63886849 1354 //\r
1355 // Construct config request string header\r
1356 //\r
1357 ConfigHdr = HiiConstructConfigHdr (&gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE, Controller);\r
894d038a 1358 if (ConfigHdr == NULL) {\r
1359 return TRUE;\r
1360 }\r
63886849 1361 \r
1362 Len = StrLen (ConfigHdr);\r
ce4106be 1363 ConfigResp = AllocateZeroPool ((Len + NIC_ITEM_CONFIG_SIZE * 2 + 100) * sizeof (CHAR16));\r
63886849 1364 if (ConfigResp == NULL) {\r
1365 goto ON_EXIT;\r
1366 }\r
1367 StrCpy (ConfigResp, ConfigHdr);\r
1368\r
1369 String = ConfigResp + Len;\r
1370 UnicodeSPrint (\r
1371 String, \r
ce4106be 1372 (8 + 4 + 7 + 4 + 1) * sizeof (CHAR16), \r
63886849 1373 L"&OFFSET=%04X&WIDTH=%04X", \r
1374 OFFSET_OF (NIC_IP4_CONFIG_INFO, Source), \r
1375 sizeof (UINT32)\r
1376 );\r
1377\r
1378 Status = HiiConfigRouting->ExtractConfig (\r
1379 HiiConfigRouting,\r
1380 ConfigResp,\r
1381 &AccessProgress,\r
1382 &AccessResults\r
1383 );\r
1384 if (EFI_ERROR (Status)) {\r
1385 goto ON_EXIT;\r
da1d0201 1386 }\r
1387\r
ce4106be 1388 ConfigInfo = AllocateZeroPool (sizeof (NIC_ITEM_CONFIG_SIZE));\r
da1d0201 1389 if (ConfigInfo == NULL) {\r
63886849 1390 goto ON_EXIT;\r
da1d0201 1391 }\r
1392\r
63886849 1393 ConfigInfo->Source = IP4_CONFIG_SOURCE_STATIC;\r
1394 Len = NIC_ITEM_CONFIG_SIZE;\r
1395 Status = HiiConfigRouting->ConfigToBlock (\r
1396 HiiConfigRouting,\r
1397 AccessResults,\r
1398 (UINT8 *) ConfigInfo,\r
1399 &Len,\r
1400 &AccessProgress\r
1401 );\r
da1d0201 1402 if (EFI_ERROR (Status)) {\r
1403 goto ON_EXIT;\r
1404 }\r
1405\r
1406 IsStatic = (BOOLEAN) (ConfigInfo->Source == IP4_CONFIG_SOURCE_STATIC);\r
63886849 1407 \r
da1d0201 1408ON_EXIT:\r
1409\r
63886849 1410 if (AccessResults != NULL) {\r
1411 FreePool (AccessResults);\r
1412 }\r
1413 if (ConfigInfo != NULL) {\r
1414 FreePool (ConfigInfo);\r
1415 }\r
1416 if (ConfigResp != NULL) {\r
1417 FreePool (ConfigResp);\r
1418 }\r
1419 if (ConfigHdr != NULL) {\r
1420 FreePool (ConfigHdr);\r
1421 }\r
da1d0201 1422\r
1423 return IsStatic;\r
1424}\r
1425\r
1426/**\r
1427 Create an IPv4 device path node.\r
b9008c87 1428 \r
1429 The header type of IPv4 device path node is MESSAGING_DEVICE_PATH.\r
1430 The header subtype of IPv4 device path node is MSG_IPv4_DP.\r
1431 The length of the IPv4 device path node in bytes is 19.\r
1432 Get other info from parameters to make up the whole IPv4 device path node.\r
da1d0201 1433\r
3e7104c2 1434 @param[in, out] Node Pointer to the IPv4 device path node.\r
1435 @param[in] Controller The handle where the NIC IP4 config protocol resides.\r
1436 @param[in] LocalIp The local IPv4 address.\r
1437 @param[in] LocalPort The local port.\r
1438 @param[in] RemoteIp The remote IPv4 address.\r
1439 @param[in] RemotePort The remote port.\r
1440 @param[in] Protocol The protocol type in the IP header.\r
1441 @param[in] UseDefaultAddress Whether this instance is using default address or not.\r
da1d0201 1442\r
da1d0201 1443**/\r
1444VOID\r
7b414b4e 1445EFIAPI\r
da1d0201 1446NetLibCreateIPv4DPathNode (\r
1447 IN OUT IPv4_DEVICE_PATH *Node,\r
1448 IN EFI_HANDLE Controller,\r
1449 IN IP4_ADDR LocalIp,\r
1450 IN UINT16 LocalPort,\r
1451 IN IP4_ADDR RemoteIp,\r
1452 IN UINT16 RemotePort,\r
1453 IN UINT16 Protocol,\r
1454 IN BOOLEAN UseDefaultAddress\r
1455 )\r
1456{\r
1457 Node->Header.Type = MESSAGING_DEVICE_PATH;\r
1458 Node->Header.SubType = MSG_IPv4_DP;\r
1459 SetDevicePathNodeLength (&Node->Header, 19);\r
1460\r
e48e37fc 1461 CopyMem (&Node->LocalIpAddress, &LocalIp, sizeof (EFI_IPv4_ADDRESS));\r
1462 CopyMem (&Node->RemoteIpAddress, &RemoteIp, sizeof (EFI_IPv4_ADDRESS));\r
da1d0201 1463\r
1464 Node->LocalPort = LocalPort;\r
1465 Node->RemotePort = RemotePort;\r
1466\r
1467 Node->Protocol = Protocol;\r
1468\r
1469 if (!UseDefaultAddress) {\r
1470 Node->StaticIpAddress = TRUE;\r
1471 } else {\r
1472 Node->StaticIpAddress = NetLibDefaultAddressIsStatic (Controller);\r
1473 }\r
1474}\r
1475\r
1476\r
1477/**\r
1478 Find the UNDI/SNP handle from controller and protocol GUID.\r
b9008c87 1479 \r
da1d0201 1480 For example, IP will open a MNP child to transmit/receive\r
1481 packets, when MNP is stopped, IP should also be stopped. IP\r
1482 needs to find its own private data which is related the IP's\r
1483 service binding instance that is install on UNDI/SNP handle.\r
1484 Now, the controller is either a MNP or ARP child handle. But\r
1485 IP opens these handle BY_DRIVER, use that info, we can get the\r
1486 UNDI/SNP handle.\r
1487\r
3e7104c2 1488 @param[in] Controller Then protocol handle to check.\r
1489 @param[in] ProtocolGuid The protocol that is related with the handle.\r
da1d0201 1490\r
3e7104c2 1491 @return The UNDI/SNP handle or NULL for errors.\r
da1d0201 1492\r
1493**/\r
1494EFI_HANDLE\r
7b414b4e 1495EFIAPI\r
da1d0201 1496NetLibGetNicHandle (\r
1497 IN EFI_HANDLE Controller,\r
1498 IN EFI_GUID *ProtocolGuid\r
1499 )\r
1500{\r
1501 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenBuffer;\r
1502 EFI_HANDLE Handle;\r
1503 EFI_STATUS Status;\r
1504 UINTN OpenCount;\r
1505 UINTN Index;\r
1506\r
1507 Status = gBS->OpenProtocolInformation (\r
1508 Controller,\r
1509 ProtocolGuid,\r
1510 &OpenBuffer,\r
1511 &OpenCount\r
1512 );\r
1513\r
1514 if (EFI_ERROR (Status)) {\r
1515 return NULL;\r
1516 }\r
1517\r
1518 Handle = NULL;\r
1519\r
1520 for (Index = 0; Index < OpenCount; Index++) {\r
1521 if (OpenBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) {\r
1522 Handle = OpenBuffer[Index].ControllerHandle;\r
1523 break;\r
1524 }\r
1525 }\r
1526\r
1527 gBS->FreePool (OpenBuffer);\r
1528 return Handle;\r
1529}\r