]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c
87ec968e7b1ffabd887a7e109369b3c58078d310
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Driver.c
1 /** @file
2 The driver binding and service binding protocol for IP4 driver.
3
4 Copyright (c) 2005 - 2019, 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 "Ip4Impl.h"
18
19 EFI_DRIVER_BINDING_PROTOCOL gIp4DriverBinding = {
20 Ip4DriverBindingSupported,
21 Ip4DriverBindingStart,
22 Ip4DriverBindingStop,
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 EFI_STATUS Status;
45 //
46 // Test if protocol was even found.
47 // Notification function will be called at least once.
48 //
49 Status = gBS->LocateProtocol (&gEfiIpSec2ProtocolGuid, NULL, (VOID **)&mIpSec);
50 if (Status == EFI_SUCCESS && mIpSec != NULL) {
51 //
52 // Close the event so it does not get called again.
53 //
54 gBS->CloseEvent (Event);
55
56 mIpSec2Installed = TRUE;
57 }
58 }
59
60 /**
61 This is the declaration of an EFI image entry point. This entry point is
62 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
63 both device drivers and bus drivers.
64
65 The entry point for IP4 driver which install the driver
66 binding and component name protocol on its image.
67
68 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
69 @param[in] SystemTable A pointer to the EFI System Table.
70
71 @retval EFI_SUCCESS The operation completed successfully.
72 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
73
74 **/
75 EFI_STATUS
76 EFIAPI
77 Ip4DriverEntryPoint (
78 IN EFI_HANDLE ImageHandle,
79 IN EFI_SYSTEM_TABLE *SystemTable
80 )
81 {
82 VOID *Registration;
83
84 EfiCreateProtocolNotifyEvent (
85 &gEfiIpSec2ProtocolGuid,
86 TPL_CALLBACK,
87 IpSec2InstalledCallback,
88 NULL,
89 &Registration
90 );
91
92 return EfiLibInstallDriverBindingComponentName2 (
93 ImageHandle,
94 SystemTable,
95 &gIp4DriverBinding,
96 ImageHandle,
97 &gIp4ComponentName,
98 &gIp4ComponentName2
99 );
100 }
101
102 /**
103 Test to see if this driver supports ControllerHandle. This service
104 is called by the EFI boot service ConnectController(). In
105 order to make drivers as small as possible, there are a few calling
106 restrictions for this service. ConnectController() must
107 follow these calling restrictions. If any other agent wishes to call
108 Supported() it must also follow these calling restrictions.
109
110 @param[in] This Protocol instance pointer.
111 @param[in] ControllerHandle Handle of device to test
112 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
113 device to start.
114
115 @retval EFI_SUCCESS This driver supports this device
116 @retval EFI_ALREADY_STARTED This driver is already running on this device
117 @retval other This driver does not support this device
118
119 **/
120 EFI_STATUS
121 EFIAPI
122 Ip4DriverBindingSupported (
123 IN EFI_DRIVER_BINDING_PROTOCOL * This,
124 IN EFI_HANDLE ControllerHandle,
125 IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
126 )
127 {
128 EFI_STATUS Status;
129
130 //
131 // Test for the MNP service binding Protocol
132 //
133 Status = gBS->OpenProtocol (
134 ControllerHandle,
135 &gEfiManagedNetworkServiceBindingProtocolGuid,
136 NULL,
137 This->DriverBindingHandle,
138 ControllerHandle,
139 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
140 );
141
142 if (EFI_ERROR (Status)) {
143 return Status;
144 }
145
146 //
147 // Test for the Arp service binding Protocol
148 //
149 Status = gBS->OpenProtocol (
150 ControllerHandle,
151 &gEfiArpServiceBindingProtocolGuid,
152 NULL,
153 This->DriverBindingHandle,
154 ControllerHandle,
155 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
156 );
157
158 return Status;
159 }
160
161 /**
162 Clean up a IP4 service binding instance. It will release all
163 the resource allocated by the instance. The instance may be
164 partly initialized, or partly destroyed. If a resource is
165 destroyed, it is marked as that in case the destroy failed and
166 being called again later.
167
168 @param[in] IpSb The IP4 service binding instance to clean up
169
170 @retval EFI_SUCCESS The resource used by the instance are cleaned up
171 @retval other Failed to clean up some of the resources.
172
173 **/
174 EFI_STATUS
175 Ip4CleanService (
176 IN IP4_SERVICE *IpSb
177 );
178
179
180 /**
181 Create a new IP4 driver service binding private instance.
182
183 @param Controller The controller that has MNP service binding
184 installed
185 @param ImageHandle The IP4 driver's image handle
186 @param Service The variable to receive the newly created IP4
187 service.
188
189 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resource
190 @retval EFI_SUCCESS A new IP4 service binding private is created.
191 @retval other Other error occurs.
192
193 **/
194 EFI_STATUS
195 Ip4CreateService (
196 IN EFI_HANDLE Controller,
197 IN EFI_HANDLE ImageHandle,
198 OUT IP4_SERVICE **Service
199 )
200 {
201 IP4_SERVICE *IpSb;
202 EFI_STATUS Status;
203
204 ASSERT (Service != NULL);
205
206 *Service = NULL;
207
208 //
209 // allocate a service private data then initialize all the filed to
210 // empty resources, so if any thing goes wrong when allocating
211 // resources, Ip4CleanService can be called to clean it up.
212 //
213 IpSb = AllocateZeroPool (sizeof (IP4_SERVICE));
214
215 if (IpSb == NULL) {
216 return EFI_OUT_OF_RESOURCES;
217 }
218
219 IpSb->Signature = IP4_SERVICE_SIGNATURE;
220 IpSb->ServiceBinding.CreateChild = Ip4ServiceBindingCreateChild;
221 IpSb->ServiceBinding.DestroyChild = Ip4ServiceBindingDestroyChild;
222 IpSb->State = IP4_SERVICE_UNSTARTED;
223
224 IpSb->NumChildren = 0;
225 InitializeListHead (&IpSb->Children);
226
227 InitializeListHead (&IpSb->Interfaces);
228 IpSb->DefaultInterface = NULL;
229 IpSb->DefaultRouteTable = NULL;
230
231 Ip4InitAssembleTable (&IpSb->Assemble);
232
233 IpSb->IgmpCtrl.Igmpv1QuerySeen = 0;
234 InitializeListHead (&IpSb->IgmpCtrl.Groups);
235
236 IpSb->Image = ImageHandle;
237 IpSb->Controller = Controller;
238
239 IpSb->MnpChildHandle = NULL;
240 IpSb->Mnp = NULL;
241
242 IpSb->MnpConfigData.ReceivedQueueTimeoutValue = 0;
243 IpSb->MnpConfigData.TransmitQueueTimeoutValue = 0;
244 IpSb->MnpConfigData.ProtocolTypeFilter = IP4_ETHER_PROTO;
245 IpSb->MnpConfigData.EnableUnicastReceive = TRUE;
246 IpSb->MnpConfigData.EnableMulticastReceive = TRUE;
247 IpSb->MnpConfigData.EnableBroadcastReceive = TRUE;
248 IpSb->MnpConfigData.EnablePromiscuousReceive = FALSE;
249 IpSb->MnpConfigData.FlushQueuesOnReset = TRUE;
250 IpSb->MnpConfigData.EnableReceiveTimestamps = FALSE;
251 IpSb->MnpConfigData.DisableBackgroundPolling = FALSE;
252
253 ZeroMem (&IpSb->SnpMode, sizeof (EFI_SIMPLE_NETWORK_MODE));
254
255 IpSb->Timer = NULL;
256 IpSb->ReconfigCheckTimer = NULL;
257
258 IpSb->ReconfigEvent = NULL;
259
260 IpSb->Reconfig = FALSE;
261
262 IpSb->MediaPresent = TRUE;
263
264 //
265 // Create various resources. First create the route table, timer
266 // event, ReconfigEvent and MNP child. IGMP, interface's initialization depend
267 // on the MNP child.
268 //
269 IpSb->DefaultRouteTable = Ip4CreateRouteTable ();
270
271 if (IpSb->DefaultRouteTable == NULL) {
272 Status = EFI_OUT_OF_RESOURCES;
273 goto ON_ERROR;
274 }
275
276 Status = gBS->CreateEvent (
277 EVT_NOTIFY_SIGNAL | EVT_TIMER,
278 TPL_CALLBACK,
279 Ip4TimerTicking,
280 IpSb,
281 &IpSb->Timer
282 );
283
284 if (EFI_ERROR (Status)) {
285 goto ON_ERROR;
286 }
287
288 Status = gBS->CreateEvent (
289 EVT_NOTIFY_SIGNAL | EVT_TIMER,
290 TPL_CALLBACK,
291 Ip4TimerReconfigChecking,
292 IpSb,
293 &IpSb->ReconfigCheckTimer
294 );
295
296 if (EFI_ERROR (Status)) {
297 goto ON_ERROR;
298 }
299
300 Status = gBS->CreateEvent (
301 EVT_NOTIFY_SIGNAL,
302 TPL_NOTIFY,
303 Ip4AutoReconfigCallBack,
304 IpSb,
305 &IpSb->ReconfigEvent
306 );
307 if (EFI_ERROR (Status)) {
308 goto ON_ERROR;
309 }
310
311 Status = NetLibCreateServiceChild (
312 Controller,
313 ImageHandle,
314 &gEfiManagedNetworkServiceBindingProtocolGuid,
315 &IpSb->MnpChildHandle
316 );
317
318 if (EFI_ERROR (Status)) {
319 goto ON_ERROR;
320 }
321
322 Status = gBS->OpenProtocol (
323 IpSb->MnpChildHandle,
324 &gEfiManagedNetworkProtocolGuid,
325 (VOID **) &IpSb->Mnp,
326 ImageHandle,
327 Controller,
328 EFI_OPEN_PROTOCOL_BY_DRIVER
329 );
330
331 if (EFI_ERROR (Status)) {
332 goto ON_ERROR;
333 }
334
335 Status = Ip4ServiceConfigMnp (IpSb, TRUE);
336
337 if (EFI_ERROR (Status)) {
338 goto ON_ERROR;
339 }
340
341 Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &IpSb->SnpMode);
342
343 if (EFI_ERROR (Status)) {
344 goto ON_ERROR;
345 }
346
347 Status = Ip4InitIgmp (IpSb);
348
349 if (EFI_ERROR (Status)) {
350 goto ON_ERROR;
351 }
352
353 IpSb->MacString = NULL;
354 Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &IpSb->MacString);
355
356 if (EFI_ERROR (Status)) {
357 goto ON_ERROR;
358 }
359
360 IpSb->DefaultInterface = Ip4CreateInterface (IpSb->Mnp, Controller, ImageHandle);
361
362 if (IpSb->DefaultInterface == NULL) {
363 Status = EFI_OUT_OF_RESOURCES;
364 goto ON_ERROR;
365 }
366
367 InsertHeadList (&IpSb->Interfaces, &IpSb->DefaultInterface->Link);
368
369 ZeroMem (&IpSb->Ip4Config2Instance, sizeof (IP4_CONFIG2_INSTANCE));
370
371 Status = Ip4Config2InitInstance (&IpSb->Ip4Config2Instance);
372
373 if (EFI_ERROR (Status)) {
374 goto ON_ERROR;
375 }
376
377 IpSb->MaxPacketSize = IpSb->SnpMode.MaxPacketSize - sizeof (IP4_HEAD);
378 if (NetLibGetVlanId (IpSb->Controller) != 0) {
379 //
380 // This is a VLAN device, reduce MTU by VLAN tag length
381 //
382 IpSb->MaxPacketSize -= NET_VLAN_TAG_LEN;
383 }
384 IpSb->OldMaxPacketSize = IpSb->MaxPacketSize;
385 *Service = IpSb;
386
387 return EFI_SUCCESS;
388
389 ON_ERROR:
390 Ip4CleanService (IpSb);
391 FreePool (IpSb);
392
393 return Status;
394 }
395
396
397 /**
398 Clean up a IP4 service binding instance. It will release all
399 the resource allocated by the instance. The instance may be
400 partly initialized, or partly destroyed. If a resource is
401 destroyed, it is marked as that in case the destroy failed and
402 being called again later.
403
404 @param[in] IpSb The IP4 service binding instance to clean up
405
406 @retval EFI_SUCCESS The resource used by the instance are cleaned up
407 @retval other Failed to clean up some of the resources.
408
409 **/
410 EFI_STATUS
411 Ip4CleanService (
412 IN IP4_SERVICE *IpSb
413 )
414 {
415 EFI_STATUS Status;
416
417 IpSb->State = IP4_SERVICE_DESTROY;
418
419 if (IpSb->Timer != NULL) {
420 gBS->SetTimer (IpSb->Timer, TimerCancel, 0);
421 gBS->CloseEvent (IpSb->Timer);
422
423 IpSb->Timer = NULL;
424 }
425
426 if (IpSb->ReconfigCheckTimer != NULL) {
427 gBS->SetTimer (IpSb->ReconfigCheckTimer, TimerCancel, 0);
428 gBS->CloseEvent (IpSb->ReconfigCheckTimer);
429
430 IpSb->ReconfigCheckTimer = NULL;
431 }
432
433 if (IpSb->DefaultInterface != NULL) {
434 Status = Ip4FreeInterface (IpSb->DefaultInterface, NULL);
435
436 if (EFI_ERROR (Status)) {
437 return Status;
438 }
439
440 IpSb->DefaultInterface = NULL;
441 }
442
443 if (IpSb->DefaultRouteTable != NULL) {
444 Ip4FreeRouteTable (IpSb->DefaultRouteTable);
445 IpSb->DefaultRouteTable = NULL;
446 }
447
448 Ip4CleanAssembleTable (&IpSb->Assemble);
449
450 if (IpSb->MnpChildHandle != NULL) {
451 if (IpSb->Mnp != NULL) {
452 gBS->CloseProtocol (
453 IpSb->MnpChildHandle,
454 &gEfiManagedNetworkProtocolGuid,
455 IpSb->Image,
456 IpSb->Controller
457 );
458
459 IpSb->Mnp = NULL;
460 }
461
462 NetLibDestroyServiceChild (
463 IpSb->Controller,
464 IpSb->Image,
465 &gEfiManagedNetworkServiceBindingProtocolGuid,
466 IpSb->MnpChildHandle
467 );
468
469 IpSb->MnpChildHandle = NULL;
470 }
471
472 if (IpSb->ReconfigEvent != NULL) {
473 gBS->CloseEvent (IpSb->ReconfigEvent);
474
475 IpSb->ReconfigEvent = NULL;
476 }
477
478 IpSb->Reconfig = FALSE;
479
480 if (IpSb->MacString != NULL) {
481 FreePool (IpSb->MacString);
482 }
483
484 Ip4Config2CleanInstance (&IpSb->Ip4Config2Instance);
485
486 return EFI_SUCCESS;
487 }
488
489 /**
490 Callback function which provided by user to remove one node in NetDestroyLinkList process.
491
492 @param[in] Entry The entry to be removed.
493 @param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
494
495 @retval EFI_SUCCESS The entry has been removed successfully.
496 @retval Others Fail to remove the entry.
497
498 **/
499 EFI_STATUS
500 EFIAPI
501 Ip4DestroyChildEntryInHandleBuffer (
502 IN LIST_ENTRY *Entry,
503 IN VOID *Context
504 )
505 {
506 IP4_PROTOCOL *IpInstance;
507 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
508 UINTN NumberOfChildren;
509 EFI_HANDLE *ChildHandleBuffer;
510
511 if (Entry == NULL || Context == NULL) {
512 return EFI_INVALID_PARAMETER;
513 }
514
515 IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP4_PROTOCOL, Link, IP4_PROTOCOL_SIGNATURE);
516 ServiceBinding = ((IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
517 NumberOfChildren = ((IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
518 ChildHandleBuffer = ((IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
519
520 if (!NetIsInHandleBuffer (IpInstance->Handle, NumberOfChildren, ChildHandleBuffer)) {
521 return EFI_SUCCESS;
522 }
523
524 return ServiceBinding->DestroyChild (ServiceBinding, IpInstance->Handle);
525 }
526
527 /**
528 Start this driver on ControllerHandle. This service is called by the
529 EFI boot service ConnectController(). In order to make
530 drivers as small as possible, there are a few calling restrictions for
531 this service. ConnectController() must follow these
532 calling restrictions. If any other agent wishes to call Start() it
533 must also follow these calling restrictions.
534
535 @param[in] This Protocol instance pointer.
536 @param[in] ControllerHandle Handle of device to bind driver to
537 @param[in] RemainingDevicePath Optional parameter use to pick a specific child
538 device to start.
539
540 @retval EFI_SUCCESS This driver is added to ControllerHandle
541 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
542 @retval other This driver does not support this device
543
544 **/
545 EFI_STATUS
546 EFIAPI
547 Ip4DriverBindingStart (
548 IN EFI_DRIVER_BINDING_PROTOCOL *This,
549 IN EFI_HANDLE ControllerHandle,
550 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
551 )
552 {
553 EFI_STATUS Status;
554 IP4_SERVICE *IpSb;
555 EFI_IP4_CONFIG2_PROTOCOL *Ip4Cfg2;
556 UINTN Index;
557 IP4_CONFIG2_DATA_ITEM *DataItem;
558
559 IpSb = NULL;
560 Ip4Cfg2 = NULL;
561 DataItem = NULL;
562
563 //
564 // Test for the Ip4 service binding protocol
565 //
566 Status = gBS->OpenProtocol (
567 ControllerHandle,
568 &gEfiIp4ServiceBindingProtocolGuid,
569 NULL,
570 This->DriverBindingHandle,
571 ControllerHandle,
572 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
573 );
574
575 if (Status == EFI_SUCCESS) {
576 return EFI_ALREADY_STARTED;
577 }
578
579 Status = Ip4CreateService (ControllerHandle, This->DriverBindingHandle, &IpSb);
580
581 if (EFI_ERROR (Status)) {
582 return Status;
583 }
584
585 ASSERT (IpSb != NULL);
586
587 Ip4Cfg2 = &IpSb->Ip4Config2Instance.Ip4Config2;
588
589 //
590 // Install the Ip4ServiceBinding Protocol onto ControlerHandle
591 //
592 Status = gBS->InstallMultipleProtocolInterfaces (
593 &ControllerHandle,
594 &gEfiIp4ServiceBindingProtocolGuid,
595 &IpSb->ServiceBinding,
596 &gEfiIp4Config2ProtocolGuid,
597 Ip4Cfg2,
598 NULL
599 );
600
601 if (EFI_ERROR (Status)) {
602 goto FREE_SERVICE;
603 }
604
605 //
606 // Read the config data from NV variable again.
607 // The default data can be changed by other drivers.
608 //
609 Status = Ip4Config2ReadConfigData (IpSb->MacString, &IpSb->Ip4Config2Instance);
610 if (EFI_ERROR (Status)) {
611 goto UNINSTALL_PROTOCOL;
612 }
613
614 //
615 // Consume the installed EFI_IP4_CONFIG2_PROTOCOL to set the default data items.
616 //
617 for (Index = Ip4Config2DataTypePolicy; Index < Ip4Config2DataTypeMaximum; Index++) {
618 DataItem = &IpSb->Ip4Config2Instance.DataItem[Index];
619 if (DataItem->Data.Ptr != NULL) {
620 Status = Ip4Cfg2->SetData (
621 Ip4Cfg2,
622 Index,
623 DataItem->DataSize,
624 DataItem->Data.Ptr
625 );
626 if (EFI_ERROR(Status)) {
627 goto UNINSTALL_PROTOCOL;
628 }
629
630 if (Index == Ip4Config2DataTypePolicy && (*(DataItem->Data.Policy) == Ip4Config2PolicyDhcp)) {
631 break;
632 }
633 }
634 }
635
636 //
637 // Ready to go: start the receiving and timer.
638 // Ip4Config2SetPolicy maybe call Ip4ReceiveFrame() to set the default interface's RecvRequest first after
639 // Ip4Config2 instance is initialized. So, EFI_ALREADY_STARTED is the allowed return status.
640 //
641 Status = Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);
642
643 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
644 goto UNINSTALL_PROTOCOL;
645 }
646
647 Status = gBS->SetTimer (IpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
648
649 if (EFI_ERROR (Status)) {
650 goto UNINSTALL_PROTOCOL;
651 }
652
653 Status = gBS->SetTimer (IpSb->ReconfigCheckTimer, TimerPeriodic, 500 * TICKS_PER_MS);
654
655 if (EFI_ERROR (Status)) {
656 goto UNINSTALL_PROTOCOL;
657 }
658
659 //
660 // Initialize the IP4 ID
661 //
662 mIp4Id = (UINT16)NET_RANDOM (NetRandomInitSeed ());
663
664 return Status;
665
666 UNINSTALL_PROTOCOL:
667 gBS->UninstallMultipleProtocolInterfaces (
668 ControllerHandle,
669 &gEfiIp4ServiceBindingProtocolGuid,
670 &IpSb->ServiceBinding,
671 &gEfiIp4Config2ProtocolGuid,
672 Ip4Cfg2,
673 NULL
674 );
675
676 FREE_SERVICE:
677 Ip4CleanService (IpSb);
678 FreePool (IpSb);
679 return Status;
680 }
681
682
683 /**
684 Stop this driver on ControllerHandle. This service is called by the
685 EFI boot service DisconnectController(). In order to
686 make drivers as small as possible, there are a few calling
687 restrictions for this service. DisconnectController()
688 must follow these calling restrictions. If any other agent wishes
689 to call Stop() it must also follow these calling restrictions.
690
691 @param[in] This Protocol instance pointer.
692 @param[in] ControllerHandle Handle of device to stop driver on
693 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number
694 of children is zero stop the entire bus driver.
695 @param[in] ChildHandleBuffer List of Child Handles to Stop.
696
697 @retval EFI_SUCCESS This driver is removed ControllerHandle
698 @retval other This driver was not removed from this device
699
700 **/
701 EFI_STATUS
702 EFIAPI
703 Ip4DriverBindingStop (
704 IN EFI_DRIVER_BINDING_PROTOCOL *This,
705 IN EFI_HANDLE ControllerHandle,
706 IN UINTN NumberOfChildren,
707 IN EFI_HANDLE *ChildHandleBuffer
708 )
709 {
710 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
711 IP4_SERVICE *IpSb;
712 EFI_HANDLE NicHandle;
713 EFI_STATUS Status;
714 INTN State;
715 LIST_ENTRY *List;
716 IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
717 IP4_INTERFACE *IpIf;
718 IP4_ROUTE_TABLE *RouteTable;
719
720 BOOLEAN IsDhcp4;
721
722 IsDhcp4 = FALSE;
723
724 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
725 if (NicHandle == NULL) {
726 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid);
727 if (NicHandle == NULL) {
728 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);
729 if (NicHandle != NULL) {
730 IsDhcp4 = TRUE;
731 } else {
732 return EFI_SUCCESS;
733 }
734 }
735 }
736
737 Status = gBS->OpenProtocol (
738 NicHandle,
739 &gEfiIp4ServiceBindingProtocolGuid,
740 (VOID **) &ServiceBinding,
741 This->DriverBindingHandle,
742 NicHandle,
743 EFI_OPEN_PROTOCOL_GET_PROTOCOL
744 );
745 if (EFI_ERROR (Status)) {
746 return EFI_DEVICE_ERROR;
747 }
748
749 IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
750
751 if (IsDhcp4) {
752 Status = Ip4Config2DestroyDhcp4 (&IpSb->Ip4Config2Instance);
753 gBS->CloseEvent (IpSb->Ip4Config2Instance.Dhcp4Event);
754 IpSb->Ip4Config2Instance.Dhcp4Event = NULL;
755 } else if (NumberOfChildren != 0) {
756 List = &IpSb->Children;
757 Context.ServiceBinding = ServiceBinding;
758 Context.NumberOfChildren = NumberOfChildren;
759 Context.ChildHandleBuffer = ChildHandleBuffer;
760 Status = NetDestroyLinkList (
761 List,
762 Ip4DestroyChildEntryInHandleBuffer,
763 &Context,
764 NULL
765 );
766 } else if (IpSb->DefaultInterface->ArpHandle == ControllerHandle) {
767
768 //
769 // The ARP protocol for the default interface is being uninstalled and all
770 // its IP child handles should have been destroyed before. So, release the
771 // default interface and route table, create a new one and mark it as not started.
772 //
773 Ip4CancelReceive (IpSb->DefaultInterface);
774 Ip4FreeInterface (IpSb->DefaultInterface, NULL);
775 Ip4FreeRouteTable (IpSb->DefaultRouteTable);
776
777 IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
778 if (IpIf == NULL) {
779 goto ON_ERROR;
780 }
781 RouteTable = Ip4CreateRouteTable ();
782 if (RouteTable == NULL) {
783 Ip4FreeInterface (IpIf, NULL);
784 goto ON_ERROR;;
785 }
786
787 IpSb->DefaultInterface = IpIf;
788 InsertHeadList (&IpSb->Interfaces, &IpIf->Link);
789 IpSb->DefaultRouteTable = RouteTable;
790 Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);
791
792 IpSb->State = IP4_SERVICE_UNSTARTED;
793
794 } else if (IsListEmpty (&IpSb->Children)) {
795 State = IpSb->State;
796 //
797 // OK, clean other resources then uninstall the service binding protocol.
798 //
799 Status = Ip4CleanService (IpSb);
800 if (EFI_ERROR (Status)) {
801 IpSb->State = State;
802 goto ON_ERROR;
803 }
804
805 gBS->UninstallMultipleProtocolInterfaces (
806 NicHandle,
807 &gEfiIp4ServiceBindingProtocolGuid,
808 ServiceBinding,
809 &gEfiIp4Config2ProtocolGuid,
810 &IpSb->Ip4Config2Instance.Ip4Config2,
811 NULL
812 );
813
814 if (gIp4ControllerNameTable != NULL) {
815 FreeUnicodeStringTable (gIp4ControllerNameTable);
816 gIp4ControllerNameTable = NULL;
817 }
818 FreePool (IpSb);
819 }
820
821 ON_ERROR:
822 return Status;
823 }
824
825
826 /**
827 Creates a child handle and installs a protocol.
828
829 The CreateChild() function installs a protocol on ChildHandle.
830 If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
831 If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
832
833 @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
834 @param ChildHandle Pointer to the handle of the child to create. If it is NULL,
835 then a new handle is created. If it is a pointer to an existing UEFI handle,
836 then the protocol is added to the existing UEFI handle.
837
838 @retval EFI_SUCCES The protocol was added to ChildHandle.
839 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
840 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
841 the child
842 @retval other The child handle was not created
843
844 **/
845 EFI_STATUS
846 EFIAPI
847 Ip4ServiceBindingCreateChild (
848 IN EFI_SERVICE_BINDING_PROTOCOL *This,
849 IN OUT EFI_HANDLE *ChildHandle
850 )
851 {
852 IP4_SERVICE *IpSb;
853 IP4_PROTOCOL *IpInstance;
854 EFI_TPL OldTpl;
855 EFI_STATUS Status;
856 VOID *Mnp;
857
858 if ((This == NULL) || (ChildHandle == NULL)) {
859 return EFI_INVALID_PARAMETER;
860 }
861
862 IpSb = IP4_SERVICE_FROM_PROTOCOL (This);
863 IpInstance = AllocatePool (sizeof (IP4_PROTOCOL));
864
865 if (IpInstance == NULL) {
866 return EFI_OUT_OF_RESOURCES;
867 }
868
869 Ip4InitProtocol (IpSb, IpInstance);
870
871 //
872 // Install Ip4 onto ChildHandle
873 //
874 Status = gBS->InstallMultipleProtocolInterfaces (
875 ChildHandle,
876 &gEfiIp4ProtocolGuid,
877 &IpInstance->Ip4Proto,
878 NULL
879 );
880
881 if (EFI_ERROR (Status)) {
882 goto ON_ERROR;
883 }
884
885 IpInstance->Handle = *ChildHandle;
886
887 //
888 // Open the Managed Network protocol BY_CHILD.
889 //
890 Status = gBS->OpenProtocol (
891 IpSb->MnpChildHandle,
892 &gEfiManagedNetworkProtocolGuid,
893 (VOID **) &Mnp,
894 gIp4DriverBinding.DriverBindingHandle,
895 IpInstance->Handle,
896 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
897 );
898 if (EFI_ERROR (Status)) {
899 gBS->UninstallMultipleProtocolInterfaces (
900 ChildHandle,
901 &gEfiIp4ProtocolGuid,
902 &IpInstance->Ip4Proto,
903 NULL
904 );
905
906 goto ON_ERROR;
907 }
908
909 //
910 // Insert it into the service binding instance.
911 //
912 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
913
914 InsertTailList (&IpSb->Children, &IpInstance->Link);
915 IpSb->NumChildren++;
916
917 gBS->RestoreTPL (OldTpl);
918
919 ON_ERROR:
920
921 if (EFI_ERROR (Status)) {
922
923 Ip4CleanProtocol (IpInstance);
924
925 FreePool (IpInstance);
926 }
927
928 return Status;
929 }
930
931
932 /**
933 Destroys a child handle with a protocol installed on it.
934
935 The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
936 that was installed by CreateChild() from ChildHandle. If the removed protocol is the
937 last protocol on ChildHandle, then ChildHandle is destroyed.
938
939 @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
940 @param ChildHandle Handle of the child to destroy
941
942 @retval EFI_SUCCES The protocol was removed from ChildHandle.
943 @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
944 @retval EFI_INVALID_PARAMETER Child handle is NULL.
945 @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
946 because its services are being used.
947 @retval other The child handle was not destroyed
948
949 **/
950 EFI_STATUS
951 EFIAPI
952 Ip4ServiceBindingDestroyChild (
953 IN EFI_SERVICE_BINDING_PROTOCOL *This,
954 IN EFI_HANDLE ChildHandle
955 )
956 {
957 EFI_STATUS Status;
958 IP4_SERVICE *IpSb;
959 IP4_PROTOCOL *IpInstance;
960 EFI_IP4_PROTOCOL *Ip4;
961 EFI_TPL OldTpl;
962
963 if ((This == NULL) || (ChildHandle == NULL)) {
964 return EFI_INVALID_PARAMETER;
965 }
966
967 //
968 // Retrieve the private context data structures
969 //
970 IpSb = IP4_SERVICE_FROM_PROTOCOL (This);
971
972 Status = gBS->OpenProtocol (
973 ChildHandle,
974 &gEfiIp4ProtocolGuid,
975 (VOID **) &Ip4,
976 gIp4DriverBinding.DriverBindingHandle,
977 ChildHandle,
978 EFI_OPEN_PROTOCOL_GET_PROTOCOL
979 );
980
981 if (EFI_ERROR (Status)) {
982 return EFI_UNSUPPORTED;
983 }
984
985 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (Ip4);
986
987 if (IpInstance->Service != IpSb) {
988 return EFI_INVALID_PARAMETER;
989 }
990
991 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
992
993 //
994 // A child can be destroyed more than once. For example,
995 // Ip4DriverBindingStop will destroy all of its children.
996 // when UDP driver is being stopped, it will destroy all
997 // the IP child it opens.
998 //
999 if (IpInstance->InDestroy) {
1000 gBS->RestoreTPL (OldTpl);
1001 return EFI_SUCCESS;
1002 }
1003
1004 IpInstance->InDestroy = TRUE;
1005
1006 //
1007 // Close the Managed Network protocol.
1008 //
1009 gBS->CloseProtocol (
1010 IpSb->MnpChildHandle,
1011 &gEfiManagedNetworkProtocolGuid,
1012 gIp4DriverBinding.DriverBindingHandle,
1013 ChildHandle
1014 );
1015
1016 if (IpInstance->Interface != NULL && IpInstance->Interface->Arp != NULL) {
1017 gBS->CloseProtocol (
1018 IpInstance->Interface->ArpHandle,
1019 &gEfiArpProtocolGuid,
1020 gIp4DriverBinding.DriverBindingHandle,
1021 ChildHandle
1022 );
1023 }
1024
1025 //
1026 // Uninstall the IP4 protocol first. Many thing happens during
1027 // this:
1028 // 1. The consumer of the IP4 protocol will be stopped if it
1029 // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
1030 // stopped, IP driver's stop function will be called, and uninstall
1031 // EFI_IP4_PROTOCOL will trigger the UDP's stop function. This
1032 // makes it possible to create the network stack bottom up, and
1033 // stop it top down.
1034 // 2. the upper layer will recycle the received packet. The recycle
1035 // event's TPL is higher than this function. The recycle events
1036 // will be called back before preceeding. If any packets not recycled,
1037 // that means there is a resource leak.
1038 //
1039 gBS->RestoreTPL (OldTpl);
1040 Status = gBS->UninstallProtocolInterface (
1041 ChildHandle,
1042 &gEfiIp4ProtocolGuid,
1043 &IpInstance->Ip4Proto
1044 );
1045 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1046 if (EFI_ERROR (Status)) {
1047 IpInstance->InDestroy = FALSE;
1048 goto ON_ERROR;
1049 }
1050
1051 Status = Ip4CleanProtocol (IpInstance);
1052 if (EFI_ERROR (Status)) {
1053 gBS->InstallMultipleProtocolInterfaces (
1054 &ChildHandle,
1055 &gEfiIp4ProtocolGuid,
1056 Ip4,
1057 NULL
1058 );
1059
1060 goto ON_ERROR;
1061 }
1062
1063 RemoveEntryList (&IpInstance->Link);
1064 IpSb->NumChildren--;
1065
1066 gBS->RestoreTPL (OldTpl);
1067
1068 FreePool (IpInstance);
1069 return EFI_SUCCESS;
1070
1071 ON_ERROR:
1072 gBS->RestoreTPL (OldTpl);
1073
1074 return Status;
1075 }