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