1 /** @file
2   The driver binding and service binding protocol for IP6 driver.
3 
4   Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
5   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
6 
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.
11 
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.
14 
15 **/
16 
17 #include "Ip6Impl.h"
18 
19 EFI_DRIVER_BINDING_PROTOCOL gIp6DriverBinding = {
20   Ip6DriverBindingSupported,
21   Ip6DriverBindingStart,
22   Ip6DriverBindingStop,
23   0xa,
24   NULL,
25   NULL
26 };
27 
28 BOOLEAN  mIpSec2Installed = FALSE;
29 
30 /**
31    Callback function for IpSec2 Protocol install.
32 
33    @param[in] Event           Event whose notification function is being invoked
34    @param[in] Context         Pointer to the notification function's context
35 
36 **/
37 VOID
38 EFIAPI
IpSec2InstalledCallback(IN EFI_EVENT Event,IN VOID * Context)39 IpSec2InstalledCallback (
40   IN EFI_EVENT  Event,
41   IN VOID       *Context
42   )
43 {
44   //
45   // Close the event so it does not get called again.
46   //
47   gBS->CloseEvent (Event);
48 
49   mIpSec2Installed = TRUE;
50 
51   return;
52 }
53 
54 /**
55   This is the declaration of an EFI image entry point. This entry point is
56   the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
57   both device drivers and bus drivers.
58 
59   The entry point for IP6 driver which installs the driver
60   binding and component name protocol on its image.
61 
62   @param[in]  ImageHandle           The firmware allocated handle for the UEFI image.
63   @param[in]  SystemTable           A pointer to the EFI System Table.
64 
65   @retval EFI_SUCCESS           The operation completed successfully.
66   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
67 
68 **/
69 EFI_STATUS
70 EFIAPI
Ip6DriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)71 Ip6DriverEntryPoint (
72   IN EFI_HANDLE             ImageHandle,
73   IN EFI_SYSTEM_TABLE       *SystemTable
74   )
75 {
76   VOID            *Registration;
77 
78   EfiCreateProtocolNotifyEvent (
79     &gEfiIpSec2ProtocolGuid,
80     TPL_CALLBACK,
81     IpSec2InstalledCallback,
82     NULL,
83     &Registration
84     );
85 
86   return EfiLibInstallDriverBindingComponentName2 (
87            ImageHandle,
88            SystemTable,
89            &gIp6DriverBinding,
90            ImageHandle,
91            &gIp6ComponentName,
92            &gIp6ComponentName2
93            );
94 }
95 
96 /**
97   Test to see if this driver supports ControllerHandle.
98 
99   @param[in]  This                   Protocol instance pointer.
100   @param[in]  ControllerHandle       Handle of device to test.
101   @param[in]  RemainingDevicePath    Optional parameter use to pick a specific child
102                                      device to start.
103 
104   @retval EFI_SUCCESS                This driver supports this device.
105   @retval EFI_ALREADY_STARTED        This driver is already running on this device.
106   @retval other                      This driver does not support this device.
107 
108 **/
109 EFI_STATUS
110 EFIAPI
Ip6DriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)111 Ip6DriverBindingSupported (
112   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
113   IN EFI_HANDLE                   ControllerHandle,
114   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
115   )
116 {
117   //
118   // Test for the MNP service binding Protocol
119   //
120   return gBS->OpenProtocol (
121                 ControllerHandle,
122                 &gEfiManagedNetworkServiceBindingProtocolGuid,
123                 NULL,
124                 This->DriverBindingHandle,
125                 ControllerHandle,
126                 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
127                 );
128 }
129 
130 /**
131   Clean up an IP6 service binding instance. It releases all
132   the resource allocated by the instance. The instance may be
133   partly initialized, or partly destroyed. If a resource is
134   destroyed, it is marked as that in case the destroy failed and
135   being called again later.
136 
137   @param[in]  IpSb               The IP6 service binding instance to clean up.
138 
139   @retval EFI_SUCCESS            The resource used by the instance are cleaned up.
140   @retval Others                 Failed to clean up some of the resources.
141 
142 **/
143 EFI_STATUS
Ip6CleanService(IN IP6_SERVICE * IpSb)144 Ip6CleanService (
145   IN IP6_SERVICE            *IpSb
146   )
147 {
148   EFI_STATUS                Status;
149   EFI_IPv6_ADDRESS          AllNodes;
150   IP6_NEIGHBOR_ENTRY        *NeighborCache;
151 
152   Ip6ConfigCleanInstance (&IpSb->Ip6ConfigInstance);
153 
154   if (!IpSb->LinkLocalDadFail) {
155     //
156     // Leave link-scope all-nodes multicast address (FF02::1)
157     //
158     Ip6SetToAllNodeMulticast (FALSE, IP6_LINK_LOCAL_SCOPE, &AllNodes);
159 
160     Status = Ip6LeaveGroup (IpSb, &AllNodes);
161     if (EFI_ERROR (Status)) {
162       return Status;
163     }
164   }
165 
166   if (IpSb->DefaultInterface != NULL) {
167     Ip6CleanInterface (IpSb->DefaultInterface, NULL);
168     IpSb->DefaultInterface = NULL;
169   }
170 
171   Ip6CleanDefaultRouterList (IpSb);
172 
173   Ip6CleanPrefixListTable (IpSb, &IpSb->OnlinkPrefix);
174   Ip6CleanPrefixListTable (IpSb, &IpSb->AutonomousPrefix);
175 
176   if (IpSb->RouteTable != NULL) {
177     Ip6CleanRouteTable (IpSb->RouteTable);
178     IpSb->RouteTable = NULL;
179   }
180 
181   if (IpSb->InterfaceId != NULL) {
182     FreePool (IpSb->InterfaceId);
183   }
184 
185   IpSb->InterfaceId = NULL;
186 
187   Ip6CleanAssembleTable (&IpSb->Assemble);
188 
189   if (IpSb->MnpChildHandle != NULL) {
190     if (IpSb->Mnp != NULL) {
191       IpSb->Mnp->Cancel (IpSb->Mnp, NULL);
192       IpSb->Mnp->Configure (IpSb->Mnp, NULL);
193       gBS->CloseProtocol (
194             IpSb->MnpChildHandle,
195             &gEfiManagedNetworkProtocolGuid,
196             IpSb->Image,
197             IpSb->Controller
198             );
199 
200       IpSb->Mnp = NULL;
201     }
202 
203     NetLibDestroyServiceChild (
204       IpSb->Controller,
205       IpSb->Image,
206       &gEfiManagedNetworkServiceBindingProtocolGuid,
207       IpSb->MnpChildHandle
208       );
209 
210     IpSb->MnpChildHandle = NULL;
211   }
212 
213   if (IpSb->RecvRequest.MnpToken.Event != NULL) {
214     gBS->CloseEvent (IpSb->RecvRequest.MnpToken.Event);
215   }
216 
217   if (IpSb->Timer != NULL) {
218     gBS->SetTimer (IpSb->Timer, TimerCancel, 0);
219     gBS->CloseEvent (IpSb->Timer);
220 
221     IpSb->Timer = NULL;
222   }
223 
224   if (IpSb->FasterTimer != NULL) {
225     gBS->SetTimer (IpSb->FasterTimer, TimerCancel, 0);
226     gBS->CloseEvent (IpSb->FasterTimer);
227 
228     IpSb->FasterTimer = NULL;
229   }
230   //
231   // Free the Neighbor Discovery resources
232   //
233   while (!IsListEmpty (&IpSb->NeighborTable)) {
234     NeighborCache = NET_LIST_HEAD (&IpSb->NeighborTable, IP6_NEIGHBOR_ENTRY, Link);
235     Ip6FreeNeighborEntry (IpSb, NeighborCache, FALSE, TRUE, EFI_SUCCESS, NULL, NULL);
236   }
237 
238   return EFI_SUCCESS;
239 }
240 
241 /**
242   Create a new IP6 driver service binding protocol.
243 
244   @param[in]  Controller         The controller that has MNP service binding
245                                  installed.
246   @param[in]  ImageHandle        The IP6 driver's image handle.
247   @param[out]  Service           The variable to receive the newly created IP6
248                                  service.
249 
250   @retval EFI_OUT_OF_RESOURCES   Failed to allocate some resources.
251   @retval EFI_SUCCESS            A new IP6 service binding private is created.
252 
253 **/
254 EFI_STATUS
Ip6CreateService(IN EFI_HANDLE Controller,IN EFI_HANDLE ImageHandle,OUT IP6_SERVICE ** Service)255 Ip6CreateService (
256   IN  EFI_HANDLE            Controller,
257   IN  EFI_HANDLE            ImageHandle,
258   OUT IP6_SERVICE           **Service
259   )
260 {
261   IP6_SERVICE                           *IpSb;
262   EFI_STATUS                            Status;
263   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *MnpToken;
264   EFI_MANAGED_NETWORK_CONFIG_DATA       *Config;
265   IP6_CONFIG_DATA_ITEM                  *DataItem;
266 
267   ASSERT (Service != NULL);
268 
269   *Service = NULL;
270 
271   //
272   // allocate a service private data then initialize all the filed to
273   // empty resources, so if any thing goes wrong when allocating
274   // resources, Ip6CleanService can be called to clean it up.
275   //
276   IpSb = AllocateZeroPool (sizeof (IP6_SERVICE));
277 
278   if (IpSb == NULL) {
279     return EFI_OUT_OF_RESOURCES;
280   }
281 
282   IpSb->Signature                   = IP6_SERVICE_SIGNATURE;
283   IpSb->ServiceBinding.CreateChild  = Ip6ServiceBindingCreateChild;
284   IpSb->ServiceBinding.DestroyChild = Ip6ServiceBindingDestroyChild;
285   IpSb->State                       = IP6_SERVICE_UNSTARTED;
286 
287   IpSb->NumChildren                 = 0;
288   InitializeListHead (&IpSb->Children);
289 
290   InitializeListHead (&IpSb->Interfaces);
291   IpSb->DefaultInterface            = NULL;
292   IpSb->RouteTable                  = NULL;
293 
294   IpSb->RecvRequest.Signature       = IP6_LINK_RX_SIGNATURE;
295   IpSb->RecvRequest.CallBack        = NULL;
296   IpSb->RecvRequest.Context         = NULL;
297   MnpToken                          = &IpSb->RecvRequest.MnpToken;
298   MnpToken->Event                   = NULL;
299   MnpToken->Status                  = EFI_NOT_READY;
300   MnpToken->Packet.RxData           = NULL;
301 
302   Ip6CreateAssembleTable (&IpSb->Assemble);
303 
304   IpSb->MldCtrl.Mldv1QuerySeen      = 0;
305   InitializeListHead (&IpSb->MldCtrl.Groups);
306 
307   ZeroMem (&IpSb->LinkLocalAddr, sizeof (EFI_IPv6_ADDRESS));
308   IpSb->LinkLocalOk                 = FALSE;
309   IpSb->LinkLocalDadFail            = FALSE;
310   IpSb->Dhcp6NeedStart              = FALSE;
311   IpSb->Dhcp6NeedInfoRequest        = FALSE;
312 
313   IpSb->CurHopLimit                 = IP6_HOP_LIMIT;
314   IpSb->LinkMTU                     = IP6_MIN_LINK_MTU;
315   IpSb->BaseReachableTime           = IP6_REACHABLE_TIME;
316   Ip6UpdateReachableTime (IpSb);
317   //
318   // RFC4861 RETRANS_TIMER: 1,000 milliseconds
319   //
320   IpSb->RetransTimer                = IP6_RETRANS_TIMER;
321 
322   IpSb->RoundRobin                  = 0;
323 
324   InitializeListHead (&IpSb->NeighborTable);
325   InitializeListHead (&IpSb->DefaultRouterList);
326   InitializeListHead (&IpSb->OnlinkPrefix);
327   InitializeListHead (&IpSb->AutonomousPrefix);
328 
329   IpSb->InterfaceIdLen              = IP6_IF_ID_LEN;
330   IpSb->InterfaceId                 = NULL;
331 
332   IpSb->RouterAdvertiseReceived     = FALSE;
333   IpSb->SolicitTimer                = IP6_MAX_RTR_SOLICITATIONS;
334   IpSb->Ticks                       = 0;
335 
336   IpSb->Image                       = ImageHandle;
337   IpSb->Controller                  = Controller;
338 
339   IpSb->MnpChildHandle              = NULL;
340   IpSb->Mnp                         = NULL;
341 
342   Config                            = &IpSb->MnpConfigData;
343   Config->ReceivedQueueTimeoutValue = 0;
344   Config->TransmitQueueTimeoutValue = 0;
345   Config->ProtocolTypeFilter        = IP6_ETHER_PROTO;
346   Config->EnableUnicastReceive      = TRUE;
347   Config->EnableMulticastReceive    = TRUE;
348   Config->EnableBroadcastReceive    = TRUE;
349   Config->EnablePromiscuousReceive  = FALSE;
350   Config->FlushQueuesOnReset        = TRUE;
351   Config->EnableReceiveTimestamps   = FALSE;
352   Config->DisableBackgroundPolling  = FALSE;
353 
354   ZeroMem (&IpSb->SnpMode, sizeof (EFI_SIMPLE_NETWORK_MODE));
355 
356   IpSb->Timer                       = NULL;
357   IpSb->FasterTimer                 = NULL;
358 
359   ZeroMem (&IpSb->Ip6ConfigInstance, sizeof (IP6_CONFIG_INSTANCE));
360 
361   IpSb->MacString                   = NULL;
362 
363   //
364   // Create various resources. First create the route table, timer
365   // event, MNP token event and MNP child.
366   //
367 
368   IpSb->RouteTable = Ip6CreateRouteTable ();
369   if (IpSb->RouteTable == NULL) {
370     Status = EFI_OUT_OF_RESOURCES;
371     goto ON_ERROR;
372   }
373 
374   Status = gBS->CreateEvent (
375                   EVT_NOTIFY_SIGNAL | EVT_TIMER,
376                   TPL_CALLBACK,
377                   Ip6TimerTicking,
378                   IpSb,
379                   &IpSb->Timer
380                   );
381   if (EFI_ERROR (Status)) {
382     goto ON_ERROR;
383   }
384 
385   Status = gBS->CreateEvent (
386                   EVT_NOTIFY_SIGNAL | EVT_TIMER,
387                   TPL_CALLBACK,
388                   Ip6NdFasterTimerTicking,
389                   IpSb,
390                   &IpSb->FasterTimer
391                   );
392   if (EFI_ERROR (Status)) {
393     goto ON_ERROR;
394   }
395 
396   Status = NetLibCreateServiceChild (
397              Controller,
398              ImageHandle,
399              &gEfiManagedNetworkServiceBindingProtocolGuid,
400              &IpSb->MnpChildHandle
401              );
402   if (EFI_ERROR (Status)) {
403     goto ON_ERROR;
404   }
405 
406   Status = gBS->OpenProtocol (
407                   IpSb->MnpChildHandle,
408                   &gEfiManagedNetworkProtocolGuid,
409                   (VOID **) (&IpSb->Mnp),
410                   ImageHandle,
411                   Controller,
412                   EFI_OPEN_PROTOCOL_BY_DRIVER
413                   );
414   if (EFI_ERROR (Status)) {
415     goto ON_ERROR;
416   }
417 
418   Status = Ip6ServiceConfigMnp (IpSb, TRUE);
419   if (EFI_ERROR (Status)) {
420     goto ON_ERROR;
421   }
422 
423   Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &IpSb->SnpMode);
424   if (EFI_ERROR (Status)) {
425     goto ON_ERROR;
426   }
427 
428   IpSb->MaxPacketSize = IP6_MIN_LINK_MTU - sizeof (EFI_IP6_HEADER);
429   if (NetLibGetVlanId (IpSb->Controller) != 0) {
430     //
431     // This is a VLAN device, reduce MTU by VLAN tag length
432     //
433     IpSb->MaxPacketSize -= NET_VLAN_TAG_LEN;
434   }
435   IpSb->OldMaxPacketSize = IpSb->MaxPacketSize;
436 
437   //
438   // Currently only ETHERNET is supported in IPv6 stack, since
439   // link local address requires an IEEE 802 48-bit MACs for
440   // EUI-64 format interface identifier mapping.
441   //
442   if (IpSb->SnpMode.IfType != NET_IFTYPE_ETHERNET) {
443     Status = EFI_UNSUPPORTED;
444     goto ON_ERROR;
445   }
446 
447   Status = Ip6InitMld (IpSb);
448   if (EFI_ERROR (Status)) {
449     goto ON_ERROR;
450   }
451 
452   Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &IpSb->MacString);
453   if (EFI_ERROR (Status)) {
454     goto ON_ERROR;
455   }
456 
457   Status = Ip6ConfigInitInstance (&IpSb->Ip6ConfigInstance);
458   if (EFI_ERROR (Status)) {
459     goto ON_ERROR;
460   }
461 
462   IpSb->DefaultInterface = Ip6CreateInterface (IpSb, TRUE);
463   if (IpSb->DefaultInterface == NULL) {
464     Status = EFI_DEVICE_ERROR;
465     goto ON_ERROR;
466   }
467 
468   Status = gBS->CreateEvent (
469                   EVT_NOTIFY_SIGNAL,
470                   TPL_NOTIFY,
471                   Ip6OnFrameReceived,
472                   &IpSb->RecvRequest,
473                   &MnpToken->Event
474                   );
475   if (EFI_ERROR (Status)) {
476     goto ON_ERROR;
477   }
478 
479   //
480   // If there is any manual address, set it.
481   //
482   DataItem = &IpSb->Ip6ConfigInstance.DataItem[Ip6ConfigDataTypeManualAddress];
483   if (DataItem->Data.Ptr != NULL) {
484     DataItem->SetData (
485                 &IpSb->Ip6ConfigInstance,
486                 DataItem->DataSize,
487                 DataItem->Data.Ptr
488                 );
489   }
490 
491   //
492   // If there is any gateway address, set it.
493   //
494   DataItem = &IpSb->Ip6ConfigInstance.DataItem[Ip6ConfigDataTypeGateway];
495   if (DataItem->Data.Ptr != NULL) {
496     DataItem->SetData (
497                 &IpSb->Ip6ConfigInstance,
498                 DataItem->DataSize,
499                 DataItem->Data.Ptr
500                 );
501   }
502 
503   InsertHeadList (&IpSb->Interfaces, &IpSb->DefaultInterface->Link);
504 
505   *Service = IpSb;
506   return EFI_SUCCESS;
507 
508 ON_ERROR:
509   Ip6CleanService (IpSb);
510   FreePool (IpSb);
511   return Status;
512 }
513 
514 
515 /**
516   Start this driver on ControllerHandle.
517 
518   @param[in]  This                Protocol instance pointer.
519   @param[in]  ControllerHandle    Handle of device to bind driver to.
520   @param[in]  RemainingDevicePath Optional parameter used to pick a specific child
521                                   device to start.
522 
523   @retval EFI_SUCCES              This driver is added to ControllerHandle.
524   @retval EFI_ALREADY_STARTED     This driver is already running on ControllerHandle.
525   @retval other                   This driver does not support this device.
526 
527 **/
528 EFI_STATUS
529 EFIAPI
Ip6DriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)530 Ip6DriverBindingStart (
531   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
532   IN EFI_HANDLE                   ControllerHandle,
533   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
534   )
535 {
536   IP6_SERVICE               *IpSb;
537   EFI_STATUS                Status;
538 
539   //
540   // Test for the Ip6 service binding protocol
541   //
542   Status = gBS->OpenProtocol (
543                   ControllerHandle,
544                   &gEfiIp6ServiceBindingProtocolGuid,
545                   NULL,
546                   This->DriverBindingHandle,
547                   ControllerHandle,
548                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
549                   );
550 
551   if (Status == EFI_SUCCESS) {
552     return EFI_ALREADY_STARTED;
553   }
554 
555   Status = Ip6CreateService (ControllerHandle, This->DriverBindingHandle, &IpSb);
556 
557   if (EFI_ERROR (Status)) {
558     return Status;
559   }
560 
561   ASSERT (IpSb != NULL);
562 
563   //
564   // Install the Ip6ServiceBinding Protocol onto ControlerHandle
565   //
566   Status = gBS->InstallMultipleProtocolInterfaces (
567                   &ControllerHandle,
568                   &gEfiIp6ServiceBindingProtocolGuid,
569                   &IpSb->ServiceBinding,
570                   &gEfiIp6ConfigProtocolGuid,
571                   &IpSb->Ip6ConfigInstance.Ip6Config,
572                   NULL
573                   );
574 
575   if (!EFI_ERROR (Status)) {
576     //
577     // ready to go: start the receiving and timer
578     //
579     Status = Ip6ReceiveFrame (Ip6AcceptFrame, IpSb);
580     if (EFI_ERROR (Status)) {
581       goto ON_ERROR;
582     }
583 
584     //
585     // The timer expires every 100 (IP6_TIMER_INTERVAL_IN_MS) milliseconds.
586     //
587     Status = gBS->SetTimer (
588                     IpSb->FasterTimer,
589                     TimerPeriodic,
590                     TICKS_PER_MS * IP6_TIMER_INTERVAL_IN_MS
591                     );
592     if (EFI_ERROR (Status)) {
593       goto ON_ERROR;
594     }
595 
596     //
597     // The timer expires every 1000 (IP6_ONE_SECOND_IN_MS) milliseconds.
598     //
599     Status = gBS->SetTimer (
600                     IpSb->Timer,
601                     TimerPeriodic,
602                     TICKS_PER_MS * IP6_ONE_SECOND_IN_MS
603                     );
604     if (EFI_ERROR (Status)) {
605       goto ON_ERROR;
606     }
607 
608     //
609     // Initialize the IP6 ID
610     //
611     mIp6Id = NET_RANDOM (NetRandomInitSeed ());
612 
613     return EFI_SUCCESS;
614   }
615 
616 ON_ERROR:
617   Ip6CleanService (IpSb);
618   FreePool (IpSb);
619   return Status;
620 }
621 
622 /**
623   Callback function which provided by user to remove one node in NetDestroyLinkList process.
624 
625   @param[in]    Entry           The entry to be removed.
626   @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
627 
628   @retval EFI_SUCCESS           The entry has been removed successfully.
629   @retval Others                Fail to remove the entry.
630 
631 **/
632 EFI_STATUS
633 EFIAPI
Ip6DestroyChildEntryInHandleBuffer(IN LIST_ENTRY * Entry,IN VOID * Context)634 Ip6DestroyChildEntryInHandleBuffer (
635   IN LIST_ENTRY         *Entry,
636   IN VOID               *Context
637   )
638 {
639   IP6_PROTOCOL                  *IpInstance;
640   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
641   UINTN                         NumberOfChildren;
642   EFI_HANDLE                    *ChildHandleBuffer;
643 
644   if (Entry == NULL || Context == NULL) {
645     return EFI_INVALID_PARAMETER;
646   }
647 
648   IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP6_PROTOCOL, Link, IP6_PROTOCOL_SIGNATURE);
649   ServiceBinding    = ((IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
650   NumberOfChildren  = ((IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
651   ChildHandleBuffer = ((IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
652 
653   if (!NetIsInHandleBuffer (IpInstance->Handle, NumberOfChildren, ChildHandleBuffer)) {
654     return EFI_SUCCESS;
655   }
656 
657   return ServiceBinding->DestroyChild (ServiceBinding, IpInstance->Handle);
658 }
659 
660 /**
661   Stop this driver on ControllerHandle.
662 
663   @param[in]  This               Protocol instance pointer.
664   @param[in]  ControllerHandle   Handle of device to stop driver on.
665   @param[in]  NumberOfChildren   Number of Handles in ChildHandleBuffer. If number
666                                  of children is zero, stop the entire  bus driver.
667   @param[in]  ChildHandleBuffer  An array of child handles to be freed. May be NULL
668                                  if NumberOfChildren is 0.
669 
670   @retval EFI_SUCCESS           The device was stopped.
671   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
672 
673 **/
674 EFI_STATUS
675 EFIAPI
Ip6DriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)676 Ip6DriverBindingStop (
677   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
678   IN  EFI_HANDLE                   ControllerHandle,
679   IN  UINTN                        NumberOfChildren,
680   IN  EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
681   )
682 {
683   EFI_SERVICE_BINDING_PROTOCOL            *ServiceBinding;
684   IP6_SERVICE                             *IpSb;
685   EFI_HANDLE                              NicHandle;
686   EFI_STATUS                              Status;
687   LIST_ENTRY                              *List;
688   INTN                                    State;
689   BOOLEAN                                 IsDhcp6;
690   IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
691 
692   IsDhcp6   = FALSE;
693   NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
694   if (NicHandle == NULL) {
695     NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp6ProtocolGuid);
696     if (NicHandle != NULL) {
697       IsDhcp6 = TRUE;
698     } else {
699       return EFI_SUCCESS;
700     }
701   }
702 
703   Status = gBS->OpenProtocol (
704                   NicHandle,
705                   &gEfiIp6ServiceBindingProtocolGuid,
706                   (VOID **) &ServiceBinding,
707                   This->DriverBindingHandle,
708                   NicHandle,
709                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
710                   );
711   if (EFI_ERROR (Status)) {
712     return EFI_DEVICE_ERROR;
713   }
714 
715   IpSb = IP6_SERVICE_FROM_PROTOCOL (ServiceBinding);
716 
717   if (IsDhcp6) {
718     Status = Ip6ConfigDestroyDhcp6 (&IpSb->Ip6ConfigInstance);
719     gBS->CloseEvent (IpSb->Ip6ConfigInstance.Dhcp6Event);
720     IpSb->Ip6ConfigInstance.Dhcp6Event = NULL;
721   } else if (NumberOfChildren != 0) {
722     //
723     // NumberOfChildren is not zero, destroy the IP6 children instances in ChildHandleBuffer.
724     //
725     List = &IpSb->Children;
726     Context.ServiceBinding    = ServiceBinding;
727     Context.NumberOfChildren  = NumberOfChildren;
728     Context.ChildHandleBuffer = ChildHandleBuffer;
729     Status = NetDestroyLinkList (
730                List,
731                Ip6DestroyChildEntryInHandleBuffer,
732                &Context,
733                NULL
734                );
735   } else if (IsListEmpty (&IpSb->Children)) {
736     State           = IpSb->State;
737     IpSb->State     = IP6_SERVICE_DESTROY;
738 
739     Status = Ip6CleanService (IpSb);
740     if (EFI_ERROR (Status)) {
741       IpSb->State = State;
742       goto Exit;
743     }
744 
745     Status = gBS->UninstallMultipleProtocolInterfaces (
746                     NicHandle,
747                     &gEfiIp6ServiceBindingProtocolGuid,
748                     ServiceBinding,
749                     &gEfiIp6ConfigProtocolGuid,
750                     &IpSb->Ip6ConfigInstance.Ip6Config,
751                     NULL
752                     );
753     ASSERT_EFI_ERROR (Status);
754     FreePool (IpSb);
755     Status = EFI_SUCCESS;
756   }
757 
758 Exit:
759   return Status;
760 }
761 
762 
763 /**
764   Creates a child handle with a set of I/O services.
765 
766   @param[in]  This               Protocol instance pointer.
767   @param[in]  ChildHandle        Pointer to the handle of the child to create.   If
768                                  it is NULL, then a new handle is created.   If it
769                                  is not NULL, then the I/O services are added to
770                                  the existing child handle.
771 
772   @retval EFI_SUCCES             The child handle was created with the I/O services.
773   @retval EFI_OUT_OF_RESOURCES   There are not enough resources availabe to create
774                                  the child.
775   @retval other                  The child handle was not created.
776 
777 **/
778 EFI_STATUS
779 EFIAPI
Ip6ServiceBindingCreateChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN EFI_HANDLE * ChildHandle)780 Ip6ServiceBindingCreateChild (
781   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
782   IN EFI_HANDLE                    *ChildHandle
783   )
784 {
785   IP6_SERVICE               *IpSb;
786   IP6_PROTOCOL              *IpInstance;
787   EFI_TPL                   OldTpl;
788   EFI_STATUS                Status;
789   VOID                      *Mnp;
790 
791   if ((This == NULL) || (ChildHandle == NULL)) {
792     return EFI_INVALID_PARAMETER;
793   }
794 
795   IpSb       = IP6_SERVICE_FROM_PROTOCOL (This);
796 
797   if (IpSb->LinkLocalDadFail) {
798     return EFI_DEVICE_ERROR;
799   }
800 
801   IpInstance = AllocatePool (sizeof (IP6_PROTOCOL));
802 
803   if (IpInstance == NULL) {
804     return EFI_OUT_OF_RESOURCES;
805   }
806 
807   Ip6InitProtocol (IpSb, IpInstance);
808 
809   //
810   // Install Ip6 onto ChildHandle
811   //
812   Status = gBS->InstallMultipleProtocolInterfaces (
813                   ChildHandle,
814                   &gEfiIp6ProtocolGuid,
815                   &IpInstance->Ip6Proto,
816                   NULL
817                   );
818   if (EFI_ERROR (Status)) {
819     goto ON_ERROR;
820   }
821 
822   IpInstance->Handle = *ChildHandle;
823 
824   //
825   // Open the Managed Network protocol BY_CHILD.
826   //
827   Status = gBS->OpenProtocol (
828                   IpSb->MnpChildHandle,
829                   &gEfiManagedNetworkProtocolGuid,
830                   (VOID **) &Mnp,
831                   gIp6DriverBinding.DriverBindingHandle,
832                   IpInstance->Handle,
833                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
834                   );
835   if (EFI_ERROR (Status)) {
836     gBS->UninstallMultipleProtocolInterfaces (
837            ChildHandle,
838            &gEfiIp6ProtocolGuid,
839            &IpInstance->Ip6Proto,
840            NULL
841            );
842 
843     goto ON_ERROR;
844   }
845 
846   //
847   // Insert it into the service binding instance.
848   //
849   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
850 
851   InsertTailList (&IpSb->Children, &IpInstance->Link);
852   IpSb->NumChildren++;
853 
854   gBS->RestoreTPL (OldTpl);
855 
856 ON_ERROR:
857 
858   if (EFI_ERROR (Status)) {
859 
860     Ip6CleanProtocol (IpInstance);
861 
862     FreePool (IpInstance);
863   }
864 
865   return Status;
866 }
867 
868 /**
869   Destroys a child handle with a set of I/O services.
870 
871   @param[in]  This               Protocol instance pointer.
872   @param[in]  ChildHandle        Handle of the child to destroy.
873 
874   @retval EFI_SUCCES             The I/O services were removed from the child
875                                  handle.
876   @retval EFI_UNSUPPORTED        The child handle does not support the I/O services
877                                   that are being removed.
878   @retval EFI_INVALID_PARAMETER  Child handle is NULL.
879   @retval EFI_ACCESS_DENIED      The child handle could not be destroyed because
880                                  its I/O services are being used.
881   @retval other                  The child handle was not destroyed.
882 
883 **/
884 EFI_STATUS
885 EFIAPI
Ip6ServiceBindingDestroyChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN EFI_HANDLE ChildHandle)886 Ip6ServiceBindingDestroyChild (
887   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
888   IN EFI_HANDLE                    ChildHandle
889   )
890 {
891   EFI_STATUS                Status;
892   IP6_SERVICE               *IpSb;
893   IP6_PROTOCOL              *IpInstance;
894   EFI_IP6_PROTOCOL          *Ip6;
895   EFI_TPL                   OldTpl;
896 
897   if ((This == NULL) || (ChildHandle == NULL)) {
898     return EFI_INVALID_PARAMETER;
899   }
900 
901   //
902   // Retrieve the private context data structures
903   //
904   IpSb   = IP6_SERVICE_FROM_PROTOCOL (This);
905 
906   Status = gBS->OpenProtocol (
907                   ChildHandle,
908                   &gEfiIp6ProtocolGuid,
909                   (VOID **) &Ip6,
910                   gIp6DriverBinding.DriverBindingHandle,
911                   ChildHandle,
912                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
913                   );
914 
915   if (EFI_ERROR (Status)) {
916     return EFI_UNSUPPORTED;
917   }
918 
919   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (Ip6);
920 
921   if (IpInstance->Service != IpSb) {
922     return EFI_INVALID_PARAMETER;
923   }
924 
925   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
926 
927   //
928   // A child can be destroyed more than once. For example,
929   // Ip6DriverBindingStop will destroy all of its children.
930   // when UDP driver is being stopped, it will destroy all
931   // the IP child it opens.
932   //
933   if (IpInstance->InDestroy) {
934     gBS->RestoreTPL (OldTpl);
935     return EFI_SUCCESS;
936   }
937 
938   IpInstance->InDestroy = TRUE;
939 
940   //
941   // Close the Managed Network protocol.
942   //
943   gBS->CloseProtocol (
944          IpSb->MnpChildHandle,
945          &gEfiManagedNetworkProtocolGuid,
946          gIp6DriverBinding.DriverBindingHandle,
947          ChildHandle
948          );
949 
950   //
951   // Uninstall the IP6 protocol first. Many thing happens during
952   // this:
953   // 1. The consumer of the IP6 protocol will be stopped if it
954   // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
955   // stopped, IP driver's stop function will be called, and uninstall
956   // EFI_IP6_PROTOCOL will trigger the UDP's stop function. This
957   // makes it possible to create the network stack bottom up, and
958   // stop it top down.
959   // 2. the upper layer will recycle the received packet. The recycle
960   // event's TPL is higher than this function. The recycle events
961   // will be called back before preceeding. If any packets not recycled,
962   // that means there is a resource leak.
963   //
964   gBS->RestoreTPL (OldTpl);
965   Status = gBS->UninstallProtocolInterface (
966                   ChildHandle,
967                   &gEfiIp6ProtocolGuid,
968                   &IpInstance->Ip6Proto
969                   );
970   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
971   if (EFI_ERROR (Status)) {
972     goto ON_ERROR;
973   }
974 
975   Status = Ip6CleanProtocol (IpInstance);
976   if (EFI_ERROR (Status)) {
977     gBS->InstallMultipleProtocolInterfaces (
978            &ChildHandle,
979            &gEfiIp6ProtocolGuid,
980            Ip6,
981            NULL
982            );
983 
984     goto ON_ERROR;
985   }
986 
987   RemoveEntryList (&IpInstance->Link);
988   ASSERT (IpSb->NumChildren > 0);
989   IpSb->NumChildren--;
990 
991   gBS->RestoreTPL (OldTpl);
992 
993   FreePool (IpInstance);
994   return EFI_SUCCESS;
995 
996 ON_ERROR:
997   gBS->RestoreTPL (OldTpl);
998 
999   return Status;
1000 }
1001