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