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