1 /** @file
2   The driver binding and service binding protocol for IP6 driver.
3 
4   Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
5   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
6 
7   SPDX-License-Identifier: BSD-2-Clause-Patent
8 
9 **/
10 
11 #include "Ip6Impl.h"
12 
13 EFI_DRIVER_BINDING_PROTOCOL gIp6DriverBinding = {
14   Ip6DriverBindingSupported,
15   Ip6DriverBindingStart,
16   Ip6DriverBindingStop,
17   0xa,
18   NULL,
19   NULL
20 };
21 
22 BOOLEAN  mIpSec2Installed = FALSE;
23 
24 /**
25    Callback function for IpSec2 Protocol install.
26 
27    @param[in] Event           Event whose notification function is being invoked
28    @param[in] Context         Pointer to the notification function's context
29 
30 **/
31 VOID
32 EFIAPI
IpSec2InstalledCallback(IN EFI_EVENT Event,IN VOID * Context)33 IpSec2InstalledCallback (
34   IN EFI_EVENT  Event,
35   IN VOID       *Context
36   )
37 {
38   EFI_STATUS    Status;
39   //
40   // Test if protocol was even found.
41   // Notification function will be called at least once.
42   //
43   Status = gBS->LocateProtocol (&gEfiIpSec2ProtocolGuid, NULL, (VOID **)&mIpSec);
44   if (Status == EFI_SUCCESS && mIpSec != NULL) {
45     //
46     // Close the event so it does not get called again.
47     //
48     gBS->CloseEvent (Event);
49 
50     mIpSec2Installed = TRUE;
51   }
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 FREE_SERVICE;
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 UNINSTALL_PROTOCOL;
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 (Status == EFI_INVALID_PARAMETER || Status == EFI_BAD_BUFFER_SIZE) {
585       //
586       // Clean the invalid ManualAddress configuration.
587       //
588       Status = Ip6Cfg->SetData (
589                          Ip6Cfg,
590                          Ip6ConfigDataTypeManualAddress,
591                          0,
592                          NULL
593                          );
594       DEBUG ((EFI_D_WARN, "Ip6DriverBindingStart: Clean the invalid ManualAddress configuration.\n"));
595     }
596   }
597 
598   //
599   // If there is any default gateway address, set it.
600   //
601   DataItem = &IpSb->Ip6ConfigInstance.DataItem[Ip6ConfigDataTypeGateway];
602   if (DataItem->Data.Ptr != NULL) {
603     Status = Ip6Cfg->SetData (
604                        Ip6Cfg,
605                        Ip6ConfigDataTypeGateway,
606                        DataItem->DataSize,
607                        DataItem->Data.Ptr
608                        );
609     if (Status == EFI_INVALID_PARAMETER || Status == EFI_BAD_BUFFER_SIZE) {
610       //
611       // Clean the invalid Gateway configuration.
612       //
613       Status = Ip6Cfg->SetData (
614                          Ip6Cfg,
615                          Ip6ConfigDataTypeGateway,
616                          0,
617                          NULL
618                          );
619       DEBUG ((EFI_D_WARN, "Ip6DriverBindingStart: Clean the invalid Gateway configuration.\n"));
620     }
621   }
622 
623   //
624   // ready to go: start the receiving and timer
625   //
626   Status = Ip6ReceiveFrame (Ip6AcceptFrame, IpSb);
627   if (EFI_ERROR (Status)) {
628     goto UNINSTALL_PROTOCOL;
629   }
630 
631   //
632   // The timer expires every 100 (IP6_TIMER_INTERVAL_IN_MS) milliseconds.
633   //
634   Status = gBS->SetTimer (
635                   IpSb->FasterTimer,
636                   TimerPeriodic,
637                   TICKS_PER_MS * IP6_TIMER_INTERVAL_IN_MS
638                   );
639   if (EFI_ERROR (Status)) {
640     goto UNINSTALL_PROTOCOL;
641   }
642 
643   //
644   // The timer expires every 1000 (IP6_ONE_SECOND_IN_MS) milliseconds.
645   //
646   Status = gBS->SetTimer (
647                   IpSb->Timer,
648                   TimerPeriodic,
649                   TICKS_PER_MS * IP6_ONE_SECOND_IN_MS
650                   );
651   if (EFI_ERROR (Status)) {
652     goto UNINSTALL_PROTOCOL;
653   }
654 
655   //
656   // Initialize the IP6 ID
657   //
658   mIp6Id = NET_RANDOM (NetRandomInitSeed ());
659 
660   return EFI_SUCCESS;
661 
662 UNINSTALL_PROTOCOL:
663   gBS->UninstallMultipleProtocolInterfaces (
664          ControllerHandle,
665          &gEfiIp6ServiceBindingProtocolGuid,
666          &IpSb->ServiceBinding,
667          &gEfiIp6ConfigProtocolGuid,
668          Ip6Cfg,
669          NULL
670          );
671 
672 FREE_SERVICE:
673   Ip6CleanService (IpSb);
674   FreePool (IpSb);
675   return Status;
676 }
677 
678 /**
679   Callback function which provided by user to remove one node in NetDestroyLinkList process.
680 
681   @param[in]    Entry           The entry to be removed.
682   @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
683 
684   @retval EFI_SUCCESS           The entry has been removed successfully.
685   @retval Others                Fail to remove the entry.
686 
687 **/
688 EFI_STATUS
689 EFIAPI
Ip6DestroyChildEntryInHandleBuffer(IN LIST_ENTRY * Entry,IN VOID * Context)690 Ip6DestroyChildEntryInHandleBuffer (
691   IN LIST_ENTRY         *Entry,
692   IN VOID               *Context
693   )
694 {
695   IP6_PROTOCOL                  *IpInstance;
696   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
697   UINTN                         NumberOfChildren;
698   EFI_HANDLE                    *ChildHandleBuffer;
699 
700   if (Entry == NULL || Context == NULL) {
701     return EFI_INVALID_PARAMETER;
702   }
703 
704   IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP6_PROTOCOL, Link, IP6_PROTOCOL_SIGNATURE);
705   ServiceBinding    = ((IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
706   NumberOfChildren  = ((IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
707   ChildHandleBuffer = ((IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
708 
709   if (!NetIsInHandleBuffer (IpInstance->Handle, NumberOfChildren, ChildHandleBuffer)) {
710     return EFI_SUCCESS;
711   }
712 
713   return ServiceBinding->DestroyChild (ServiceBinding, IpInstance->Handle);
714 }
715 
716 /**
717   Stop this driver on ControllerHandle.
718 
719   @param[in]  This               Protocol instance pointer.
720   @param[in]  ControllerHandle   Handle of device to stop driver on.
721   @param[in]  NumberOfChildren   Number of Handles in ChildHandleBuffer. If number
722                                  of children is zero, stop the entire  bus driver.
723   @param[in]  ChildHandleBuffer  An array of child handles to be freed. May be NULL
724                                  if NumberOfChildren is 0.
725 
726   @retval EFI_SUCCESS           The device was stopped.
727   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
728 
729 **/
730 EFI_STATUS
731 EFIAPI
Ip6DriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)732 Ip6DriverBindingStop (
733   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
734   IN  EFI_HANDLE                   ControllerHandle,
735   IN  UINTN                        NumberOfChildren,
736   IN  EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
737   )
738 {
739   EFI_SERVICE_BINDING_PROTOCOL            *ServiceBinding;
740   IP6_SERVICE                             *IpSb;
741   EFI_HANDLE                              NicHandle;
742   EFI_STATUS                              Status;
743   LIST_ENTRY                              *List;
744   INTN                                    State;
745   BOOLEAN                                 IsDhcp6;
746   IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
747 
748   IsDhcp6   = FALSE;
749   NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
750   if (NicHandle == NULL) {
751     NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp6ProtocolGuid);
752     if (NicHandle != NULL) {
753       IsDhcp6 = TRUE;
754     } else {
755       return EFI_SUCCESS;
756     }
757   }
758 
759   Status = gBS->OpenProtocol (
760                   NicHandle,
761                   &gEfiIp6ServiceBindingProtocolGuid,
762                   (VOID **) &ServiceBinding,
763                   This->DriverBindingHandle,
764                   NicHandle,
765                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
766                   );
767   if (EFI_ERROR (Status)) {
768     return EFI_DEVICE_ERROR;
769   }
770 
771   IpSb = IP6_SERVICE_FROM_PROTOCOL (ServiceBinding);
772 
773   if (IsDhcp6) {
774     Status = Ip6ConfigDestroyDhcp6 (&IpSb->Ip6ConfigInstance);
775     gBS->CloseEvent (IpSb->Ip6ConfigInstance.Dhcp6Event);
776     IpSb->Ip6ConfigInstance.Dhcp6Event = NULL;
777   } else if (NumberOfChildren != 0) {
778     //
779     // NumberOfChildren is not zero, destroy the IP6 children instances in ChildHandleBuffer.
780     //
781     List = &IpSb->Children;
782     Context.ServiceBinding    = ServiceBinding;
783     Context.NumberOfChildren  = NumberOfChildren;
784     Context.ChildHandleBuffer = ChildHandleBuffer;
785     Status = NetDestroyLinkList (
786                List,
787                Ip6DestroyChildEntryInHandleBuffer,
788                &Context,
789                NULL
790                );
791   } else if (IsListEmpty (&IpSb->Children)) {
792     State           = IpSb->State;
793     Status = Ip6CleanService (IpSb);
794     if (EFI_ERROR (Status)) {
795       IpSb->State = State;
796       goto Exit;
797     }
798 
799     Status = gBS->UninstallMultipleProtocolInterfaces (
800                     NicHandle,
801                     &gEfiIp6ServiceBindingProtocolGuid,
802                     ServiceBinding,
803                     &gEfiIp6ConfigProtocolGuid,
804                     &IpSb->Ip6ConfigInstance.Ip6Config,
805                     NULL
806                     );
807     ASSERT_EFI_ERROR (Status);
808     FreePool (IpSb);
809     Status = EFI_SUCCESS;
810   }
811 
812 Exit:
813   return Status;
814 }
815 
816 
817 /**
818   Creates a child handle with a set of I/O services.
819 
820   @param[in]  This               Protocol instance pointer.
821   @param[in]  ChildHandle        Pointer to the handle of the child to create.   If
822                                  it is NULL, then a new handle is created.   If it
823                                  is not NULL, then the I/O services are added to
824                                  the existing child handle.
825 
826   @retval EFI_SUCCES             The child handle was created with the I/O services.
827   @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to create
828                                  the child.
829   @retval other                  The child handle was not created.
830 
831 **/
832 EFI_STATUS
833 EFIAPI
Ip6ServiceBindingCreateChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN EFI_HANDLE * ChildHandle)834 Ip6ServiceBindingCreateChild (
835   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
836   IN EFI_HANDLE                    *ChildHandle
837   )
838 {
839   IP6_SERVICE               *IpSb;
840   IP6_PROTOCOL              *IpInstance;
841   EFI_TPL                   OldTpl;
842   EFI_STATUS                Status;
843   VOID                      *Mnp;
844 
845   if ((This == NULL) || (ChildHandle == NULL)) {
846     return EFI_INVALID_PARAMETER;
847   }
848 
849   IpSb       = IP6_SERVICE_FROM_PROTOCOL (This);
850 
851   if (IpSb->LinkLocalDadFail) {
852     return EFI_DEVICE_ERROR;
853   }
854 
855   IpInstance = AllocatePool (sizeof (IP6_PROTOCOL));
856 
857   if (IpInstance == NULL) {
858     return EFI_OUT_OF_RESOURCES;
859   }
860 
861   Ip6InitProtocol (IpSb, IpInstance);
862 
863   //
864   // Install Ip6 onto ChildHandle
865   //
866   Status = gBS->InstallMultipleProtocolInterfaces (
867                   ChildHandle,
868                   &gEfiIp6ProtocolGuid,
869                   &IpInstance->Ip6Proto,
870                   NULL
871                   );
872   if (EFI_ERROR (Status)) {
873     goto ON_ERROR;
874   }
875 
876   IpInstance->Handle = *ChildHandle;
877 
878   //
879   // Open the Managed Network protocol BY_CHILD.
880   //
881   Status = gBS->OpenProtocol (
882                   IpSb->MnpChildHandle,
883                   &gEfiManagedNetworkProtocolGuid,
884                   (VOID **) &Mnp,
885                   gIp6DriverBinding.DriverBindingHandle,
886                   IpInstance->Handle,
887                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
888                   );
889   if (EFI_ERROR (Status)) {
890     gBS->UninstallMultipleProtocolInterfaces (
891            *ChildHandle,
892            &gEfiIp6ProtocolGuid,
893            &IpInstance->Ip6Proto,
894            NULL
895            );
896 
897     goto ON_ERROR;
898   }
899 
900   //
901   // Insert it into the service binding instance.
902   //
903   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
904 
905   InsertTailList (&IpSb->Children, &IpInstance->Link);
906   IpSb->NumChildren++;
907 
908   gBS->RestoreTPL (OldTpl);
909 
910 ON_ERROR:
911 
912   if (EFI_ERROR (Status)) {
913 
914     Ip6CleanProtocol (IpInstance);
915 
916     FreePool (IpInstance);
917   }
918 
919   return Status;
920 }
921 
922 /**
923   Destroys a child handle with a set of I/O services.
924 
925   @param[in]  This               Protocol instance pointer.
926   @param[in]  ChildHandle        Handle of the child to destroy.
927 
928   @retval EFI_SUCCES             The I/O services were removed from the child
929                                  handle.
930   @retval EFI_UNSUPPORTED        The child handle does not support the I/O services
931                                   that are being removed.
932   @retval EFI_INVALID_PARAMETER  Child handle is NULL.
933   @retval EFI_ACCESS_DENIED      The child handle could not be destroyed because
934                                  its I/O services are being used.
935   @retval other                  The child handle was not destroyed.
936 
937 **/
938 EFI_STATUS
939 EFIAPI
Ip6ServiceBindingDestroyChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN EFI_HANDLE ChildHandle)940 Ip6ServiceBindingDestroyChild (
941   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
942   IN EFI_HANDLE                    ChildHandle
943   )
944 {
945   EFI_STATUS                Status;
946   IP6_SERVICE               *IpSb;
947   IP6_PROTOCOL              *IpInstance;
948   EFI_IP6_PROTOCOL          *Ip6;
949   EFI_TPL                   OldTpl;
950 
951   if ((This == NULL) || (ChildHandle == NULL)) {
952     return EFI_INVALID_PARAMETER;
953   }
954 
955   //
956   // Retrieve the private context data structures
957   //
958   IpSb   = IP6_SERVICE_FROM_PROTOCOL (This);
959 
960   Status = gBS->OpenProtocol (
961                   ChildHandle,
962                   &gEfiIp6ProtocolGuid,
963                   (VOID **) &Ip6,
964                   gIp6DriverBinding.DriverBindingHandle,
965                   ChildHandle,
966                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
967                   );
968 
969   if (EFI_ERROR (Status)) {
970     return EFI_UNSUPPORTED;
971   }
972 
973   IpInstance = IP6_INSTANCE_FROM_PROTOCOL (Ip6);
974 
975   if (IpInstance->Service != IpSb) {
976     return EFI_INVALID_PARAMETER;
977   }
978 
979   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
980 
981   //
982   // A child can be destroyed more than once. For example,
983   // Ip6DriverBindingStop will destroy all of its children.
984   // when UDP driver is being stopped, it will destroy all
985   // the IP child it opens.
986   //
987   if (IpInstance->InDestroy) {
988     gBS->RestoreTPL (OldTpl);
989     return EFI_SUCCESS;
990   }
991 
992   IpInstance->InDestroy = TRUE;
993 
994   //
995   // Close the Managed Network protocol.
996   //
997   gBS->CloseProtocol (
998          IpSb->MnpChildHandle,
999          &gEfiManagedNetworkProtocolGuid,
1000          gIp6DriverBinding.DriverBindingHandle,
1001          ChildHandle
1002          );
1003 
1004   //
1005   // Uninstall the IP6 protocol first. Many thing happens during
1006   // this:
1007   // 1. The consumer of the IP6 protocol will be stopped if it
1008   // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
1009   // stopped, IP driver's stop function will be called, and uninstall
1010   // EFI_IP6_PROTOCOL will trigger the UDP's stop function. This
1011   // makes it possible to create the network stack bottom up, and
1012   // stop it top down.
1013   // 2. the upper layer will recycle the received packet. The recycle
1014   // event's TPL is higher than this function. The recycle events
1015   // will be called back before preceeding. If any packets not recycled,
1016   // that means there is a resource leak.
1017   //
1018   gBS->RestoreTPL (OldTpl);
1019   Status = gBS->UninstallProtocolInterface (
1020                   ChildHandle,
1021                   &gEfiIp6ProtocolGuid,
1022                   &IpInstance->Ip6Proto
1023                   );
1024   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1025   if (EFI_ERROR (Status)) {
1026     goto ON_ERROR;
1027   }
1028 
1029   Status = Ip6CleanProtocol (IpInstance);
1030   if (EFI_ERROR (Status)) {
1031     gBS->InstallMultipleProtocolInterfaces (
1032            &ChildHandle,
1033            &gEfiIp6ProtocolGuid,
1034            Ip6,
1035            NULL
1036            );
1037 
1038     goto ON_ERROR;
1039   }
1040 
1041   RemoveEntryList (&IpInstance->Link);
1042   ASSERT (IpSb->NumChildren > 0);
1043   IpSb->NumChildren--;
1044 
1045   gBS->RestoreTPL (OldTpl);
1046 
1047   FreePool (IpInstance);
1048   return EFI_SUCCESS;
1049 
1050 ON_ERROR:
1051   gBS->RestoreTPL (OldTpl);
1052 
1053   return Status;
1054 }
1055