]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c
0d308c05211c98867622e060eb6cbbd181031f47
[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 = NetAllocatePool (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 NetListInit (&IpSb->Children);
178
179 NetListInit (&IpSb->Interfaces);
180 IpSb->DefaultInterface = NULL;
181 IpSb->DefaultRouteTable = NULL;
182
183 Ip4InitAssembleTable (&IpSb->Assemble);
184
185 IpSb->IgmpCtrl.Igmpv1QuerySeen = 0;
186 NetListInit (&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 NetZeroMem (&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
212 //
213 // Create various resources. First create the route table, timer
214 // event and MNP child. IGMP, interface's initialization depend
215 // on the MNP child.
216 //
217 IpSb->DefaultRouteTable = Ip4CreateRouteTable ();
218
219 if (IpSb->DefaultRouteTable == NULL) {
220 Status = EFI_OUT_OF_RESOURCES;
221 goto ON_ERROR;
222 }
223
224 Status = gBS->CreateEvent (
225 EVT_NOTIFY_SIGNAL | EVT_TIMER,
226 TPL_CALLBACK,
227 Ip4TimerTicking,
228 IpSb,
229 &IpSb->Timer
230 );
231
232 if (EFI_ERROR (Status)) {
233 goto ON_ERROR;
234 }
235
236 Status = NetLibCreateServiceChild (
237 Controller,
238 ImageHandle,
239 &gEfiManagedNetworkServiceBindingProtocolGuid,
240 &IpSb->MnpChildHandle
241 );
242
243 if (EFI_ERROR (Status)) {
244 goto ON_ERROR;
245 }
246
247 Status = gBS->OpenProtocol (
248 IpSb->MnpChildHandle,
249 &gEfiManagedNetworkProtocolGuid,
250 (VOID **) &IpSb->Mnp,
251 ImageHandle,
252 Controller,
253 EFI_OPEN_PROTOCOL_BY_DRIVER
254 );
255
256 if (EFI_ERROR (Status)) {
257 goto ON_ERROR;
258 }
259
260 Status = Ip4ServiceConfigMnp (IpSb, TRUE);
261
262 if (EFI_ERROR (Status)) {
263 goto ON_ERROR;
264 }
265
266 Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &IpSb->SnpMode);
267
268 if (EFI_ERROR (Status)) {
269 goto ON_ERROR;
270 }
271
272 Status = Ip4InitIgmp (IpSb);
273
274 if (EFI_ERROR (Status)) {
275 goto ON_ERROR;
276 }
277
278 IpSb->DefaultInterface = Ip4CreateInterface (IpSb->Mnp, Controller, ImageHandle);
279
280 if (IpSb->DefaultInterface == NULL) {
281 Status = EFI_OUT_OF_RESOURCES;
282 goto ON_ERROR;
283 }
284
285 NetListInsertHead (&IpSb->Interfaces, &IpSb->DefaultInterface->Link);
286
287 IpSb->MacString = NULL;
288
289 *Service = IpSb;
290 return EFI_SUCCESS;
291
292 ON_ERROR:
293 Ip4CleanService (IpSb);
294 NetFreePool (IpSb);
295
296 return Status;
297 }
298
299
300 /**
301 Clean up a IP4 service binding instance. It will release all
302 the resource allocated by the instance. The instance may be
303 partly initialized, or partly destoried. If a resource is
304 destoried, it is marked as that in case the destory failed and
305 being called again later.
306
307 @param IpSb The IP4 serviceing binding instance to clean up
308
309 @retval EFI_SUCCESS The resource used by the instance are cleaned up
310 @retval Others Failed to clean up some of the resources.
311
312 **/
313 EFI_STATUS
314 Ip4CleanService (
315 IN IP4_SERVICE *IpSb
316 )
317 {
318 EFI_STATUS Status;
319
320 if (IpSb->DefaultInterface != NULL) {
321 Status = Ip4FreeInterface (IpSb->DefaultInterface, NULL);
322
323 if (EFI_ERROR (Status)) {
324 return Status;
325 }
326
327 IpSb->DefaultInterface = NULL;
328 }
329
330 if (IpSb->DefaultRouteTable != NULL) {
331 Ip4FreeRouteTable (IpSb->DefaultRouteTable);
332 IpSb->DefaultRouteTable = NULL;
333 }
334
335 Ip4CleanAssembleTable (&IpSb->Assemble);
336
337 if (IpSb->MnpChildHandle != NULL) {
338 if (IpSb->Mnp) {
339 gBS->CloseProtocol (
340 IpSb->MnpChildHandle,
341 &gEfiManagedNetworkProtocolGuid,
342 IpSb->Image,
343 IpSb->Controller
344 );
345
346 IpSb->Mnp = NULL;
347 }
348
349 NetLibDestroyServiceChild (
350 IpSb->Controller,
351 IpSb->Image,
352 &gEfiManagedNetworkServiceBindingProtocolGuid,
353 IpSb->MnpChildHandle
354 );
355
356 IpSb->MnpChildHandle = NULL;
357 }
358
359 if (IpSb->Timer != NULL) {
360 gBS->SetTimer (IpSb->Timer, TimerCancel, 0);
361 gBS->CloseEvent (IpSb->Timer);
362
363 IpSb->Timer = NULL;
364 }
365
366 if (IpSb->Ip4Config != NULL) {
367 IpSb->Ip4Config->Stop (IpSb->Ip4Config);
368
369 gBS->CloseProtocol (
370 IpSb->Controller,
371 &gEfiIp4ConfigProtocolGuid,
372 IpSb->Image,
373 IpSb->Controller
374 );
375
376 gBS->CloseEvent (IpSb->DoneEvent);
377 gBS->CloseEvent (IpSb->ReconfigEvent);
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 NetFreePool (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
514 //
515 // IP4 driver opens the MNP child, ARP children or the IP4_CONFIG protocol
516 // by driver. So the ControllerHandle may be the MNP child handle, ARP child
517 // handle, or the NIC (UNDI) handle because IP4_CONFIG protocol is installed
518 // in the NIC handle.
519 //
520 //
521 // First, check whether it is the IP4_CONFIG protocol being uninstalled.
522 // IP4_CONFIG protocol is installed on the NIC handle. It isn't necessary
523 // to clean up the default configuration if IP4_CONFIG is being stopped.
524 //
525 Status = gBS->OpenProtocol (
526 ControllerHandle,
527 &gEfiIp4ConfigProtocolGuid,
528 NULL,
529 This->DriverBindingHandle,
530 ControllerHandle,
531 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
532 );
533
534 if (Status == EFI_SUCCESS) {
535 //
536 // Retrieve the IP4 service binding protocol. If failed, it is
537 // likely that Ip4 ServiceBinding is uninstalled already. In this
538 // case, return immediately.
539 //
540 Status = gBS->OpenProtocol (
541 ControllerHandle,
542 &gEfiIp4ServiceBindingProtocolGuid,
543 (VOID **) &ServiceBinding,
544 This->DriverBindingHandle,
545 ControllerHandle,
546 EFI_OPEN_PROTOCOL_GET_PROTOCOL
547 );
548
549 if (EFI_ERROR (Status)) {
550 return EFI_SUCCESS;
551 }
552
553 IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
554
555 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
556
557 if (IpSb->Ip4Config && (IpSb->State != IP4_SERVICE_DESTORY)) {
558
559 IpSb->Ip4Config->Stop (IpSb->Ip4Config);
560
561 Status = gBS->CloseProtocol (
562 ControllerHandle,
563 &gEfiIp4ConfigProtocolGuid,
564 IpSb->Image,
565 ControllerHandle
566 );
567
568 if (EFI_ERROR (Status)) {
569 NET_RESTORE_TPL (OldTpl);
570 return Status;
571 }
572
573 //
574 // If the auto configure hasn't complete, mark it as not started.
575 //
576 if (IpSb->State == IP4_SERVICE_STARTED) {
577 IpSb->State = IP4_SERVICE_UNSTARTED;
578 }
579
580 IpSb->Ip4Config = NULL;
581 gBS->CloseEvent (IpSb->DoneEvent);
582 gBS->CloseEvent (IpSb->ReconfigEvent);
583 }
584
585 NET_RESTORE_TPL (OldTpl);
586 return EFI_SUCCESS;
587 }
588
589 //
590 // Either MNP or ARP protocol is being uninstalled. The controller
591 // handle is either the MNP child or ARP child. But, the IP4's
592 // service binding is installed on the NIC handle. So, need to open
593 // the protocol info to find the NIC handle.
594 //
595 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
596
597 if (NicHandle == NULL) {
598 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid);
599 }
600
601 if (NicHandle == NULL) {
602 return EFI_SUCCESS;
603 }
604
605 //
606 // Retrieve the IP4 service binding protocol
607 //
608 Status = gBS->OpenProtocol (
609 NicHandle,
610 &gEfiIp4ServiceBindingProtocolGuid,
611 (VOID **) &ServiceBinding,
612 This->DriverBindingHandle,
613 NicHandle,
614 EFI_OPEN_PROTOCOL_GET_PROTOCOL
615 );
616
617 if (EFI_ERROR (Status)) {
618 return EFI_DEVICE_ERROR;
619 }
620
621 IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
622
623 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
624
625 if (IpSb->InDestory) {
626 NET_RESTORE_TPL (OldTpl);
627 return EFI_SUCCESS;
628 }
629
630 IpSb->InDestory = TRUE;
631
632 State = IpSb->State;
633 IpSb->State = IP4_SERVICE_DESTORY;
634
635 //
636 // Destory all the children first. If not all children are destoried,
637 // the IP driver can operate correctly, so restore it state. Don't
638 // use NET_LIST_FOR_EACH_SAFE here, because it will cache the next
639 // pointer, which may point to the child that has already been destoried.
640 // For example, if there are two child in the list, the first is UDP
641 // listen child, the send is the MTFTP's child. When Udp child is
642 // destoried, it will destory the MTFTP's child. Then Next point to
643 // a invalid child.
644 //
645 while (!NetListIsEmpty (&IpSb->Children)) {
646 IpInstance = NET_LIST_HEAD (&IpSb->Children, IP4_PROTOCOL, Link);
647 Ip4ServiceBindingDestroyChild (ServiceBinding, IpInstance->Handle);
648 }
649
650 if (IpSb->NumChildren != 0) {
651 IpSb->State = State;
652 Status = EFI_DEVICE_ERROR;
653 goto ON_ERROR;
654 }
655
656 //
657 // Clear the variable data.
658 //
659 Ip4ClearVariableData (IpSb);
660
661 //
662 // OK, clean other resources then uninstall the service binding protocol.
663 //
664 Status = Ip4CleanService (IpSb);
665
666 if (EFI_ERROR (Status)) {
667 goto ON_ERROR;
668 }
669
670 Status = gBS->UninstallProtocolInterface (
671 NicHandle,
672 &gEfiIp4ServiceBindingProtocolGuid,
673 ServiceBinding
674 );
675
676 if (EFI_ERROR (Status)) {
677 goto ON_ERROR;
678 }
679
680 NET_RESTORE_TPL (OldTpl);
681 NetFreePool (IpSb);
682 return EFI_SUCCESS;
683
684 ON_ERROR:
685 IpSb->InDestory = FALSE;
686 NET_RESTORE_TPL (OldTpl);
687 return Status;
688 }
689
690
691 /**
692 Creates a child handle with a set of I/O services.
693
694 @param This Protocol instance pointer.
695 @param ChildHandle Pointer to the handle of the child to create. If
696 it is NULL, then a new handle is created. If it
697 is not NULL, then the I/O services are added to
698 the existing child handle.
699
700 @retval EFI_SUCCES The child handle was created with the I/O services
701 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
702 the child
703 @retval other The child handle was not created
704
705 **/
706 EFI_STATUS
707 EFIAPI
708 Ip4ServiceBindingCreateChild (
709 IN EFI_SERVICE_BINDING_PROTOCOL *This,
710 IN EFI_HANDLE *ChildHandle
711 )
712 {
713 IP4_SERVICE *IpSb;
714 IP4_PROTOCOL *IpInstance;
715 EFI_TPL OldTpl;
716 EFI_STATUS Status;
717 VOID *Mnp;
718
719 if ((This == NULL) || (ChildHandle == NULL)) {
720 return EFI_INVALID_PARAMETER;
721 }
722
723 IpSb = IP4_SERVICE_FROM_PROTOCOL (This);
724 IpInstance = NetAllocatePool (sizeof (IP4_PROTOCOL));
725
726 if (IpInstance == NULL) {
727 return EFI_OUT_OF_RESOURCES;
728 }
729
730 Ip4InitProtocol (IpSb, IpInstance);
731
732 //
733 // Install Ip4 onto ChildHandle
734 //
735 Status = gBS->InstallMultipleProtocolInterfaces (
736 ChildHandle,
737 &gEfiIp4ProtocolGuid,
738 &IpInstance->Ip4Proto,
739 NULL
740 );
741
742 if (EFI_ERROR (Status)) {
743 goto ON_ERROR;
744 }
745
746 IpInstance->Handle = *ChildHandle;
747
748 //
749 // Open the Managed Network protocol BY_CHILD.
750 //
751 Status = gBS->OpenProtocol (
752 IpSb->MnpChildHandle,
753 &gEfiManagedNetworkProtocolGuid,
754 (VOID **) &Mnp,
755 gIp4DriverBinding.DriverBindingHandle,
756 IpInstance->Handle,
757 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
758 );
759 if (EFI_ERROR (Status)) {
760 gBS->UninstallMultipleProtocolInterfaces (
761 ChildHandle,
762 &gEfiIp4ProtocolGuid,
763 &IpInstance->Ip4Proto,
764 NULL
765 );
766
767 goto ON_ERROR;
768 }
769
770 //
771 // Insert it into the service binding instance.
772 //
773 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
774
775 NetListInsertTail (&IpSb->Children, &IpInstance->Link);
776 IpSb->NumChildren++;
777
778 NET_RESTORE_TPL (OldTpl);
779
780 ON_ERROR:
781
782 if (EFI_ERROR (Status)) {
783
784 Ip4CleanProtocol (IpInstance);
785
786 NetFreePool (IpInstance);
787 }
788
789 return Status;
790 }
791
792
793 /**
794 Destroys a child handle with a set of I/O services.
795
796 @param This Protocol instance pointer.
797 @param ChildHandle Handle of the child to destroy
798
799 @retval EFI_SUCCES The I/O services were removed from the child
800 handle
801 @retval EFI_UNSUPPORTED The child handle does not support the I/O services
802 that are being removed
803 @retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
804 @retval EFI_ACCESS_DENIED The child handle could not be destroyed because
805 its I/O services are being used.
806 @retval other The child handle was not destroyed
807
808 **/
809 EFI_STATUS
810 EFIAPI
811 Ip4ServiceBindingDestroyChild (
812 IN EFI_SERVICE_BINDING_PROTOCOL *This,
813 IN EFI_HANDLE ChildHandle
814 )
815 {
816 EFI_STATUS Status;
817 IP4_SERVICE *IpSb;
818 IP4_PROTOCOL *IpInstance;
819 EFI_IP4_PROTOCOL *Ip4;
820 EFI_TPL OldTpl;
821 INTN State;
822
823 if ((This == NULL) || (ChildHandle == NULL)) {
824 return EFI_INVALID_PARAMETER;
825 }
826
827 //
828 // Retrieve the private context data structures
829 //
830 IpSb = IP4_SERVICE_FROM_PROTOCOL (This);
831
832 Status = gBS->OpenProtocol (
833 ChildHandle,
834 &gEfiIp4ProtocolGuid,
835 (VOID **) &Ip4,
836 gIp4DriverBinding.DriverBindingHandle,
837 ChildHandle,
838 EFI_OPEN_PROTOCOL_GET_PROTOCOL
839 );
840
841 if (EFI_ERROR (Status)) {
842 return EFI_UNSUPPORTED;
843 }
844
845 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (Ip4);
846
847 if (IpInstance->Service != IpSb) {
848 return EFI_INVALID_PARAMETER;
849 }
850
851 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
852
853 //
854 // A child can be destoried more than once. For example,
855 // Ip4DriverBindingStop will destory all of its children.
856 // when UDP driver is being stopped, it will destory all
857 // the IP child it opens.
858 //
859 if (IpInstance->State == IP4_STATE_DESTORY) {
860 NET_RESTORE_TPL (OldTpl);
861 return EFI_SUCCESS;
862 }
863
864 State = IpInstance->State;
865 IpInstance->State = IP4_STATE_DESTORY;
866
867 //
868 // Close the Managed Network protocol.
869 //
870 gBS->CloseProtocol (
871 IpSb->MnpChildHandle,
872 &gEfiManagedNetworkProtocolGuid,
873 gIp4DriverBinding.DriverBindingHandle,
874 ChildHandle
875 );
876
877 //
878 // Uninstall the IP4 protocol first. Many thing happens during
879 // this:
880 // 1. The consumer of the IP4 protocol will be stopped if it
881 // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
882 // stopped, IP driver's stop function will be called, and uninstall
883 // EFI_IP4_PROTOCOL will trigger the UDP's stop function. This
884 // makes it possible to create the network stack bottom up, and
885 // stop it top down.
886 // 2. the upper layer will recycle the received packet. The recycle
887 // event's TPL is higher than this function. The recycle events
888 // will be called back before preceeding. If any packets not recycled,
889 // that means there is a resource leak.
890 //
891 Status = gBS->UninstallProtocolInterface (
892 ChildHandle,
893 &gEfiIp4ProtocolGuid,
894 &IpInstance->Ip4Proto
895 );
896
897 if (EFI_ERROR (Status)) {
898 goto ON_ERROR;
899 }
900
901 Status = Ip4CleanProtocol (IpInstance);
902
903 Ip4SetVariableData (IpSb);
904
905 if (EFI_ERROR (Status)) {
906 gBS->InstallMultipleProtocolInterfaces (
907 &ChildHandle,
908 &gEfiIp4ProtocolGuid,
909 Ip4,
910 NULL
911 );
912
913 goto ON_ERROR;
914 }
915
916 NetListRemoveEntry (&IpInstance->Link);
917 IpSb->NumChildren--;
918
919 NET_RESTORE_TPL (OldTpl);
920
921 NetFreePool (IpInstance);
922 return EFI_SUCCESS;
923
924 ON_ERROR:
925 IpInstance->State = State;
926 NET_RESTORE_TPL (OldTpl);
927
928 return Status;
929 }