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