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