VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/NetworkPkg/Ip4Dxe/Ip4Driver.c

Last change on this file was 105670, checked in by vboxsync, 5 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette