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