2 The driver binding and service binding protocol for IP6 driver.
4 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php.
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 EFI_DRIVER_BINDING_PROTOCOL gIp6DriverBinding
= {
20 Ip6DriverBindingSupported
,
21 Ip6DriverBindingStart
,
28 BOOLEAN mIpSec2Installed
= FALSE
;
31 Callback function for IpSec2 Protocol install.
33 @param[in] Event Event whose notification function is being invoked
34 @param[in] Context Pointer to the notification function's context
36 @retval EFI_SUCCESS Callback successful.
40 IpSec2InstalledCallback (
46 // Close the event so it does not get called again.
48 gBS
->CloseEvent (Event
);
50 mIpSec2Installed
= TRUE
;
56 This is the declaration of an EFI image entry point. This entry point is
57 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
58 both device drivers and bus drivers.
60 The entry point for IP6 driver which installs the driver
61 binding and component name protocol on its image.
63 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
64 @param[in] SystemTable A pointer to the EFI System Table.
66 @retval EFI_SUCCESS The operation completed successfully.
67 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
73 IN EFI_HANDLE ImageHandle
,
74 IN EFI_SYSTEM_TABLE
*SystemTable
79 EfiCreateProtocolNotifyEvent (
80 &gEfiIpSec2ProtocolGuid
,
82 IpSec2InstalledCallback
,
87 return EfiLibInstallDriverBindingComponentName2 (
98 Test to see if this driver supports ControllerHandle.
100 @param[in] This Protocol instance pointer.
101 @param[in] ControllerHandle Handle of device to test.
102 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
105 @retval EFI_SUCCESS This driver supports this device.
106 @retval EFI_ALREADY_STARTED This driver is already running on this device.
107 @retval other This driver does not support this device.
112 Ip6DriverBindingSupported (
113 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
114 IN EFI_HANDLE ControllerHandle
,
115 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
119 // Test for the MNP service binding Protocol
121 return gBS
->OpenProtocol (
123 &gEfiManagedNetworkServiceBindingProtocolGuid
,
125 This
->DriverBindingHandle
,
127 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
132 Clean up an IP6 service binding instance. It releases all
133 the resource allocated by the instance. The instance may be
134 partly initialized, or partly destroyed. If a resource is
135 destroyed, it is marked as that in case the destroy failed and
136 being called again later.
138 @param[in] IpSb The IP6 service binding instance to clean up.
140 @retval EFI_SUCCESS The resource used by the instance are cleaned up.
141 @retval Others Failed to clean up some of the resources.
150 EFI_IPv6_ADDRESS AllNodes
;
151 IP6_NEIGHBOR_ENTRY
*NeighborCache
;
153 Ip6ConfigCleanInstance (&IpSb
->Ip6ConfigInstance
);
155 if (!IpSb
->LinkLocalDadFail
) {
157 // Leave link-scope all-nodes multicast address (FF02::1)
159 Ip6SetToAllNodeMulticast (FALSE
, IP6_LINK_LOCAL_SCOPE
, &AllNodes
);
161 Status
= Ip6LeaveGroup (IpSb
, &AllNodes
);
162 if (EFI_ERROR (Status
)) {
167 if (IpSb
->DefaultInterface
!= NULL
) {
168 Ip6CleanInterface (IpSb
->DefaultInterface
, NULL
);
169 IpSb
->DefaultInterface
= NULL
;
172 Ip6CleanDefaultRouterList (IpSb
);
174 Ip6CleanPrefixListTable (IpSb
, &IpSb
->OnlinkPrefix
);
175 Ip6CleanPrefixListTable (IpSb
, &IpSb
->AutonomousPrefix
);
177 if (IpSb
->RouteTable
!= NULL
) {
178 Ip6CleanRouteTable (IpSb
->RouteTable
);
179 IpSb
->RouteTable
= NULL
;
182 if (IpSb
->InterfaceId
!= NULL
) {
183 FreePool (IpSb
->InterfaceId
);
186 IpSb
->InterfaceId
= NULL
;
188 Ip6CleanAssembleTable (&IpSb
->Assemble
);
190 if (IpSb
->MnpChildHandle
!= NULL
) {
191 if (IpSb
->Mnp
!= NULL
) {
192 IpSb
->Mnp
->Cancel (IpSb
->Mnp
, NULL
);
193 IpSb
->Mnp
->Configure (IpSb
->Mnp
, NULL
);
195 IpSb
->MnpChildHandle
,
196 &gEfiManagedNetworkProtocolGuid
,
204 NetLibDestroyServiceChild (
207 &gEfiManagedNetworkServiceBindingProtocolGuid
,
211 IpSb
->MnpChildHandle
= NULL
;
214 if (IpSb
->RecvRequest
.MnpToken
.Event
!= NULL
) {
215 gBS
->CloseEvent (IpSb
->RecvRequest
.MnpToken
.Event
);
218 if (IpSb
->Timer
!= NULL
) {
219 gBS
->SetTimer (IpSb
->Timer
, TimerCancel
, 0);
220 gBS
->CloseEvent (IpSb
->Timer
);
225 if (IpSb
->FasterTimer
!= NULL
) {
226 gBS
->SetTimer (IpSb
->FasterTimer
, TimerCancel
, 0);
227 gBS
->CloseEvent (IpSb
->FasterTimer
);
229 IpSb
->FasterTimer
= NULL
;
232 // Free the Neighbor Discovery resources
234 while (!IsListEmpty (&IpSb
->NeighborTable
)) {
235 NeighborCache
= NET_LIST_HEAD (&IpSb
->NeighborTable
, IP6_NEIGHBOR_ENTRY
, Link
);
236 Ip6FreeNeighborEntry (IpSb
, NeighborCache
, FALSE
, TRUE
, EFI_SUCCESS
, NULL
, NULL
);
243 Create a new IP6 driver service binding protocol.
245 @param[in] Controller The controller that has MNP service binding
247 @param[in] ImageHandle The IP6 driver's image handle.
248 @param[out] Service The variable to receive the newly created IP6
251 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.
252 @retval EFI_SUCCESS A new IP6 service binding private is created.
257 IN EFI_HANDLE Controller
,
258 IN EFI_HANDLE ImageHandle
,
259 OUT IP6_SERVICE
**Service
264 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*MnpToken
;
265 EFI_MANAGED_NETWORK_CONFIG_DATA
*Config
;
266 IP6_CONFIG_DATA_ITEM
*DataItem
;
268 ASSERT (Service
!= NULL
);
273 // allocate a service private data then initialize all the filed to
274 // empty resources, so if any thing goes wrong when allocating
275 // resources, Ip6CleanService can be called to clean it up.
277 IpSb
= AllocateZeroPool (sizeof (IP6_SERVICE
));
280 return EFI_OUT_OF_RESOURCES
;
283 IpSb
->Signature
= IP6_SERVICE_SIGNATURE
;
284 IpSb
->ServiceBinding
.CreateChild
= Ip6ServiceBindingCreateChild
;
285 IpSb
->ServiceBinding
.DestroyChild
= Ip6ServiceBindingDestroyChild
;
286 IpSb
->State
= IP6_SERVICE_UNSTARTED
;
288 IpSb
->NumChildren
= 0;
289 InitializeListHead (&IpSb
->Children
);
291 InitializeListHead (&IpSb
->Interfaces
);
292 IpSb
->DefaultInterface
= NULL
;
293 IpSb
->RouteTable
= NULL
;
295 IpSb
->RecvRequest
.Signature
= IP6_LINK_RX_SIGNATURE
;
296 IpSb
->RecvRequest
.CallBack
= NULL
;
297 IpSb
->RecvRequest
.Context
= NULL
;
298 MnpToken
= &IpSb
->RecvRequest
.MnpToken
;
299 MnpToken
->Event
= NULL
;
300 MnpToken
->Status
= EFI_NOT_READY
;
301 MnpToken
->Packet
.RxData
= NULL
;
303 Ip6CreateAssembleTable (&IpSb
->Assemble
);
305 IpSb
->MldCtrl
.Mldv1QuerySeen
= 0;
306 InitializeListHead (&IpSb
->MldCtrl
.Groups
);
308 ZeroMem (&IpSb
->LinkLocalAddr
, sizeof (EFI_IPv6_ADDRESS
));
309 IpSb
->LinkLocalOk
= FALSE
;
310 IpSb
->LinkLocalDadFail
= FALSE
;
311 IpSb
->Dhcp6NeedStart
= FALSE
;
312 IpSb
->Dhcp6NeedInfoRequest
= FALSE
;
314 IpSb
->CurHopLimit
= IP6_HOP_LIMIT
;
315 IpSb
->LinkMTU
= IP6_MIN_LINK_MTU
;
316 IpSb
->BaseReachableTime
= IP6_REACHABLE_TIME
;
317 Ip6UpdateReachableTime (IpSb
);
319 // RFC4861 RETRANS_TIMER: 1,000 milliseconds
321 IpSb
->RetransTimer
= IP6_RETRANS_TIMER
;
323 IpSb
->RoundRobin
= 0;
325 InitializeListHead (&IpSb
->NeighborTable
);
326 InitializeListHead (&IpSb
->DefaultRouterList
);
327 InitializeListHead (&IpSb
->OnlinkPrefix
);
328 InitializeListHead (&IpSb
->AutonomousPrefix
);
330 IpSb
->InterfaceIdLen
= IP6_IF_ID_LEN
;
331 IpSb
->InterfaceId
= NULL
;
333 IpSb
->RouterAdvertiseReceived
= FALSE
;
334 IpSb
->SolicitTimer
= IP6_MAX_RTR_SOLICITATIONS
;
337 IpSb
->Image
= ImageHandle
;
338 IpSb
->Controller
= Controller
;
340 IpSb
->MnpChildHandle
= NULL
;
343 Config
= &IpSb
->MnpConfigData
;
344 Config
->ReceivedQueueTimeoutValue
= 0;
345 Config
->TransmitQueueTimeoutValue
= 0;
346 Config
->ProtocolTypeFilter
= IP6_ETHER_PROTO
;
347 Config
->EnableUnicastReceive
= TRUE
;
348 Config
->EnableMulticastReceive
= TRUE
;
349 Config
->EnableBroadcastReceive
= TRUE
;
350 Config
->EnablePromiscuousReceive
= FALSE
;
351 Config
->FlushQueuesOnReset
= TRUE
;
352 Config
->EnableReceiveTimestamps
= FALSE
;
353 Config
->DisableBackgroundPolling
= FALSE
;
355 ZeroMem (&IpSb
->SnpMode
, sizeof (EFI_SIMPLE_NETWORK_MODE
));
358 IpSb
->FasterTimer
= NULL
;
360 ZeroMem (&IpSb
->Ip6ConfigInstance
, sizeof (IP6_CONFIG_INSTANCE
));
362 IpSb
->MacString
= NULL
;
365 // Create various resources. First create the route table, timer
366 // event, MNP token event and MNP child.
369 IpSb
->RouteTable
= Ip6CreateRouteTable ();
370 if (IpSb
->RouteTable
== NULL
) {
371 Status
= EFI_OUT_OF_RESOURCES
;
375 Status
= gBS
->CreateEvent (
376 EVT_NOTIFY_SIGNAL
| EVT_TIMER
,
382 if (EFI_ERROR (Status
)) {
386 Status
= gBS
->CreateEvent (
387 EVT_NOTIFY_SIGNAL
| EVT_TIMER
,
389 Ip6NdFasterTimerTicking
,
393 if (EFI_ERROR (Status
)) {
397 Status
= NetLibCreateServiceChild (
400 &gEfiManagedNetworkServiceBindingProtocolGuid
,
401 &IpSb
->MnpChildHandle
403 if (EFI_ERROR (Status
)) {
407 Status
= gBS
->OpenProtocol (
408 IpSb
->MnpChildHandle
,
409 &gEfiManagedNetworkProtocolGuid
,
410 (VOID
**) (&IpSb
->Mnp
),
413 EFI_OPEN_PROTOCOL_BY_DRIVER
415 if (EFI_ERROR (Status
)) {
419 Status
= Ip6ServiceConfigMnp (IpSb
, TRUE
);
420 if (EFI_ERROR (Status
)) {
424 Status
= IpSb
->Mnp
->GetModeData (IpSb
->Mnp
, NULL
, &IpSb
->SnpMode
);
425 if (EFI_ERROR (Status
)) {
429 IpSb
->MaxPacketSize
= IP6_MIN_LINK_MTU
- sizeof (EFI_IP6_HEADER
);
430 if (NetLibGetVlanId (IpSb
->Controller
) != 0) {
432 // This is a VLAN device, reduce MTU by VLAN tag length
434 IpSb
->MaxPacketSize
-= NET_VLAN_TAG_LEN
;
436 IpSb
->OldMaxPacketSize
= IpSb
->MaxPacketSize
;
439 // Currently only ETHERNET is supported in IPv6 stack, since
440 // link local address requires an IEEE 802 48-bit MACs for
441 // EUI-64 format interface identifier mapping.
443 if (IpSb
->SnpMode
.IfType
!= NET_IFTYPE_ETHERNET
) {
444 Status
= EFI_UNSUPPORTED
;
448 Status
= Ip6InitMld (IpSb
);
449 if (EFI_ERROR (Status
)) {
453 Status
= NetLibGetMacString (IpSb
->Controller
, IpSb
->Image
, &IpSb
->MacString
);
454 if (EFI_ERROR (Status
)) {
458 Status
= Ip6ConfigInitInstance (&IpSb
->Ip6ConfigInstance
);
459 if (EFI_ERROR (Status
)) {
463 IpSb
->DefaultInterface
= Ip6CreateInterface (IpSb
, TRUE
);
464 if (IpSb
->DefaultInterface
== NULL
) {
465 Status
= EFI_DEVICE_ERROR
;
469 Status
= gBS
->CreateEvent (
476 if (EFI_ERROR (Status
)) {
481 // If there is any manual address, set it.
483 DataItem
= &IpSb
->Ip6ConfigInstance
.DataItem
[Ip6ConfigDataTypeManualAddress
];
484 if (DataItem
->Data
.Ptr
!= NULL
) {
486 &IpSb
->Ip6ConfigInstance
,
493 // If there is any gateway address, set it.
495 DataItem
= &IpSb
->Ip6ConfigInstance
.DataItem
[Ip6ConfigDataTypeGateway
];
496 if (DataItem
->Data
.Ptr
!= NULL
) {
498 &IpSb
->Ip6ConfigInstance
,
504 InsertHeadList (&IpSb
->Interfaces
, &IpSb
->DefaultInterface
->Link
);
510 Ip6CleanService (IpSb
);
517 Start this driver on ControllerHandle.
519 @param[in] This Protocol instance pointer.
520 @param[in] ControllerHandle Handle of device to bind driver to.
521 @param[in] RemainingDevicePath Optional parameter used to pick a specific child
524 @retval EFI_SUCCES This driver is added to ControllerHandle.
525 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
526 @retval other This driver does not support this device.
531 Ip6DriverBindingStart (
532 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
533 IN EFI_HANDLE ControllerHandle
,
534 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
541 // Test for the Ip6 service binding protocol
543 Status
= gBS
->OpenProtocol (
545 &gEfiIp6ServiceBindingProtocolGuid
,
547 This
->DriverBindingHandle
,
549 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
552 if (Status
== EFI_SUCCESS
) {
553 return EFI_ALREADY_STARTED
;
556 Status
= Ip6CreateService (ControllerHandle
, This
->DriverBindingHandle
, &IpSb
);
558 if (EFI_ERROR (Status
)) {
562 ASSERT (IpSb
!= NULL
);
565 // Install the Ip6ServiceBinding Protocol onto ControlerHandle
567 Status
= gBS
->InstallMultipleProtocolInterfaces (
569 &gEfiIp6ServiceBindingProtocolGuid
,
570 &IpSb
->ServiceBinding
,
571 &gEfiIp6ConfigProtocolGuid
,
572 &IpSb
->Ip6ConfigInstance
.Ip6Config
,
576 if (!EFI_ERROR (Status
)) {
578 // ready to go: start the receiving and timer
580 Status
= Ip6ReceiveFrame (Ip6AcceptFrame
, IpSb
);
581 if (EFI_ERROR (Status
)) {
586 // The timer expires every 100 (IP6_TIMER_INTERVAL_IN_MS) milliseconds.
588 Status
= gBS
->SetTimer (
591 TICKS_PER_MS
* IP6_TIMER_INTERVAL_IN_MS
593 if (EFI_ERROR (Status
)) {
598 // The timer expires every 1000 (IP6_ONE_SECOND_IN_MS) milliseconds.
600 Status
= gBS
->SetTimer (
603 TICKS_PER_MS
* IP6_ONE_SECOND_IN_MS
605 if (EFI_ERROR (Status
)) {
610 // Initialize the IP6 ID
612 mIp6Id
= NET_RANDOM (NetRandomInitSeed ());
618 Ip6CleanService (IpSb
);
624 Callback function which provided by user to remove one node in NetDestroyLinkList process.
626 @param[in] Entry The entry to be removed.
627 @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
629 @retval EFI_SUCCESS The entry has been removed successfully.
630 @retval Others Fail to remove the entry.
635 Ip6DestroyChildEntryInHandleBuffer (
636 IN LIST_ENTRY
*Entry
,
640 IP6_PROTOCOL
*IpInstance
;
641 EFI_SERVICE_BINDING_PROTOCOL
*ServiceBinding
;
642 UINTN NumberOfChildren
;
643 EFI_HANDLE
*ChildHandleBuffer
;
645 if (Entry
== NULL
|| Context
== NULL
) {
646 return EFI_INVALID_PARAMETER
;
649 IpInstance
= NET_LIST_USER_STRUCT_S (Entry
, IP6_PROTOCOL
, Link
, IP6_PROTOCOL_SIGNATURE
);
650 ServiceBinding
= ((IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT
*) Context
)->ServiceBinding
;
651 NumberOfChildren
= ((IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT
*) Context
)->NumberOfChildren
;
652 ChildHandleBuffer
= ((IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT
*) Context
)->ChildHandleBuffer
;
654 if (!NetIsInHandleBuffer (IpInstance
->Handle
, NumberOfChildren
, ChildHandleBuffer
)) {
658 return ServiceBinding
->DestroyChild (ServiceBinding
, IpInstance
->Handle
);
662 Stop this driver on ControllerHandle.
664 @param[in] This Protocol instance pointer.
665 @param[in] ControllerHandle Handle of device to stop driver on.
666 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number
667 of children is zero, stop the entire bus driver.
668 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
669 if NumberOfChildren is 0.
671 @retval EFI_SUCCESS The device was stopped.
672 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
677 Ip6DriverBindingStop (
678 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
679 IN EFI_HANDLE ControllerHandle
,
680 IN UINTN NumberOfChildren
,
681 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
684 EFI_SERVICE_BINDING_PROTOCOL
*ServiceBinding
;
686 EFI_HANDLE NicHandle
;
691 IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context
;
694 NicHandle
= NetLibGetNicHandle (ControllerHandle
, &gEfiManagedNetworkProtocolGuid
);
695 if (NicHandle
== NULL
) {
696 NicHandle
= NetLibGetNicHandle (ControllerHandle
, &gEfiDhcp6ProtocolGuid
);
697 if (NicHandle
!= NULL
) {
704 Status
= gBS
->OpenProtocol (
706 &gEfiIp6ServiceBindingProtocolGuid
,
707 (VOID
**) &ServiceBinding
,
708 This
->DriverBindingHandle
,
710 EFI_OPEN_PROTOCOL_GET_PROTOCOL
712 if (EFI_ERROR (Status
)) {
713 return EFI_DEVICE_ERROR
;
716 IpSb
= IP6_SERVICE_FROM_PROTOCOL (ServiceBinding
);
719 Status
= Ip6ConfigDestroyDhcp6 (&IpSb
->Ip6ConfigInstance
);
720 gBS
->CloseEvent (IpSb
->Ip6ConfigInstance
.Dhcp6Event
);
721 IpSb
->Ip6ConfigInstance
.Dhcp6Event
= NULL
;
722 } else if (NumberOfChildren
!= 0) {
724 // NumberOfChildren is not zero, destroy the IP6 children instances in ChildHandleBuffer.
726 List
= &IpSb
->Children
;
727 Context
.ServiceBinding
= ServiceBinding
;
728 Context
.NumberOfChildren
= NumberOfChildren
;
729 Context
.ChildHandleBuffer
= ChildHandleBuffer
;
730 Status
= NetDestroyLinkList (
732 Ip6DestroyChildEntryInHandleBuffer
,
736 } else if (IsListEmpty (&IpSb
->Children
)) {
738 IpSb
->State
= IP6_SERVICE_DESTROY
;
740 Status
= Ip6CleanService (IpSb
);
741 if (EFI_ERROR (Status
)) {
746 Status
= gBS
->UninstallMultipleProtocolInterfaces (
748 &gEfiIp6ServiceBindingProtocolGuid
,
750 &gEfiIp6ConfigProtocolGuid
,
751 &IpSb
->Ip6ConfigInstance
.Ip6Config
,
754 ASSERT_EFI_ERROR (Status
);
756 Status
= EFI_SUCCESS
;
765 Creates a child handle with a set of I/O services.
767 @param[in] This Protocol instance pointer.
768 @param[in] ChildHandle Pointer to the handle of the child to create. If
769 it is NULL, then a new handle is created. If it
770 is not NULL, then the I/O services are added to
771 the existing child handle.
773 @retval EFI_SUCCES The child handle was created with the I/O services.
774 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
776 @retval other The child handle was not created.
781 Ip6ServiceBindingCreateChild (
782 IN EFI_SERVICE_BINDING_PROTOCOL
*This
,
783 IN EFI_HANDLE
*ChildHandle
787 IP6_PROTOCOL
*IpInstance
;
792 if ((This
== NULL
) || (ChildHandle
== NULL
)) {
793 return EFI_INVALID_PARAMETER
;
796 IpSb
= IP6_SERVICE_FROM_PROTOCOL (This
);
798 if (IpSb
->LinkLocalDadFail
) {
799 return EFI_DEVICE_ERROR
;
802 IpInstance
= AllocatePool (sizeof (IP6_PROTOCOL
));
804 if (IpInstance
== NULL
) {
805 return EFI_OUT_OF_RESOURCES
;
808 Ip6InitProtocol (IpSb
, IpInstance
);
811 // Install Ip6 onto ChildHandle
813 Status
= gBS
->InstallMultipleProtocolInterfaces (
815 &gEfiIp6ProtocolGuid
,
816 &IpInstance
->Ip6Proto
,
819 if (EFI_ERROR (Status
)) {
823 IpInstance
->Handle
= *ChildHandle
;
826 // Open the Managed Network protocol BY_CHILD.
828 Status
= gBS
->OpenProtocol (
829 IpSb
->MnpChildHandle
,
830 &gEfiManagedNetworkProtocolGuid
,
832 gIp6DriverBinding
.DriverBindingHandle
,
834 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
836 if (EFI_ERROR (Status
)) {
837 gBS
->UninstallMultipleProtocolInterfaces (
839 &gEfiIp6ProtocolGuid
,
840 &IpInstance
->Ip6Proto
,
848 // Insert it into the service binding instance.
850 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
852 InsertTailList (&IpSb
->Children
, &IpInstance
->Link
);
855 gBS
->RestoreTPL (OldTpl
);
859 if (EFI_ERROR (Status
)) {
861 Ip6CleanProtocol (IpInstance
);
863 FreePool (IpInstance
);
870 Destroys a child handle with a set of I/O services.
872 @param[in] This Protocol instance pointer.
873 @param[in] ChildHandle Handle of the child to destroy.
875 @retval EFI_SUCCES The I/O services were removed from the child
877 @retval EFI_UNSUPPORTED The child handle does not support the I/O services
878 that are being removed.
879 @retval EFI_INVALID_PARAMETER Child handle is NULL.
880 @retval EFI_ACCESS_DENIED The child handle could not be destroyed because
881 its I/O services are being used.
882 @retval other The child handle was not destroyed.
887 Ip6ServiceBindingDestroyChild (
888 IN EFI_SERVICE_BINDING_PROTOCOL
*This
,
889 IN EFI_HANDLE ChildHandle
894 IP6_PROTOCOL
*IpInstance
;
895 EFI_IP6_PROTOCOL
*Ip6
;
898 if ((This
== NULL
) || (ChildHandle
== NULL
)) {
899 return EFI_INVALID_PARAMETER
;
903 // Retrieve the private context data structures
905 IpSb
= IP6_SERVICE_FROM_PROTOCOL (This
);
907 Status
= gBS
->OpenProtocol (
909 &gEfiIp6ProtocolGuid
,
911 gIp6DriverBinding
.DriverBindingHandle
,
913 EFI_OPEN_PROTOCOL_GET_PROTOCOL
916 if (EFI_ERROR (Status
)) {
917 return EFI_UNSUPPORTED
;
920 IpInstance
= IP6_INSTANCE_FROM_PROTOCOL (Ip6
);
922 if (IpInstance
->Service
!= IpSb
) {
923 return EFI_INVALID_PARAMETER
;
926 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
929 // A child can be destroyed more than once. For example,
930 // Ip6DriverBindingStop will destroy all of its children.
931 // when UDP driver is being stopped, it will destroy all
932 // the IP child it opens.
934 if (IpInstance
->InDestroy
) {
935 gBS
->RestoreTPL (OldTpl
);
939 IpInstance
->InDestroy
= TRUE
;
942 // Close the Managed Network protocol.
945 IpSb
->MnpChildHandle
,
946 &gEfiManagedNetworkProtocolGuid
,
947 gIp6DriverBinding
.DriverBindingHandle
,
952 // Uninstall the IP6 protocol first. Many thing happens during
954 // 1. The consumer of the IP6 protocol will be stopped if it
955 // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
956 // stopped, IP driver's stop function will be called, and uninstall
957 // EFI_IP6_PROTOCOL will trigger the UDP's stop function. This
958 // makes it possible to create the network stack bottom up, and
960 // 2. the upper layer will recycle the received packet. The recycle
961 // event's TPL is higher than this function. The recycle events
962 // will be called back before preceeding. If any packets not recycled,
963 // that means there is a resource leak.
965 gBS
->RestoreTPL (OldTpl
);
966 Status
= gBS
->UninstallProtocolInterface (
968 &gEfiIp6ProtocolGuid
,
969 &IpInstance
->Ip6Proto
971 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
972 if (EFI_ERROR (Status
)) {
976 Status
= Ip6CleanProtocol (IpInstance
);
977 if (EFI_ERROR (Status
)) {
978 gBS
->InstallMultipleProtocolInterfaces (
980 &gEfiIp6ProtocolGuid
,
988 RemoveEntryList (&IpInstance
->Link
);
989 ASSERT (IpSb
->NumChildren
> 0);
992 gBS
->RestoreTPL (OldTpl
);
994 FreePool (IpInstance
);
998 gBS
->RestoreTPL (OldTpl
);