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