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