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