Home | History | Annotate | Download | only in Ip6Dxe
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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