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
IpSec2InstalledCallback(IN EFI_EVENT Event,IN VOID * Context)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
Ip6DriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
Ip6DriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)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
Ip6CleanService(IN IP6_SERVICE * IpSb)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
Ip6CreateService(IN EFI_HANDLE Controller,IN EFI_HANDLE ImageHandle,OUT IP6_SERVICE ** Service)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
Ip6DriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)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
Ip6DestroyChildEntryInHandleBuffer(IN LIST_ENTRY * Entry,IN VOID * Context)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
Ip6DriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)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
Ip6ServiceBindingCreateChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN EFI_HANDLE * ChildHandle)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
Ip6ServiceBindingDestroyChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN EFI_HANDLE ChildHandle)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