1). Fix the debug level for DEBUG macro
[mirror_edk2.git] / MdeModulePkg / Library / DxeNetLib / DxeNetLib.c
CommitLineData
da1d0201 1/** @file\r
3e7104c2 2 Network library.\r
3 \r
4Copyright (c) 2005 - 2007, 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
16#include <Protocol/ServiceBinding.h>\r
17#include <Protocol/SimpleNetwork.h>\r
da1d0201 18#include <Protocol/NicIp4Config.h>\r
3012ce5c 19#include <Protocol/ComponentName.h>\r
20#include <Protocol/ComponentName2.h>\r
e1a590c3 21#include <Protocol/Dpc.h>\r
da1d0201 22\r
23#include <Library/NetLib.h>\r
24#include <Library/BaseLib.h>\r
25#include <Library/DebugLib.h>\r
26#include <Library/BaseMemoryLib.h>\r
27#include <Library/UefiBootServicesTableLib.h>\r
28#include <Library/UefiRuntimeServicesTableLib.h>\r
da1d0201 29#include <Library/MemoryAllocationLib.h>\r
1232b214 30#include <Library/DevicePathLib.h>\r
da1d0201 31\r
36ee91ca 32EFI_DPC_PROTOCOL *mDpc = NULL;\r
33\r
ac7e320c
LG
34GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mNetLibHexStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};\r
35\r
da1d0201 36//\r
37// All the supported IP4 maskes in host byte order.\r
38//\r
2a86ff1c 39IP4_ADDR gIp4AllMasks[IP4_MASK_NUM] = {\r
da1d0201 40 0x00000000,\r
41 0x80000000,\r
42 0xC0000000,\r
43 0xE0000000,\r
44 0xF0000000,\r
45 0xF8000000,\r
46 0xFC000000,\r
47 0xFE000000,\r
48\r
49 0xFF000000,\r
50 0xFF800000,\r
51 0xFFC00000,\r
52 0xFFE00000,\r
53 0xFFF00000,\r
54 0xFFF80000,\r
55 0xFFFC0000,\r
56 0xFFFE0000,\r
57\r
58 0xFFFF0000,\r
59 0xFFFF8000,\r
60 0xFFFFC000,\r
61 0xFFFFE000,\r
62 0xFFFFF000,\r
63 0xFFFFF800,\r
64 0xFFFFFC00,\r
65 0xFFFFFE00,\r
66\r
67 0xFFFFFF00,\r
68 0xFFFFFF80,\r
69 0xFFFFFFC0,\r
70 0xFFFFFFE0,\r
71 0xFFFFFFF0,\r
72 0xFFFFFFF8,\r
73 0xFFFFFFFC,\r
74 0xFFFFFFFE,\r
75 0xFFFFFFFF,\r
76};\r
77\r
78EFI_IPv4_ADDRESS mZeroIp4Addr = {{0, 0, 0, 0}};\r
79\r
da1d0201 80/**\r
81 Return the length of the mask. If the mask is invalid,\r
82 return the invalid length 33, which is IP4_MASK_NUM.\r
83 NetMask is in the host byte order.\r
84\r
3e7104c2 85 @param[in] NetMask The netmask to get the length from.\r
da1d0201 86\r
3e7104c2 87 @return The length of the netmask, IP4_MASK_NUM if the mask isn't.\r
88 \r
da1d0201 89**/\r
90INTN\r
7b414b4e 91EFIAPI\r
da1d0201 92NetGetMaskLength (\r
93 IN IP4_ADDR NetMask\r
94 )\r
95{\r
96 INTN Index;\r
97\r
98 for (Index = 0; Index < IP4_MASK_NUM; Index++) {\r
2a86ff1c 99 if (NetMask == gIp4AllMasks[Index]) {\r
da1d0201 100 break;\r
101 }\r
102 }\r
103\r
104 return Index;\r
105}\r
106\r
107\r
108\r
109/**\r
110 Return the class of the address, such as class a, b, c.\r
111 Addr is in host byte order.\r
112\r
3e7104c2 113 @param[in] Addr The address to get the class from.\r
da1d0201 114\r
3e7104c2 115 @return IP address class, such as IP4_ADDR_CLASSA.\r
da1d0201 116\r
117**/\r
118INTN\r
7b414b4e 119EFIAPI\r
da1d0201 120NetGetIpClass (\r
121 IN IP4_ADDR Addr\r
122 )\r
123{\r
124 UINT8 ByteOne;\r
125\r
126 ByteOne = (UINT8) (Addr >> 24);\r
127\r
128 if ((ByteOne & 0x80) == 0) {\r
129 return IP4_ADDR_CLASSA;\r
130\r
131 } else if ((ByteOne & 0xC0) == 0x80) {\r
132 return IP4_ADDR_CLASSB;\r
133\r
134 } else if ((ByteOne & 0xE0) == 0xC0) {\r
135 return IP4_ADDR_CLASSC;\r
136\r
137 } else if ((ByteOne & 0xF0) == 0xE0) {\r
138 return IP4_ADDR_CLASSD;\r
139\r
140 } else {\r
141 return IP4_ADDR_CLASSE;\r
142\r
143 }\r
144}\r
145\r
146\r
147/**\r
148 Check whether the IP is a valid unicast address according to\r
149 the netmask. If NetMask is zero, use the IP address's class to\r
150 get the default mask.\r
151\r
3e7104c2 152 @param[in] Ip The IP to check against.\r
153 @param[in] NetMask The mask of the IP.\r
da1d0201 154\r
3e7104c2 155 @return TRUE if IP is a valid unicast address on the network, otherwise FALSE.\r
da1d0201 156\r
157**/\r
158BOOLEAN\r
7b414b4e 159EFIAPI\r
da1d0201 160Ip4IsUnicast (\r
161 IN IP4_ADDR Ip,\r
162 IN IP4_ADDR NetMask\r
163 )\r
164{\r
165 INTN Class;\r
166\r
167 Class = NetGetIpClass (Ip);\r
168\r
169 if ((Ip == 0) || (Class >= IP4_ADDR_CLASSD)) {\r
170 return FALSE;\r
171 }\r
172\r
173 if (NetMask == 0) {\r
2a86ff1c 174 NetMask = gIp4AllMasks[Class << 3];\r
da1d0201 175 }\r
176\r
177 if (((Ip &~NetMask) == ~NetMask) || ((Ip &~NetMask) == 0)) {\r
178 return FALSE;\r
179 }\r
180\r
181 return TRUE;\r
182}\r
183\r
184\r
185/**\r
186 Initialize a random seed using current time.\r
187\r
da1d0201 188 @return The random seed initialized with current time.\r
189\r
190**/\r
191UINT32\r
7b414b4e 192EFIAPI\r
da1d0201 193NetRandomInitSeed (\r
194 VOID\r
195 )\r
196{\r
197 EFI_TIME Time;\r
198 UINT32 Seed;\r
199\r
200 gRT->GetTime (&Time, NULL);\r
36ee91ca 201 Seed = (~Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second);\r
da1d0201 202 Seed ^= Time.Nanosecond;\r
203 Seed ^= Time.Year << 7;\r
204\r
205 return Seed;\r
206}\r
207\r
208\r
209/**\r
210 Extract a UINT32 from a byte stream, then convert it to host\r
211 byte order. Use this function to avoid alignment error.\r
212\r
3e7104c2 213 @param[in] Buf The buffer to extract the UINT32.\r
da1d0201 214\r
215 @return The UINT32 extracted.\r
216\r
217**/\r
218UINT32\r
7b414b4e 219EFIAPI\r
da1d0201 220NetGetUint32 (\r
221 IN UINT8 *Buf\r
222 )\r
223{\r
224 UINT32 Value;\r
225\r
e48e37fc 226 CopyMem (&Value, Buf, sizeof (UINT32));\r
da1d0201 227 return NTOHL (Value);\r
228}\r
229\r
230\r
231/**\r
232 Put a UINT32 to the byte stream. Convert it from host byte order\r
233 to network byte order before putting.\r
234\r
3e7104c2 235 @param[in, out] Buf The buffer to put the UINT32.\r
236 @param[in] Data The data to put.\r
237 \r
da1d0201 238**/\r
239VOID\r
7b414b4e 240EFIAPI\r
da1d0201 241NetPutUint32 (\r
3e7104c2 242 IN OUT UINT8 *Buf,\r
243 IN UINT32 Data\r
da1d0201 244 )\r
245{\r
246 Data = HTONL (Data);\r
e48e37fc 247 CopyMem (Buf, &Data, sizeof (UINT32));\r
da1d0201 248}\r
249\r
250\r
251/**\r
3e7104c2 252 Remove the first entry on the list.\r
da1d0201 253\r
3e7104c2 254 @param[in, out] Head The list header.\r
da1d0201 255\r
256 @return The entry that is removed from the list, NULL if the list is empty.\r
257\r
258**/\r
e48e37fc 259LIST_ENTRY *\r
7b414b4e 260EFIAPI\r
da1d0201 261NetListRemoveHead (\r
3e7104c2 262 IN OUT LIST_ENTRY *Head\r
da1d0201 263 )\r
264{\r
e48e37fc 265 LIST_ENTRY *First;\r
da1d0201 266\r
267 ASSERT (Head != NULL);\r
268\r
e48e37fc 269 if (IsListEmpty (Head)) {\r
da1d0201 270 return NULL;\r
271 }\r
272\r
273 First = Head->ForwardLink;\r
274 Head->ForwardLink = First->ForwardLink;\r
275 First->ForwardLink->BackLink = Head;\r
276\r
277 DEBUG_CODE (\r
e48e37fc 278 First->ForwardLink = (LIST_ENTRY *) NULL;\r
279 First->BackLink = (LIST_ENTRY *) NULL;\r
da1d0201 280 );\r
281\r
282 return First;\r
283}\r
284\r
285\r
286/**\r
3e7104c2 287 Remove the last entry on the list.\r
da1d0201 288\r
3e7104c2 289 @param[in, out] Head The list head.\r
da1d0201 290\r
291 @return The entry that is removed from the list, NULL if the list is empty.\r
292\r
293**/\r
e48e37fc 294LIST_ENTRY *\r
7b414b4e 295EFIAPI\r
da1d0201 296NetListRemoveTail (\r
3e7104c2 297 IN OUT LIST_ENTRY *Head\r
da1d0201 298 )\r
299{\r
e48e37fc 300 LIST_ENTRY *Last;\r
da1d0201 301\r
302 ASSERT (Head != NULL);\r
303\r
e48e37fc 304 if (IsListEmpty (Head)) {\r
da1d0201 305 return NULL;\r
306 }\r
307\r
308 Last = Head->BackLink;\r
309 Head->BackLink = Last->BackLink;\r
310 Last->BackLink->ForwardLink = Head;\r
311\r
312 DEBUG_CODE (\r
e48e37fc 313 Last->ForwardLink = (LIST_ENTRY *) NULL;\r
314 Last->BackLink = (LIST_ENTRY *) NULL;\r
da1d0201 315 );\r
316\r
317 return Last;\r
318}\r
319\r
320\r
321/**\r
3e7104c2 322 Insert the NewEntry after the PrevEntry.\r
da1d0201 323\r
3e7104c2 324 @param[in, out] PrevEntry The previous entry to insert after.\r
325 @param[in, out] NewEntry The new entry to insert.\r
da1d0201 326\r
327**/\r
328VOID\r
7b414b4e 329EFIAPI\r
da1d0201 330NetListInsertAfter (\r
3e7104c2 331 IN OUT LIST_ENTRY *PrevEntry,\r
332 IN OUT LIST_ENTRY *NewEntry\r
da1d0201 333 )\r
334{\r
335 NewEntry->BackLink = PrevEntry;\r
336 NewEntry->ForwardLink = PrevEntry->ForwardLink;\r
337 PrevEntry->ForwardLink->BackLink = NewEntry;\r
338 PrevEntry->ForwardLink = NewEntry;\r
339}\r
340\r
341\r
342/**\r
3e7104c2 343 Insert the NewEntry before the PostEntry.\r
da1d0201 344\r
3e7104c2 345 @param[in, out] PostEntry The entry to insert before.\r
346 @param[in, out] NewEntry The new entry to insert.\r
da1d0201 347\r
348**/\r
349VOID\r
7b414b4e 350EFIAPI\r
da1d0201 351NetListInsertBefore (\r
3e7104c2 352 IN OUT LIST_ENTRY *PostEntry,\r
353 IN OUT LIST_ENTRY *NewEntry\r
da1d0201 354 )\r
355{\r
356 NewEntry->ForwardLink = PostEntry;\r
357 NewEntry->BackLink = PostEntry->BackLink;\r
358 PostEntry->BackLink->ForwardLink = NewEntry;\r
359 PostEntry->BackLink = NewEntry;\r
360}\r
361\r
362\r
363/**\r
364 Initialize the netmap. Netmap is a reposity to keep the <Key, Value> pairs.\r
365\r
3e7104c2 366 @param[in, out] Map The netmap to initialize.\r
da1d0201 367\r
368**/\r
369VOID\r
7b414b4e 370EFIAPI\r
da1d0201 371NetMapInit (\r
3e7104c2 372 IN OUT NET_MAP *Map\r
da1d0201 373 )\r
374{\r
375 ASSERT (Map != NULL);\r
376\r
e48e37fc 377 InitializeListHead (&Map->Used);\r
378 InitializeListHead (&Map->Recycled);\r
da1d0201 379 Map->Count = 0;\r
380}\r
381\r
382\r
383/**\r
384 To clean up the netmap, that is, release allocated memories.\r
385\r
3e7104c2 386 @param[in, out] Map The netmap to clean up.\r
da1d0201 387\r
388**/\r
389VOID\r
7b414b4e 390EFIAPI\r
da1d0201 391NetMapClean (\r
3e7104c2 392 IN OUT NET_MAP *Map\r
da1d0201 393 )\r
394{\r
395 NET_MAP_ITEM *Item;\r
e48e37fc 396 LIST_ENTRY *Entry;\r
397 LIST_ENTRY *Next;\r
da1d0201 398\r
399 ASSERT (Map != NULL);\r
400\r
401 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Used) {\r
402 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
403\r
e48e37fc 404 RemoveEntryList (&Item->Link);\r
da1d0201 405 Map->Count--;\r
406\r
e48e37fc 407 gBS->FreePool (Item);\r
da1d0201 408 }\r
409\r
e48e37fc 410 ASSERT ((Map->Count == 0) && IsListEmpty (&Map->Used));\r
da1d0201 411\r
412 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Map->Recycled) {\r
413 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
414\r
e48e37fc 415 RemoveEntryList (&Item->Link);\r
416 gBS->FreePool (Item);\r
da1d0201 417 }\r
418\r
e48e37fc 419 ASSERT (IsListEmpty (&Map->Recycled));\r
da1d0201 420}\r
421\r
422\r
423/**\r
3e7104c2 424 Test whether the netmap is empty.\r
da1d0201 425\r
3e7104c2 426 @param[in] Map The net map to test.\r
da1d0201 427\r
428 @return TRUE if the netmap is empty, otherwise FALSE.\r
429\r
430**/\r
431BOOLEAN\r
7b414b4e 432EFIAPI\r
da1d0201 433NetMapIsEmpty (\r
434 IN NET_MAP *Map\r
435 )\r
436{\r
437 ASSERT (Map != NULL);\r
438 return (BOOLEAN) (Map->Count == 0);\r
439}\r
440\r
441\r
442/**\r
443 Return the number of the <Key, Value> pairs in the netmap.\r
444\r
3e7104c2 445 @param[in] Map The netmap to get the entry number.\r
da1d0201 446\r
447 @return The entry number in the netmap.\r
448\r
449**/\r
450UINTN\r
7b414b4e 451EFIAPI\r
da1d0201 452NetMapGetCount (\r
453 IN NET_MAP *Map\r
454 )\r
455{\r
456 return Map->Count;\r
457}\r
458\r
459\r
460/**\r
3e7104c2 461 Allocate an item for the netmap. It will try to allocate.\r
da1d0201 462 a batch of items and return one.\r
463\r
3e7104c2 464 @param[in, out] Map The netmap to allocate item for.\r
da1d0201 465\r
3e7104c2 466 @return The allocated item. If NULL, the\r
467 allocation failed due to resource limit.\r
da1d0201 468\r
469**/\r
da1d0201 470NET_MAP_ITEM *\r
471NetMapAllocItem (\r
3e7104c2 472 IN OUT NET_MAP *Map\r
da1d0201 473 )\r
474{\r
475 NET_MAP_ITEM *Item;\r
e48e37fc 476 LIST_ENTRY *Head;\r
da1d0201 477 UINTN Index;\r
478\r
479 ASSERT (Map != NULL);\r
480\r
481 Head = &Map->Recycled;\r
482\r
e48e37fc 483 if (IsListEmpty (Head)) {\r
da1d0201 484 for (Index = 0; Index < NET_MAP_INCREAMENT; Index++) {\r
e48e37fc 485 Item = AllocatePool (sizeof (NET_MAP_ITEM));\r
da1d0201 486\r
487 if (Item == NULL) {\r
488 if (Index == 0) {\r
489 return NULL;\r
490 }\r
491\r
492 break;\r
493 }\r
494\r
e48e37fc 495 InsertHeadList (Head, &Item->Link);\r
da1d0201 496 }\r
497 }\r
498\r
499 Item = NET_LIST_HEAD (Head, NET_MAP_ITEM, Link);\r
500 NetListRemoveHead (Head);\r
501\r
502 return Item;\r
503}\r
504\r
505\r
506/**\r
507 Allocate an item to save the <Key, Value> pair to the head of the netmap.\r
508\r
3e7104c2 509 @param[in, out] Map The netmap to insert into.\r
510 @param[in] Key The user's key.\r
511 @param[in] Value The user's value for the key.\r
da1d0201 512\r
3e7104c2 513 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.\r
514 @retval EFI_SUCCESS The item is inserted to the head.\r
da1d0201 515\r
516**/\r
517EFI_STATUS\r
7b414b4e 518EFIAPI\r
da1d0201 519NetMapInsertHead (\r
3e7104c2 520 IN OUT NET_MAP *Map,\r
da1d0201 521 IN VOID *Key,\r
522 IN VOID *Value OPTIONAL\r
523 )\r
524{\r
525 NET_MAP_ITEM *Item;\r
526\r
527 ASSERT (Map != NULL);\r
528\r
529 Item = NetMapAllocItem (Map);\r
530\r
531 if (Item == NULL) {\r
532 return EFI_OUT_OF_RESOURCES;\r
533 }\r
534\r
535 Item->Key = Key;\r
536 Item->Value = Value;\r
e48e37fc 537 InsertHeadList (&Map->Used, &Item->Link);\r
da1d0201 538\r
539 Map->Count++;\r
540 return EFI_SUCCESS;\r
541}\r
542\r
543\r
544/**\r
545 Allocate an item to save the <Key, Value> pair to the tail of the netmap.\r
546\r
3e7104c2 547 @param[in, out] Map The netmap to insert into.\r
548 @param[in] Key The user's key.\r
549 @param[in] Value The user's value for the key.\r
da1d0201 550\r
3e7104c2 551 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the item.\r
552 @retval EFI_SUCCESS The item is inserted to the tail.\r
da1d0201 553\r
554**/\r
555EFI_STATUS\r
7b414b4e 556EFIAPI\r
da1d0201 557NetMapInsertTail (\r
3e7104c2 558 IN OUT NET_MAP *Map,\r
da1d0201 559 IN VOID *Key,\r
560 IN VOID *Value OPTIONAL\r
561 )\r
562{\r
563 NET_MAP_ITEM *Item;\r
564\r
565 ASSERT (Map != NULL);\r
566\r
567 Item = NetMapAllocItem (Map);\r
568\r
569 if (Item == NULL) {\r
570 return EFI_OUT_OF_RESOURCES;\r
571 }\r
572\r
573 Item->Key = Key;\r
574 Item->Value = Value;\r
e48e37fc 575 InsertTailList (&Map->Used, &Item->Link);\r
da1d0201 576\r
577 Map->Count++;\r
578\r
579 return EFI_SUCCESS;\r
580}\r
581\r
582\r
583/**\r
3e7104c2 584 Check whther the item is in the Map.\r
da1d0201 585\r
3e7104c2 586 @param[in] Map The netmap to search within.\r
587 @param[in] Item The item to search.\r
da1d0201 588\r
589 @return TRUE if the item is in the netmap, otherwise FALSE.\r
590\r
591**/\r
da1d0201 592BOOLEAN\r
593NetItemInMap (\r
594 IN NET_MAP *Map,\r
595 IN NET_MAP_ITEM *Item\r
596 )\r
597{\r
e48e37fc 598 LIST_ENTRY *ListEntry;\r
da1d0201 599\r
600 NET_LIST_FOR_EACH (ListEntry, &Map->Used) {\r
601 if (ListEntry == &Item->Link) {\r
602 return TRUE;\r
603 }\r
604 }\r
605\r
606 return FALSE;\r
607}\r
608\r
609\r
610/**\r
3e7104c2 611 Find the key in the netmap.\r
da1d0201 612\r
3e7104c2 613 @param[in] Map The netmap to search within.\r
614 @param[in] Key The key to search.\r
da1d0201 615\r
616 @return The point to the item contains the Key, or NULL if Key isn't in the map.\r
617\r
618**/\r
619NET_MAP_ITEM *\r
7b414b4e 620EFIAPI\r
da1d0201 621NetMapFindKey (\r
622 IN NET_MAP *Map,\r
623 IN VOID *Key\r
624 )\r
625{\r
e48e37fc 626 LIST_ENTRY *Entry;\r
da1d0201 627 NET_MAP_ITEM *Item;\r
628\r
629 ASSERT (Map != NULL);\r
630\r
631 NET_LIST_FOR_EACH (Entry, &Map->Used) {\r
632 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
633\r
634 if (Item->Key == Key) {\r
635 return Item;\r
636 }\r
637 }\r
638\r
639 return NULL;\r
640}\r
641\r
642\r
643/**\r
3e7104c2 644 Remove the item from the netmap.\r
da1d0201 645\r
3e7104c2 646 @param[in, out] Map The netmap to remove the item from.\r
647 @param[in, out] Item The item to remove.\r
648 @param[out] Value The variable to receive the value if not NULL.\r
da1d0201 649\r
3e7104c2 650 @return The key of the removed item.\r
da1d0201 651\r
652**/\r
653VOID *\r
7b414b4e 654EFIAPI\r
da1d0201 655NetMapRemoveItem (\r
3e7104c2 656 IN OUT NET_MAP *Map,\r
657 IN OUT NET_MAP_ITEM *Item,\r
658 OUT VOID **Value OPTIONAL\r
da1d0201 659 )\r
660{\r
661 ASSERT ((Map != NULL) && (Item != NULL));\r
662 ASSERT (NetItemInMap (Map, Item));\r
663\r
e48e37fc 664 RemoveEntryList (&Item->Link);\r
da1d0201 665 Map->Count--;\r
e48e37fc 666 InsertHeadList (&Map->Recycled, &Item->Link);\r
da1d0201 667\r
668 if (Value != NULL) {\r
669 *Value = Item->Value;\r
670 }\r
671\r
672 return Item->Key;\r
673}\r
674\r
675\r
676/**\r
3e7104c2 677 Remove the first entry on the netmap.\r
da1d0201 678\r
3e7104c2 679 @param[in, out] Map The netmap to remove the head from.\r
680 @param[out] Value The variable to receive the value if not NULL.\r
da1d0201 681\r
3e7104c2 682 @return The key of the item removed.\r
da1d0201 683\r
684**/\r
685VOID *\r
7b414b4e 686EFIAPI\r
da1d0201 687NetMapRemoveHead (\r
3e7104c2 688 IN OUT NET_MAP *Map,\r
da1d0201 689 OUT VOID **Value OPTIONAL\r
690 )\r
691{\r
692 NET_MAP_ITEM *Item;\r
693\r
694 //\r
695 // Often, it indicates a programming error to remove\r
696 // the first entry in an empty list\r
697 //\r
e48e37fc 698 ASSERT (Map && !IsListEmpty (&Map->Used));\r
da1d0201 699\r
700 Item = NET_LIST_HEAD (&Map->Used, NET_MAP_ITEM, Link);\r
e48e37fc 701 RemoveEntryList (&Item->Link);\r
da1d0201 702 Map->Count--;\r
e48e37fc 703 InsertHeadList (&Map->Recycled, &Item->Link);\r
da1d0201 704\r
705 if (Value != NULL) {\r
706 *Value = Item->Value;\r
707 }\r
708\r
709 return Item->Key;\r
710}\r
711\r
712\r
713/**\r
3e7104c2 714 Remove the last entry on the netmap.\r
da1d0201 715\r
3e7104c2 716 @param[in, out] Map The netmap to remove the tail from.\r
717 @param[out] Value The variable to receive the value if not NULL.\r
da1d0201 718\r
3e7104c2 719 @return The key of the item removed.\r
da1d0201 720\r
721**/\r
722VOID *\r
7b414b4e 723EFIAPI\r
da1d0201 724NetMapRemoveTail (\r
3e7104c2 725 IN OUT NET_MAP *Map,\r
da1d0201 726 OUT VOID **Value OPTIONAL\r
727 )\r
728{\r
729 NET_MAP_ITEM *Item;\r
730\r
731 //\r
732 // Often, it indicates a programming error to remove\r
733 // the last entry in an empty list\r
734 //\r
e48e37fc 735 ASSERT (Map && !IsListEmpty (&Map->Used));\r
da1d0201 736\r
737 Item = NET_LIST_TAIL (&Map->Used, NET_MAP_ITEM, Link);\r
e48e37fc 738 RemoveEntryList (&Item->Link);\r
da1d0201 739 Map->Count--;\r
e48e37fc 740 InsertHeadList (&Map->Recycled, &Item->Link);\r
da1d0201 741\r
742 if (Value != NULL) {\r
743 *Value = Item->Value;\r
744 }\r
745\r
746 return Item->Key;\r
747}\r
748\r
749\r
750/**\r
751 Iterate through the netmap and call CallBack for each item. It will\r
752 contiue the traverse if CallBack returns EFI_SUCCESS, otherwise, break\r
753 from the loop. It returns the CallBack's last return value. This\r
754 function is delete safe for the current item.\r
755\r
3e7104c2 756 @param[in] Map The Map to iterate through.\r
757 @param[in] CallBack The callback function to call for each item.\r
758 @param[in] Arg The opaque parameter to the callback.\r
da1d0201 759\r
3e7104c2 760 @retval EFI_SUCCESS There is no item in the netmap or CallBack for each item\r
761 return EFI_SUCCESS.\r
762 @retval Others It returns the CallBack's last return value.\r
da1d0201 763\r
764**/\r
765EFI_STATUS\r
7b414b4e 766EFIAPI\r
da1d0201 767NetMapIterate (\r
768 IN NET_MAP *Map,\r
769 IN NET_MAP_CALLBACK CallBack,\r
770 IN VOID *Arg\r
771 )\r
772{\r
773\r
e48e37fc 774 LIST_ENTRY *Entry;\r
775 LIST_ENTRY *Next;\r
776 LIST_ENTRY *Head;\r
da1d0201 777 NET_MAP_ITEM *Item;\r
778 EFI_STATUS Result;\r
779\r
780 ASSERT ((Map != NULL) && (CallBack != NULL));\r
781\r
782 Head = &Map->Used;\r
783\r
e48e37fc 784 if (IsListEmpty (Head)) {\r
da1d0201 785 return EFI_SUCCESS;\r
786 }\r
787\r
788 NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {\r
789 Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);\r
790 Result = CallBack (Map, Item, Arg);\r
791\r
792 if (EFI_ERROR (Result)) {\r
793 return Result;\r
794 }\r
795 }\r
796\r
797 return EFI_SUCCESS;\r
798}\r
799\r
800\r
801/**\r
802 This is the default unload handle for all the network drivers.\r
803\r
3e7104c2 804 @param[in] ImageHandle The drivers' driver image.\r
da1d0201 805\r
806 @retval EFI_SUCCESS The image is unloaded.\r
807 @retval Others Failed to unload the image.\r
808\r
809**/\r
810EFI_STATUS\r
811EFIAPI\r
812NetLibDefaultUnload (\r
813 IN EFI_HANDLE ImageHandle\r
814 )\r
815{\r
816 EFI_STATUS Status;\r
817 EFI_HANDLE *DeviceHandleBuffer;\r
818 UINTN DeviceHandleCount;\r
819 UINTN Index;\r
820 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
821 EFI_COMPONENT_NAME_PROTOCOL *ComponentName;\r
3012ce5c 822 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;\r
da1d0201 823\r
824 //\r
825 // Get the list of all the handles in the handle database.\r
826 // If there is an error getting the list, then the unload\r
827 // operation fails.\r
828 //\r
829 Status = gBS->LocateHandleBuffer (\r
830 AllHandles,\r
831 NULL,\r
832 NULL,\r
833 &DeviceHandleCount,\r
834 &DeviceHandleBuffer\r
835 );\r
836\r
837 if (EFI_ERROR (Status)) {\r
838 return Status;\r
839 }\r
840\r
841 //\r
842 // Disconnect the driver specified by ImageHandle from all\r
843 // the devices in the handle database.\r
844 //\r
845 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
846 Status = gBS->DisconnectController (\r
847 DeviceHandleBuffer[Index],\r
848 ImageHandle,\r
849 NULL\r
850 );\r
851 }\r
852\r
853 //\r
854 // Uninstall all the protocols installed in the driver entry point\r
855 //\r
856 for (Index = 0; Index < DeviceHandleCount; Index++) {\r
857 Status = gBS->HandleProtocol (\r
858 DeviceHandleBuffer[Index],\r
859 &gEfiDriverBindingProtocolGuid,\r
860 (VOID **) &DriverBinding\r
861 );\r
862\r
863 if (EFI_ERROR (Status)) {\r
864 continue;\r
865 }\r
866\r
867 if (DriverBinding->ImageHandle != ImageHandle) {\r
868 continue;\r
869 }\r
870\r
871 gBS->UninstallProtocolInterface (\r
872 ImageHandle,\r
873 &gEfiDriverBindingProtocolGuid,\r
874 DriverBinding\r
875 );\r
876 Status = gBS->HandleProtocol (\r
877 DeviceHandleBuffer[Index],\r
878 &gEfiComponentNameProtocolGuid,\r
879 (VOID **) &ComponentName\r
880 );\r
881 if (!EFI_ERROR (Status)) {\r
882 gBS->UninstallProtocolInterface (\r
883 ImageHandle,\r
884 &gEfiComponentNameProtocolGuid,\r
885 ComponentName\r
886 );\r
887 }\r
888\r
889 Status = gBS->HandleProtocol (\r
890 DeviceHandleBuffer[Index],\r
3012ce5c 891 &gEfiComponentName2ProtocolGuid,\r
892 (VOID **) &ComponentName2\r
da1d0201 893 );\r
da1d0201 894 if (!EFI_ERROR (Status)) {\r
895 gBS->UninstallProtocolInterface (\r
3012ce5c 896 ImageHandle,\r
897 &gEfiComponentName2ProtocolGuid,\r
898 ComponentName2\r
899 );\r
da1d0201 900 }\r
901 }\r
902\r
903 //\r
904 // Free the buffer containing the list of handles from the handle database\r
905 //\r
906 if (DeviceHandleBuffer != NULL) {\r
907 gBS->FreePool (DeviceHandleBuffer);\r
908 }\r
909\r
910 return EFI_SUCCESS;\r
911}\r
912\r
913\r
914\r
915/**\r
916 Create a child of the service that is identified by ServiceBindingGuid.\r
917\r
3e7104c2 918 @param[in] Controller The controller which has the service installed.\r
919 @param[in] Image The image handle used to open service.\r
920 @param[in] ServiceBindingGuid The service's Guid.\r
921 @param[in, out] ChildHandle The handle to receive the create child\r
da1d0201 922\r
923 @retval EFI_SUCCESS The child is successfully created.\r
924 @retval Others Failed to create the child.\r
925\r
926**/\r
927EFI_STATUS\r
7b414b4e 928EFIAPI\r
da1d0201 929NetLibCreateServiceChild (\r
930 IN EFI_HANDLE Controller,\r
931 IN EFI_HANDLE Image,\r
932 IN EFI_GUID *ServiceBindingGuid,\r
3e7104c2 933 IN OUT EFI_HANDLE *ChildHandle\r
da1d0201 934 )\r
935{\r
936 EFI_STATUS Status;\r
937 EFI_SERVICE_BINDING_PROTOCOL *Service;\r
938\r
939\r
940 ASSERT ((ServiceBindingGuid != NULL) && (ChildHandle != NULL));\r
941\r
942 //\r
943 // Get the ServiceBinding Protocol\r
944 //\r
945 Status = gBS->OpenProtocol (\r
946 Controller,\r
947 ServiceBindingGuid,\r
948 (VOID **) &Service,\r
949 Image,\r
950 Controller,\r
951 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
952 );\r
953\r
954 if (EFI_ERROR (Status)) {\r
955 return Status;\r
956 }\r
957\r
958 //\r
959 // Create a child\r
960 //\r
961 Status = Service->CreateChild (Service, ChildHandle);\r
962 return Status;\r
963}\r
964\r
965\r
966/**\r
967 Destory a child of the service that is identified by ServiceBindingGuid.\r
968\r
3e7104c2 969 @param[in] Controller The controller which has the service installed.\r
970 @param[in] Image The image handle used to open service.\r
971 @param[in] ServiceBindingGuid The service's Guid.\r
972 @param[in] ChildHandle The child to destory\r
da1d0201 973\r
974 @retval EFI_SUCCESS The child is successfully destoried.\r
975 @retval Others Failed to destory the child.\r
976\r
977**/\r
978EFI_STATUS\r
7b414b4e 979EFIAPI\r
da1d0201 980NetLibDestroyServiceChild (\r
981 IN EFI_HANDLE Controller,\r
982 IN EFI_HANDLE Image,\r
983 IN EFI_GUID *ServiceBindingGuid,\r
984 IN EFI_HANDLE ChildHandle\r
985 )\r
986{\r
987 EFI_STATUS Status;\r
988 EFI_SERVICE_BINDING_PROTOCOL *Service;\r
989\r
990 ASSERT (ServiceBindingGuid != NULL);\r
991\r
992 //\r
993 // Get the ServiceBinding Protocol\r
994 //\r
995 Status = gBS->OpenProtocol (\r
996 Controller,\r
997 ServiceBindingGuid,\r
998 (VOID **) &Service,\r
999 Image,\r
1000 Controller,\r
1001 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1002 );\r
1003\r
1004 if (EFI_ERROR (Status)) {\r
1005 return Status;\r
1006 }\r
1007\r
1008 //\r
1009 // destory the child\r
1010 //\r
1011 Status = Service->DestroyChild (Service, ChildHandle);\r
1012 return Status;\r
1013}\r
1014\r
1015\r
1016/**\r
1017 Convert the mac address of the simple network protocol installed on\r
1018 SnpHandle to a unicode string. Callers are responsible for freeing the\r
1019 string storage.\r
1020\r
3e7104c2 1021 @param[in] SnpHandle The handle where the simple network protocol is\r
1022 installed on.\r
1023 @param[in] ImageHandle The image handle used to act as the agent handle to\r
1024 get the simple network protocol.\r
1025 @param[out] MacString The pointer to store the address of the string\r
1026 representation of the mac address.\r
1027 \r
1028 @retval EFI_SUCCESS Convert the mac address a unicode string successfully.\r
da1d0201 1029 @retval EFI_OUT_OF_RESOURCES There are not enough memory resource.\r
3e7104c2 1030 @retval Others Failed to open the simple network protocol.\r
da1d0201 1031\r
1032**/\r
1033EFI_STATUS\r
7b414b4e 1034EFIAPI\r
da1d0201 1035NetLibGetMacString (\r
3e7104c2 1036 IN EFI_HANDLE SnpHandle,\r
1037 IN EFI_HANDLE ImageHandle,\r
1038 OUT CHAR16 **MacString\r
da1d0201 1039 )\r
1040{\r
1041 EFI_STATUS Status;\r
1042 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
1043 EFI_SIMPLE_NETWORK_MODE *Mode;\r
1044 CHAR16 *MacAddress;\r
1045 UINTN Index;\r
1046\r
1047 *MacString = NULL;\r
1048\r
1049 //\r
1050 // Get the Simple Network protocol from the SnpHandle.\r
1051 //\r
1052 Status = gBS->OpenProtocol (\r
1053 SnpHandle,\r
1054 &gEfiSimpleNetworkProtocolGuid,\r
1055 (VOID **) &Snp,\r
1056 ImageHandle,\r
1057 SnpHandle,\r
1058 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1059 );\r
1060 if (EFI_ERROR (Status)) {\r
1061 return Status;\r
1062 }\r
1063\r
1064 Mode = Snp->Mode;\r
1065\r
1066 //\r
1067 // It takes 2 unicode characters to represent a 1 byte binary buffer.\r
1068 // Plus one unicode character for the null-terminator.\r
1069 //\r
e48e37fc 1070 MacAddress = AllocatePool ((2 * Mode->HwAddressSize + 1) * sizeof (CHAR16));\r
da1d0201 1071 if (MacAddress == NULL) {\r
1072 return EFI_OUT_OF_RESOURCES;\r
1073 }\r
1074\r
1075 //\r
1076 // Convert the mac address into a unicode string.\r
1077 //\r
1078 for (Index = 0; Index < Mode->HwAddressSize; Index++) {\r
ac7e320c
LG
1079 MacAddress[Index * 2] = (CHAR16) mNetLibHexStr[(Mode->CurrentAddress.Addr[Index] >> 4) & 0x0F];\r
1080 MacAddress[Index * 2 + 1] = (CHAR16) mNetLibHexStr[Mode->CurrentAddress.Addr[Index] & 0x0F];\r
da1d0201 1081 }\r
1082\r
1083 MacAddress[Mode->HwAddressSize * 2] = L'\0';\r
1084\r
1085 *MacString = MacAddress;\r
1086\r
1087 return EFI_SUCCESS;\r
1088}\r
1089\r
1090/**\r
1091 Check the default address used by the IPv4 driver is static or dynamic (acquired\r
1092 from DHCP).\r
1093\r
3e7104c2 1094 @param[in] Controller The controller handle which has the NIC Ip4 Config Protocol\r
1095 relative with the default address to judge.\r
da1d0201 1096\r
1097 @retval TRUE If the default address is static.\r
1098 @retval FALSE If the default address is acquired from DHCP.\r
1099\r
1100**/\r
da1d0201 1101BOOLEAN\r
1102NetLibDefaultAddressIsStatic (\r
1103 IN EFI_HANDLE Controller\r
1104 )\r
1105{\r
1106 EFI_STATUS Status;\r
1107 EFI_NIC_IP4_CONFIG_PROTOCOL *NicIp4;\r
1108 UINTN Len;\r
1109 NIC_IP4_CONFIG_INFO *ConfigInfo;\r
1110 BOOLEAN IsStatic;\r
1111\r
1112 Status = gBS->HandleProtocol (\r
1113 Controller,\r
1114 &gEfiNicIp4ConfigProtocolGuid,\r
1115 (VOID **) &NicIp4\r
1116 );\r
1117 if (EFI_ERROR (Status)) {\r
1118 return TRUE;\r
1119 }\r
1120\r
1121 Len = 0;\r
1122 Status = NicIp4->GetInfo (NicIp4, &Len, NULL);\r
1123 if (Status != EFI_BUFFER_TOO_SMALL) {\r
1124 return TRUE;\r
1125 }\r
1126\r
e48e37fc 1127 ConfigInfo = AllocatePool (Len);\r
da1d0201 1128 if (ConfigInfo == NULL) {\r
1129 return TRUE;\r
1130 }\r
1131\r
1132 IsStatic = TRUE;\r
1133 Status = NicIp4->GetInfo (NicIp4, &Len, ConfigInfo);\r
1134 if (EFI_ERROR (Status)) {\r
1135 goto ON_EXIT;\r
1136 }\r
1137\r
1138 IsStatic = (BOOLEAN) (ConfigInfo->Source == IP4_CONFIG_SOURCE_STATIC);\r
1139\r
1140ON_EXIT:\r
1141\r
e48e37fc 1142 gBS->FreePool (ConfigInfo);\r
da1d0201 1143\r
1144 return IsStatic;\r
1145}\r
1146\r
1147/**\r
1148 Create an IPv4 device path node.\r
1149\r
3e7104c2 1150 @param[in, out] Node Pointer to the IPv4 device path node.\r
1151 @param[in] Controller The handle where the NIC IP4 config protocol resides.\r
1152 @param[in] LocalIp The local IPv4 address.\r
1153 @param[in] LocalPort The local port.\r
1154 @param[in] RemoteIp The remote IPv4 address.\r
1155 @param[in] RemotePort The remote port.\r
1156 @param[in] Protocol The protocol type in the IP header.\r
1157 @param[in] UseDefaultAddress Whether this instance is using default address or not.\r
da1d0201 1158\r
da1d0201 1159**/\r
1160VOID\r
7b414b4e 1161EFIAPI\r
da1d0201 1162NetLibCreateIPv4DPathNode (\r
1163 IN OUT IPv4_DEVICE_PATH *Node,\r
1164 IN EFI_HANDLE Controller,\r
1165 IN IP4_ADDR LocalIp,\r
1166 IN UINT16 LocalPort,\r
1167 IN IP4_ADDR RemoteIp,\r
1168 IN UINT16 RemotePort,\r
1169 IN UINT16 Protocol,\r
1170 IN BOOLEAN UseDefaultAddress\r
1171 )\r
1172{\r
1173 Node->Header.Type = MESSAGING_DEVICE_PATH;\r
1174 Node->Header.SubType = MSG_IPv4_DP;\r
1175 SetDevicePathNodeLength (&Node->Header, 19);\r
1176\r
e48e37fc 1177 CopyMem (&Node->LocalIpAddress, &LocalIp, sizeof (EFI_IPv4_ADDRESS));\r
1178 CopyMem (&Node->RemoteIpAddress, &RemoteIp, sizeof (EFI_IPv4_ADDRESS));\r
da1d0201 1179\r
1180 Node->LocalPort = LocalPort;\r
1181 Node->RemotePort = RemotePort;\r
1182\r
1183 Node->Protocol = Protocol;\r
1184\r
1185 if (!UseDefaultAddress) {\r
1186 Node->StaticIpAddress = TRUE;\r
1187 } else {\r
1188 Node->StaticIpAddress = NetLibDefaultAddressIsStatic (Controller);\r
1189 }\r
1190}\r
1191\r
1192\r
1193/**\r
1194 Find the UNDI/SNP handle from controller and protocol GUID.\r
1195 For example, IP will open a MNP child to transmit/receive\r
1196 packets, when MNP is stopped, IP should also be stopped. IP\r
1197 needs to find its own private data which is related the IP's\r
1198 service binding instance that is install on UNDI/SNP handle.\r
1199 Now, the controller is either a MNP or ARP child handle. But\r
1200 IP opens these handle BY_DRIVER, use that info, we can get the\r
1201 UNDI/SNP handle.\r
1202\r
3e7104c2 1203 @param[in] Controller Then protocol handle to check.\r
1204 @param[in] ProtocolGuid The protocol that is related with the handle.\r
da1d0201 1205\r
3e7104c2 1206 @return The UNDI/SNP handle or NULL for errors.\r
da1d0201 1207\r
1208**/\r
1209EFI_HANDLE\r
7b414b4e 1210EFIAPI\r
da1d0201 1211NetLibGetNicHandle (\r
1212 IN EFI_HANDLE Controller,\r
1213 IN EFI_GUID *ProtocolGuid\r
1214 )\r
1215{\r
1216 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenBuffer;\r
1217 EFI_HANDLE Handle;\r
1218 EFI_STATUS Status;\r
1219 UINTN OpenCount;\r
1220 UINTN Index;\r
1221\r
1222 Status = gBS->OpenProtocolInformation (\r
1223 Controller,\r
1224 ProtocolGuid,\r
1225 &OpenBuffer,\r
1226 &OpenCount\r
1227 );\r
1228\r
1229 if (EFI_ERROR (Status)) {\r
1230 return NULL;\r
1231 }\r
1232\r
1233 Handle = NULL;\r
1234\r
1235 for (Index = 0; Index < OpenCount; Index++) {\r
1236 if (OpenBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) {\r
1237 Handle = OpenBuffer[Index].ControllerHandle;\r
1238 break;\r
1239 }\r
1240 }\r
1241\r
1242 gBS->FreePool (OpenBuffer);\r
1243 return Handle;\r
1244}\r
1245\r
36ee91ca 1246/**\r
1247 Add a Deferred Procedure Call to the end of the DPC queue.\r
1248\r
3e7104c2 1249 @param[in] DpcTpl The EFI_TPL that the DPC should be invoked.\r
1250 @param[in] DpcProcedure Pointer to the DPC's function.\r
1251 @param[in] DpcContext Pointer to the DPC's context. Passed to DpcProcedure\r
1252 when DpcProcedure is invoked.\r
36ee91ca 1253\r
1254 @retval EFI_SUCCESS The DPC was queued.\r
3e7104c2 1255 @retval EFI_INVALID_PARAMETER DpcTpl is not a valid EFI_TPL, or DpcProcedure\r
1256 is NULL.\r
36ee91ca 1257 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to\r
1258 add the DPC to the queue.\r
1259\r
1260**/\r
1261EFI_STATUS\r
7b414b4e 1262EFIAPI\r
36ee91ca 1263NetLibQueueDpc (\r
1264 IN EFI_TPL DpcTpl,\r
1265 IN EFI_DPC_PROCEDURE DpcProcedure,\r
1266 IN VOID *DpcContext OPTIONAL\r
1267 )\r
1268{\r
1269 return mDpc->QueueDpc (mDpc, DpcTpl, DpcProcedure, DpcContext);\r
1270}\r
1271\r
1272/**\r
3e7104c2 1273 Dispatch the queue of DPCs. ALL DPCs that have been queued with a DpcTpl\r
1274 value greater than or equal to the current TPL are invoked in the order that\r
1275 they were queued. DPCs with higher DpcTpl values are invoked before DPCs with\r
1276 lower DpcTpl values.\r
36ee91ca 1277\r
1278 @retval EFI_SUCCESS One or more DPCs were invoked.\r
1279 @retval EFI_NOT_FOUND No DPCs were invoked.\r
1280\r
1281**/\r
1282EFI_STATUS\r
7b414b4e 1283EFIAPI\r
36ee91ca 1284NetLibDispatchDpc (\r
1285 VOID\r
1286 )\r
1287{\r
1288 return mDpc->DispatchDpc(mDpc);\r
1289}\r
1290\r
36ee91ca 1291/**\r
1292 The constructor function caches the pointer to DPC protocol.\r
1293\r
1294 The constructor function locates DPC protocol from protocol database.\r
1295 It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.\r
1296\r
3e7104c2 1297 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
1298 @param[in] SystemTable A pointer to the EFI System Table.\r
36ee91ca 1299\r
1300 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
1301\r
1302**/\r
1303EFI_STATUS\r
1304EFIAPI\r
1305NetLibConstructor (\r
1306 IN EFI_HANDLE ImageHandle,\r
1307 IN EFI_SYSTEM_TABLE *SystemTable\r
1308 )\r
1309{\r
1310 EFI_STATUS Status;\r
1311\r
1312 Status = gBS->LocateProtocol (&gEfiDpcProtocolGuid, NULL, (VOID**) &mDpc);\r
1313 ASSERT_EFI_ERROR (Status);\r
1314 ASSERT (mDpc != NULL);\r
1315\r
1316 return Status;\r
1317}\r