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