]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/Ip6Dxe/Ip6Driver.c
16617c12b174163bfc7279e082c44582b07e1493
[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) && Status != EFI_NOT_READY) {
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 //
603 // ready to go: start the receiving and timer
604 //
605 Status = Ip6ReceiveFrame (Ip6AcceptFrame, IpSb);
606 if (EFI_ERROR (Status)) {
607 goto ON_ERROR;
608 }
609
610 //
611 // The timer expires every 100 (IP6_TIMER_INTERVAL_IN_MS) milliseconds.
612 //
613 Status = gBS->SetTimer (
614 IpSb->FasterTimer,
615 TimerPeriodic,
616 TICKS_PER_MS * IP6_TIMER_INTERVAL_IN_MS
617 );
618 if (EFI_ERROR (Status)) {
619 goto ON_ERROR;
620 }
621
622 //
623 // The timer expires every 1000 (IP6_ONE_SECOND_IN_MS) milliseconds.
624 //
625 Status = gBS->SetTimer (
626 IpSb->Timer,
627 TimerPeriodic,
628 TICKS_PER_MS * IP6_ONE_SECOND_IN_MS
629 );
630 if (EFI_ERROR (Status)) {
631 goto ON_ERROR;
632 }
633
634 //
635 // Initialize the IP6 ID
636 //
637 mIp6Id = NET_RANDOM (NetRandomInitSeed ());
638
639 return EFI_SUCCESS;
640
641 ON_ERROR:
642 Ip6CleanService (IpSb);
643 FreePool (IpSb);
644 return Status;
645 }
646
647 /**
648 Callback function which provided by user to remove one node in NetDestroyLinkList process.
649
650 @param[in] Entry The entry to be removed.
651 @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
652
653 @retval EFI_SUCCESS The entry has been removed successfully.
654 @retval Others Fail to remove the entry.
655
656 **/
657 EFI_STATUS
658 EFIAPI
659 Ip6DestroyChildEntryInHandleBuffer (
660 IN LIST_ENTRY *Entry,
661 IN VOID *Context
662 )
663 {
664 IP6_PROTOCOL *IpInstance;
665 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
666 UINTN NumberOfChildren;
667 EFI_HANDLE *ChildHandleBuffer;
668
669 if (Entry == NULL || Context == NULL) {
670 return EFI_INVALID_PARAMETER;
671 }
672
673 IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP6_PROTOCOL, Link, IP6_PROTOCOL_SIGNATURE);
674 ServiceBinding = ((IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
675 NumberOfChildren = ((IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
676 ChildHandleBuffer = ((IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
677
678 if (!NetIsInHandleBuffer (IpInstance->Handle, NumberOfChildren, ChildHandleBuffer)) {
679 return EFI_SUCCESS;
680 }
681
682 return ServiceBinding->DestroyChild (ServiceBinding, IpInstance->Handle);
683 }
684
685 /**
686 Stop this driver on ControllerHandle.
687
688 @param[in] This Protocol instance pointer.
689 @param[in] ControllerHandle Handle of device to stop driver on.
690 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number
691 of children is zero, stop the entire bus driver.
692 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
693 if NumberOfChildren is 0.
694
695 @retval EFI_SUCCESS The device was stopped.
696 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
697
698 **/
699 EFI_STATUS
700 EFIAPI
701 Ip6DriverBindingStop (
702 IN EFI_DRIVER_BINDING_PROTOCOL *This,
703 IN EFI_HANDLE ControllerHandle,
704 IN UINTN NumberOfChildren,
705 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
706 )
707 {
708 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
709 IP6_SERVICE *IpSb;
710 EFI_HANDLE NicHandle;
711 EFI_STATUS Status;
712 LIST_ENTRY *List;
713 INTN State;
714 BOOLEAN IsDhcp6;
715 IP6_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
716
717 IsDhcp6 = FALSE;
718 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
719 if (NicHandle == NULL) {
720 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp6ProtocolGuid);
721 if (NicHandle != NULL) {
722 IsDhcp6 = TRUE;
723 } else {
724 return EFI_SUCCESS;
725 }
726 }
727
728 Status = gBS->OpenProtocol (
729 NicHandle,
730 &gEfiIp6ServiceBindingProtocolGuid,
731 (VOID **) &ServiceBinding,
732 This->DriverBindingHandle,
733 NicHandle,
734 EFI_OPEN_PROTOCOL_GET_PROTOCOL
735 );
736 if (EFI_ERROR (Status)) {
737 return EFI_DEVICE_ERROR;
738 }
739
740 IpSb = IP6_SERVICE_FROM_PROTOCOL (ServiceBinding);
741
742 if (IsDhcp6) {
743 Status = Ip6ConfigDestroyDhcp6 (&IpSb->Ip6ConfigInstance);
744 gBS->CloseEvent (IpSb->Ip6ConfigInstance.Dhcp6Event);
745 IpSb->Ip6ConfigInstance.Dhcp6Event = NULL;
746 } else if (NumberOfChildren != 0) {
747 //
748 // NumberOfChildren is not zero, destroy the IP6 children instances in ChildHandleBuffer.
749 //
750 List = &IpSb->Children;
751 Context.ServiceBinding = ServiceBinding;
752 Context.NumberOfChildren = NumberOfChildren;
753 Context.ChildHandleBuffer = ChildHandleBuffer;
754 Status = NetDestroyLinkList (
755 List,
756 Ip6DestroyChildEntryInHandleBuffer,
757 &Context,
758 NULL
759 );
760 } else if (IsListEmpty (&IpSb->Children)) {
761 State = IpSb->State;
762 IpSb->State = IP6_SERVICE_DESTROY;
763
764 Status = Ip6CleanService (IpSb);
765 if (EFI_ERROR (Status)) {
766 IpSb->State = State;
767 goto Exit;
768 }
769
770 Status = gBS->UninstallMultipleProtocolInterfaces (
771 NicHandle,
772 &gEfiIp6ServiceBindingProtocolGuid,
773 ServiceBinding,
774 &gEfiIp6ConfigProtocolGuid,
775 &IpSb->Ip6ConfigInstance.Ip6Config,
776 NULL
777 );
778 ASSERT_EFI_ERROR (Status);
779 FreePool (IpSb);
780 Status = EFI_SUCCESS;
781 }
782
783 Exit:
784 return Status;
785 }
786
787
788 /**
789 Creates a child handle with a set of I/O services.
790
791 @param[in] This Protocol instance pointer.
792 @param[in] ChildHandle Pointer to the handle of the child to create. If
793 it is NULL, then a new handle is created. If it
794 is not NULL, then the I/O services are added to
795 the existing child handle.
796
797 @retval EFI_SUCCES The child handle was created with the I/O services.
798 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
799 the child.
800 @retval other The child handle was not created.
801
802 **/
803 EFI_STATUS
804 EFIAPI
805 Ip6ServiceBindingCreateChild (
806 IN EFI_SERVICE_BINDING_PROTOCOL *This,
807 IN EFI_HANDLE *ChildHandle
808 )
809 {
810 IP6_SERVICE *IpSb;
811 IP6_PROTOCOL *IpInstance;
812 EFI_TPL OldTpl;
813 EFI_STATUS Status;
814 VOID *Mnp;
815
816 if ((This == NULL) || (ChildHandle == NULL)) {
817 return EFI_INVALID_PARAMETER;
818 }
819
820 IpSb = IP6_SERVICE_FROM_PROTOCOL (This);
821
822 if (IpSb->LinkLocalDadFail) {
823 return EFI_DEVICE_ERROR;
824 }
825
826 IpInstance = AllocatePool (sizeof (IP6_PROTOCOL));
827
828 if (IpInstance == NULL) {
829 return EFI_OUT_OF_RESOURCES;
830 }
831
832 Ip6InitProtocol (IpSb, IpInstance);
833
834 //
835 // Install Ip6 onto ChildHandle
836 //
837 Status = gBS->InstallMultipleProtocolInterfaces (
838 ChildHandle,
839 &gEfiIp6ProtocolGuid,
840 &IpInstance->Ip6Proto,
841 NULL
842 );
843 if (EFI_ERROR (Status)) {
844 goto ON_ERROR;
845 }
846
847 IpInstance->Handle = *ChildHandle;
848
849 //
850 // Open the Managed Network protocol BY_CHILD.
851 //
852 Status = gBS->OpenProtocol (
853 IpSb->MnpChildHandle,
854 &gEfiManagedNetworkProtocolGuid,
855 (VOID **) &Mnp,
856 gIp6DriverBinding.DriverBindingHandle,
857 IpInstance->Handle,
858 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
859 );
860 if (EFI_ERROR (Status)) {
861 gBS->UninstallMultipleProtocolInterfaces (
862 ChildHandle,
863 &gEfiIp6ProtocolGuid,
864 &IpInstance->Ip6Proto,
865 NULL
866 );
867
868 goto ON_ERROR;
869 }
870
871 //
872 // Insert it into the service binding instance.
873 //
874 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
875
876 InsertTailList (&IpSb->Children, &IpInstance->Link);
877 IpSb->NumChildren++;
878
879 gBS->RestoreTPL (OldTpl);
880
881 ON_ERROR:
882
883 if (EFI_ERROR (Status)) {
884
885 Ip6CleanProtocol (IpInstance);
886
887 FreePool (IpInstance);
888 }
889
890 return Status;
891 }
892
893 /**
894 Destroys a child handle with a set of I/O services.
895
896 @param[in] This Protocol instance pointer.
897 @param[in] ChildHandle Handle of the child to destroy.
898
899 @retval EFI_SUCCES The I/O services were removed from the child
900 handle.
901 @retval EFI_UNSUPPORTED The child handle does not support the I/O services
902 that are being removed.
903 @retval EFI_INVALID_PARAMETER Child handle is NULL.
904 @retval EFI_ACCESS_DENIED The child handle could not be destroyed because
905 its I/O services are being used.
906 @retval other The child handle was not destroyed.
907
908 **/
909 EFI_STATUS
910 EFIAPI
911 Ip6ServiceBindingDestroyChild (
912 IN EFI_SERVICE_BINDING_PROTOCOL *This,
913 IN EFI_HANDLE ChildHandle
914 )
915 {
916 EFI_STATUS Status;
917 IP6_SERVICE *IpSb;
918 IP6_PROTOCOL *IpInstance;
919 EFI_IP6_PROTOCOL *Ip6;
920 EFI_TPL OldTpl;
921
922 if ((This == NULL) || (ChildHandle == NULL)) {
923 return EFI_INVALID_PARAMETER;
924 }
925
926 //
927 // Retrieve the private context data structures
928 //
929 IpSb = IP6_SERVICE_FROM_PROTOCOL (This);
930
931 Status = gBS->OpenProtocol (
932 ChildHandle,
933 &gEfiIp6ProtocolGuid,
934 (VOID **) &Ip6,
935 gIp6DriverBinding.DriverBindingHandle,
936 ChildHandle,
937 EFI_OPEN_PROTOCOL_GET_PROTOCOL
938 );
939
940 if (EFI_ERROR (Status)) {
941 return EFI_UNSUPPORTED;
942 }
943
944 IpInstance = IP6_INSTANCE_FROM_PROTOCOL (Ip6);
945
946 if (IpInstance->Service != IpSb) {
947 return EFI_INVALID_PARAMETER;
948 }
949
950 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
951
952 //
953 // A child can be destroyed more than once. For example,
954 // Ip6DriverBindingStop will destroy all of its children.
955 // when UDP driver is being stopped, it will destroy all
956 // the IP child it opens.
957 //
958 if (IpInstance->InDestroy) {
959 gBS->RestoreTPL (OldTpl);
960 return EFI_SUCCESS;
961 }
962
963 IpInstance->InDestroy = TRUE;
964
965 //
966 // Close the Managed Network protocol.
967 //
968 gBS->CloseProtocol (
969 IpSb->MnpChildHandle,
970 &gEfiManagedNetworkProtocolGuid,
971 gIp6DriverBinding.DriverBindingHandle,
972 ChildHandle
973 );
974
975 //
976 // Uninstall the IP6 protocol first. Many thing happens during
977 // this:
978 // 1. The consumer of the IP6 protocol will be stopped if it
979 // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
980 // stopped, IP driver's stop function will be called, and uninstall
981 // EFI_IP6_PROTOCOL will trigger the UDP's stop function. This
982 // makes it possible to create the network stack bottom up, and
983 // stop it top down.
984 // 2. the upper layer will recycle the received packet. The recycle
985 // event's TPL is higher than this function. The recycle events
986 // will be called back before preceeding. If any packets not recycled,
987 // that means there is a resource leak.
988 //
989 gBS->RestoreTPL (OldTpl);
990 Status = gBS->UninstallProtocolInterface (
991 ChildHandle,
992 &gEfiIp6ProtocolGuid,
993 &IpInstance->Ip6Proto
994 );
995 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
996 if (EFI_ERROR (Status)) {
997 goto ON_ERROR;
998 }
999
1000 Status = Ip6CleanProtocol (IpInstance);
1001 if (EFI_ERROR (Status)) {
1002 gBS->InstallMultipleProtocolInterfaces (
1003 &ChildHandle,
1004 &gEfiIp6ProtocolGuid,
1005 Ip6,
1006 NULL
1007 );
1008
1009 goto ON_ERROR;
1010 }
1011
1012 RemoveEntryList (&IpInstance->Link);
1013 ASSERT (IpSb->NumChildren > 0);
1014 IpSb->NumChildren--;
1015
1016 gBS->RestoreTPL (OldTpl);
1017
1018 FreePool (IpInstance);
1019 return EFI_SUCCESS;
1020
1021 ON_ERROR:
1022 gBS->RestoreTPL (OldTpl);
1023
1024 return Status;
1025 }