]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c
MdeModulePkg: Clean up source files
[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 - 2018, 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->UninstallProtocolInterface (
668 ControllerHandle,
669 &gEfiIp4ServiceBindingProtocolGuid,
670 &IpSb->ServiceBinding
671 );
672
673 FREE_SERVICE:
674 Ip4CleanService (IpSb);
675 FreePool (IpSb);
676 return Status;
677 }
678
679
680 /**
681 Stop this driver on ControllerHandle. This service is called by the
682 EFI boot service DisconnectController(). In order to
683 make drivers as small as possible, there are a few calling
684 restrictions for this service. DisconnectController()
685 must follow these calling restrictions. If any other agent wishes
686 to call Stop() it must also follow these calling restrictions.
687
688 @param[in] This Protocol instance pointer.
689 @param[in] ControllerHandle Handle of device to stop driver on
690 @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number
691 of children is zero stop the entire bus driver.
692 @param[in] ChildHandleBuffer List of Child Handles to Stop.
693
694 @retval EFI_SUCCESS This driver is removed ControllerHandle
695 @retval other This driver was not removed from this device
696
697 **/
698 EFI_STATUS
699 EFIAPI
700 Ip4DriverBindingStop (
701 IN EFI_DRIVER_BINDING_PROTOCOL *This,
702 IN EFI_HANDLE ControllerHandle,
703 IN UINTN NumberOfChildren,
704 IN EFI_HANDLE *ChildHandleBuffer
705 )
706 {
707 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
708 IP4_SERVICE *IpSb;
709 EFI_HANDLE NicHandle;
710 EFI_STATUS Status;
711 INTN State;
712 LIST_ENTRY *List;
713 IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context;
714 IP4_INTERFACE *IpIf;
715 IP4_ROUTE_TABLE *RouteTable;
716
717 BOOLEAN IsDhcp4;
718
719 IsDhcp4 = FALSE;
720
721 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
722 if (NicHandle == NULL) {
723 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid);
724 if (NicHandle == NULL) {
725 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);
726 if (NicHandle != NULL) {
727 IsDhcp4 = TRUE;
728 } else {
729 return EFI_SUCCESS;
730 }
731 }
732 }
733
734 Status = gBS->OpenProtocol (
735 NicHandle,
736 &gEfiIp4ServiceBindingProtocolGuid,
737 (VOID **) &ServiceBinding,
738 This->DriverBindingHandle,
739 NicHandle,
740 EFI_OPEN_PROTOCOL_GET_PROTOCOL
741 );
742 if (EFI_ERROR (Status)) {
743 return EFI_DEVICE_ERROR;
744 }
745
746 IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
747
748 if (IsDhcp4) {
749 Status = Ip4Config2DestroyDhcp4 (&IpSb->Ip4Config2Instance);
750 gBS->CloseEvent (IpSb->Ip4Config2Instance.Dhcp4Event);
751 IpSb->Ip4Config2Instance.Dhcp4Event = NULL;
752 } else if (NumberOfChildren != 0) {
753 List = &IpSb->Children;
754 Context.ServiceBinding = ServiceBinding;
755 Context.NumberOfChildren = NumberOfChildren;
756 Context.ChildHandleBuffer = ChildHandleBuffer;
757 Status = NetDestroyLinkList (
758 List,
759 Ip4DestroyChildEntryInHandleBuffer,
760 &Context,
761 NULL
762 );
763 } else if (IpSb->DefaultInterface->ArpHandle == ControllerHandle) {
764
765 //
766 // The ARP protocol for the default interface is being uninstalled and all
767 // its IP child handles should have been destroyed before. So, release the
768 // default interface and route table, create a new one and mark it as not started.
769 //
770 Ip4CancelReceive (IpSb->DefaultInterface);
771 Ip4FreeInterface (IpSb->DefaultInterface, NULL);
772 Ip4FreeRouteTable (IpSb->DefaultRouteTable);
773
774 IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
775 if (IpIf == NULL) {
776 goto ON_ERROR;
777 }
778 RouteTable = Ip4CreateRouteTable ();
779 if (RouteTable == NULL) {
780 Ip4FreeInterface (IpIf, NULL);
781 goto ON_ERROR;;
782 }
783
784 IpSb->DefaultInterface = IpIf;
785 InsertHeadList (&IpSb->Interfaces, &IpIf->Link);
786 IpSb->DefaultRouteTable = RouteTable;
787 Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);
788
789 IpSb->State = IP4_SERVICE_UNSTARTED;
790
791 } else if (IsListEmpty (&IpSb->Children)) {
792 State = IpSb->State;
793 //
794 // OK, clean other resources then uninstall the service binding protocol.
795 //
796 Status = Ip4CleanService (IpSb);
797 if (EFI_ERROR (Status)) {
798 IpSb->State = State;
799 goto ON_ERROR;
800 }
801
802 gBS->UninstallMultipleProtocolInterfaces (
803 NicHandle,
804 &gEfiIp4ServiceBindingProtocolGuid,
805 ServiceBinding,
806 &gEfiIp4Config2ProtocolGuid,
807 &IpSb->Ip4Config2Instance.Ip4Config2,
808 NULL
809 );
810
811 if (gIp4ControllerNameTable != NULL) {
812 FreeUnicodeStringTable (gIp4ControllerNameTable);
813 gIp4ControllerNameTable = NULL;
814 }
815 FreePool (IpSb);
816 }
817
818 ON_ERROR:
819 return Status;
820 }
821
822
823 /**
824 Creates a child handle and installs a protocol.
825
826 The CreateChild() function installs a protocol on ChildHandle.
827 If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
828 If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
829
830 @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
831 @param ChildHandle Pointer to the handle of the child to create. If it is NULL,
832 then a new handle is created. If it is a pointer to an existing UEFI handle,
833 then the protocol is added to the existing UEFI handle.
834
835 @retval EFI_SUCCES The protocol was added to ChildHandle.
836 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
837 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
838 the child
839 @retval other The child handle was not created
840
841 **/
842 EFI_STATUS
843 EFIAPI
844 Ip4ServiceBindingCreateChild (
845 IN EFI_SERVICE_BINDING_PROTOCOL *This,
846 IN OUT EFI_HANDLE *ChildHandle
847 )
848 {
849 IP4_SERVICE *IpSb;
850 IP4_PROTOCOL *IpInstance;
851 EFI_TPL OldTpl;
852 EFI_STATUS Status;
853 VOID *Mnp;
854
855 if ((This == NULL) || (ChildHandle == NULL)) {
856 return EFI_INVALID_PARAMETER;
857 }
858
859 IpSb = IP4_SERVICE_FROM_PROTOCOL (This);
860 IpInstance = AllocatePool (sizeof (IP4_PROTOCOL));
861
862 if (IpInstance == NULL) {
863 return EFI_OUT_OF_RESOURCES;
864 }
865
866 Ip4InitProtocol (IpSb, IpInstance);
867
868 //
869 // Install Ip4 onto ChildHandle
870 //
871 Status = gBS->InstallMultipleProtocolInterfaces (
872 ChildHandle,
873 &gEfiIp4ProtocolGuid,
874 &IpInstance->Ip4Proto,
875 NULL
876 );
877
878 if (EFI_ERROR (Status)) {
879 goto ON_ERROR;
880 }
881
882 IpInstance->Handle = *ChildHandle;
883
884 //
885 // Open the Managed Network protocol BY_CHILD.
886 //
887 Status = gBS->OpenProtocol (
888 IpSb->MnpChildHandle,
889 &gEfiManagedNetworkProtocolGuid,
890 (VOID **) &Mnp,
891 gIp4DriverBinding.DriverBindingHandle,
892 IpInstance->Handle,
893 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
894 );
895 if (EFI_ERROR (Status)) {
896 gBS->UninstallMultipleProtocolInterfaces (
897 ChildHandle,
898 &gEfiIp4ProtocolGuid,
899 &IpInstance->Ip4Proto,
900 NULL
901 );
902
903 goto ON_ERROR;
904 }
905
906 //
907 // Insert it into the service binding instance.
908 //
909 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
910
911 InsertTailList (&IpSb->Children, &IpInstance->Link);
912 IpSb->NumChildren++;
913
914 gBS->RestoreTPL (OldTpl);
915
916 ON_ERROR:
917
918 if (EFI_ERROR (Status)) {
919
920 Ip4CleanProtocol (IpInstance);
921
922 FreePool (IpInstance);
923 }
924
925 return Status;
926 }
927
928
929 /**
930 Destroys a child handle with a protocol installed on it.
931
932 The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
933 that was installed by CreateChild() from ChildHandle. If the removed protocol is the
934 last protocol on ChildHandle, then ChildHandle is destroyed.
935
936 @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
937 @param ChildHandle Handle of the child to destroy
938
939 @retval EFI_SUCCES The protocol was removed from ChildHandle.
940 @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
941 @retval EFI_INVALID_PARAMETER Child handle is NULL.
942 @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
943 because its services are being used.
944 @retval other The child handle was not destroyed
945
946 **/
947 EFI_STATUS
948 EFIAPI
949 Ip4ServiceBindingDestroyChild (
950 IN EFI_SERVICE_BINDING_PROTOCOL *This,
951 IN EFI_HANDLE ChildHandle
952 )
953 {
954 EFI_STATUS Status;
955 IP4_SERVICE *IpSb;
956 IP4_PROTOCOL *IpInstance;
957 EFI_IP4_PROTOCOL *Ip4;
958 EFI_TPL OldTpl;
959
960 if ((This == NULL) || (ChildHandle == NULL)) {
961 return EFI_INVALID_PARAMETER;
962 }
963
964 //
965 // Retrieve the private context data structures
966 //
967 IpSb = IP4_SERVICE_FROM_PROTOCOL (This);
968
969 Status = gBS->OpenProtocol (
970 ChildHandle,
971 &gEfiIp4ProtocolGuid,
972 (VOID **) &Ip4,
973 gIp4DriverBinding.DriverBindingHandle,
974 ChildHandle,
975 EFI_OPEN_PROTOCOL_GET_PROTOCOL
976 );
977
978 if (EFI_ERROR (Status)) {
979 return EFI_UNSUPPORTED;
980 }
981
982 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (Ip4);
983
984 if (IpInstance->Service != IpSb) {
985 return EFI_INVALID_PARAMETER;
986 }
987
988 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
989
990 //
991 // A child can be destroyed more than once. For example,
992 // Ip4DriverBindingStop will destroy all of its children.
993 // when UDP driver is being stopped, it will destroy all
994 // the IP child it opens.
995 //
996 if (IpInstance->InDestroy) {
997 gBS->RestoreTPL (OldTpl);
998 return EFI_SUCCESS;
999 }
1000
1001 IpInstance->InDestroy = TRUE;
1002
1003 //
1004 // Close the Managed Network protocol.
1005 //
1006 gBS->CloseProtocol (
1007 IpSb->MnpChildHandle,
1008 &gEfiManagedNetworkProtocolGuid,
1009 gIp4DriverBinding.DriverBindingHandle,
1010 ChildHandle
1011 );
1012
1013 if (IpInstance->Interface != NULL && IpInstance->Interface->Arp != NULL) {
1014 gBS->CloseProtocol (
1015 IpInstance->Interface->ArpHandle,
1016 &gEfiArpProtocolGuid,
1017 gIp4DriverBinding.DriverBindingHandle,
1018 ChildHandle
1019 );
1020 }
1021
1022 //
1023 // Uninstall the IP4 protocol first. Many thing happens during
1024 // this:
1025 // 1. The consumer of the IP4 protocol will be stopped if it
1026 // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
1027 // stopped, IP driver's stop function will be called, and uninstall
1028 // EFI_IP4_PROTOCOL will trigger the UDP's stop function. This
1029 // makes it possible to create the network stack bottom up, and
1030 // stop it top down.
1031 // 2. the upper layer will recycle the received packet. The recycle
1032 // event's TPL is higher than this function. The recycle events
1033 // will be called back before preceeding. If any packets not recycled,
1034 // that means there is a resource leak.
1035 //
1036 gBS->RestoreTPL (OldTpl);
1037 Status = gBS->UninstallProtocolInterface (
1038 ChildHandle,
1039 &gEfiIp4ProtocolGuid,
1040 &IpInstance->Ip4Proto
1041 );
1042 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1043 if (EFI_ERROR (Status)) {
1044 IpInstance->InDestroy = FALSE;
1045 goto ON_ERROR;
1046 }
1047
1048 Status = Ip4CleanProtocol (IpInstance);
1049 if (EFI_ERROR (Status)) {
1050 gBS->InstallMultipleProtocolInterfaces (
1051 &ChildHandle,
1052 &gEfiIp4ProtocolGuid,
1053 Ip4,
1054 NULL
1055 );
1056
1057 goto ON_ERROR;
1058 }
1059
1060 RemoveEntryList (&IpInstance->Link);
1061 IpSb->NumChildren--;
1062
1063 gBS->RestoreTPL (OldTpl);
1064
1065 FreePool (IpInstance);
1066 return EFI_SUCCESS;
1067
1068 ON_ERROR:
1069 gBS->RestoreTPL (OldTpl);
1070
1071 return Status;
1072 }