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