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