]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Driver.c
1. Add DPC protocol and DpcLib library in MdeModulePkg.
[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 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 NET_TPL_TIMER,
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 NetListInsertHead (&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 NetFreePool (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 NetFreePool (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
516 //
517 // IP4 driver opens the MNP child, ARP children or the IP4_CONFIG protocol
518 // by driver. So the ControllerHandle may be the MNP child handle, ARP child
519 // handle, or the NIC (UNDI) handle because IP4_CONFIG protocol is installed
520 // in the NIC handle.
521 //
522 //
523 // First, check whether it is the IP4_CONFIG protocol being uninstalled.
524 // IP4_CONFIG protocol is installed on the NIC handle. It isn't necessary
525 // to clean up the default configuration if IP4_CONFIG is being stopped.
526 //
527 Status = gBS->OpenProtocol (
528 ControllerHandle,
529 &gEfiIp4ConfigProtocolGuid,
530 NULL,
531 This->DriverBindingHandle,
532 ControllerHandle,
533 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
534 );
535
536 if (Status == EFI_SUCCESS) {
537 //
538 // Retrieve the IP4 service binding protocol. If failed, it is
539 // likely that Ip4 ServiceBinding is uninstalled already. In this
540 // case, return immediately.
541 //
542 Status = gBS->OpenProtocol (
543 ControllerHandle,
544 &gEfiIp4ServiceBindingProtocolGuid,
545 (VOID **) &ServiceBinding,
546 This->DriverBindingHandle,
547 ControllerHandle,
548 EFI_OPEN_PROTOCOL_GET_PROTOCOL
549 );
550
551 if (EFI_ERROR (Status)) {
552 return EFI_SUCCESS;
553 }
554
555 IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
556
557 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
558
559 if (IpSb->Ip4Config && (IpSb->State != IP4_SERVICE_DESTORY)) {
560
561 IpSb->Ip4Config->Stop (IpSb->Ip4Config);
562
563 Status = gBS->CloseProtocol (
564 ControllerHandle,
565 &gEfiIp4ConfigProtocolGuid,
566 IpSb->Image,
567 ControllerHandle
568 );
569
570 if (EFI_ERROR (Status)) {
571 NET_RESTORE_TPL (OldTpl);
572 return Status;
573 }
574
575 //
576 // If the auto configure hasn't complete, mark it as not started.
577 //
578 if (IpSb->State == IP4_SERVICE_STARTED) {
579 IpSb->State = IP4_SERVICE_UNSTARTED;
580 }
581
582 IpSb->Ip4Config = NULL;
583 gBS->CloseEvent (IpSb->DoneEvent);
584 gBS->CloseEvent (IpSb->ReconfigEvent);
585 }
586
587 NET_RESTORE_TPL (OldTpl);
588 return EFI_SUCCESS;
589 }
590
591 //
592 // Either MNP or ARP protocol is being uninstalled. The controller
593 // handle is either the MNP child or ARP child. But, the IP4's
594 // service binding is installed on the NIC handle. So, need to open
595 // the protocol info to find the NIC handle.
596 //
597 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
598
599 if (NicHandle == NULL) {
600 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid);
601 }
602
603 if (NicHandle == NULL) {
604 return EFI_SUCCESS;
605 }
606
607 //
608 // Retrieve the IP4 service binding protocol
609 //
610 Status = gBS->OpenProtocol (
611 NicHandle,
612 &gEfiIp4ServiceBindingProtocolGuid,
613 (VOID **) &ServiceBinding,
614 This->DriverBindingHandle,
615 NicHandle,
616 EFI_OPEN_PROTOCOL_GET_PROTOCOL
617 );
618
619 if (EFI_ERROR (Status)) {
620 return EFI_DEVICE_ERROR;
621 }
622
623 IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
624
625 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
626
627 if (IpSb->InDestory) {
628 NET_RESTORE_TPL (OldTpl);
629 return EFI_SUCCESS;
630 }
631
632 IpSb->InDestory = TRUE;
633
634 State = IpSb->State;
635 IpSb->State = IP4_SERVICE_DESTORY;
636
637 //
638 // Destory all the children first. If not all children are destoried,
639 // the IP driver can operate correctly, so restore it state. Don't
640 // use NET_LIST_FOR_EACH_SAFE here, because it will cache the next
641 // pointer, which may point to the child that has already been destoried.
642 // For example, if there are two child in the list, the first is UDP
643 // listen child, the send is the MTFTP's child. When Udp child is
644 // destoried, it will destory the MTFTP's child. Then Next point to
645 // a invalid child.
646 //
647 while (!NetListIsEmpty (&IpSb->Children)) {
648 IpInstance = NET_LIST_HEAD (&IpSb->Children, IP4_PROTOCOL, Link);
649 Ip4ServiceBindingDestroyChild (ServiceBinding, IpInstance->Handle);
650 }
651
652 if (IpSb->NumChildren != 0) {
653 IpSb->State = State;
654 Status = EFI_DEVICE_ERROR;
655 goto ON_ERROR;
656 }
657
658 //
659 // Clear the variable data.
660 //
661 Ip4ClearVariableData (IpSb);
662
663 //
664 // OK, clean other resources then uninstall the service binding protocol.
665 //
666 Status = Ip4CleanService (IpSb);
667
668 if (EFI_ERROR (Status)) {
669 goto ON_ERROR;
670 }
671
672 Status = gBS->UninstallProtocolInterface (
673 NicHandle,
674 &gEfiIp4ServiceBindingProtocolGuid,
675 ServiceBinding
676 );
677
678 if (EFI_ERROR (Status)) {
679 goto ON_ERROR;
680 }
681
682 NET_RESTORE_TPL (OldTpl);
683 NetFreePool (IpSb);
684 return EFI_SUCCESS;
685
686 ON_ERROR:
687 IpSb->InDestory = FALSE;
688 NET_RESTORE_TPL (OldTpl);
689 return Status;
690 }
691
692
693 /**
694 Creates a child handle with a set of I/O services.
695
696 @param This Protocol instance pointer.
697 @param ChildHandle Pointer to the handle of the child to create. If
698 it is NULL, then a new handle is created. If it
699 is not NULL, then the I/O services are added to
700 the existing child handle.
701
702 @retval EFI_SUCCES The child handle was created with the I/O services
703 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
704 the child
705 @retval other The child handle was not created
706
707 **/
708 EFI_STATUS
709 EFIAPI
710 Ip4ServiceBindingCreateChild (
711 IN EFI_SERVICE_BINDING_PROTOCOL *This,
712 IN EFI_HANDLE *ChildHandle
713 )
714 {
715 IP4_SERVICE *IpSb;
716 IP4_PROTOCOL *IpInstance;
717 EFI_TPL OldTpl;
718 EFI_STATUS Status;
719 VOID *Mnp;
720
721 if ((This == NULL) || (ChildHandle == NULL)) {
722 return EFI_INVALID_PARAMETER;
723 }
724
725 IpSb = IP4_SERVICE_FROM_PROTOCOL (This);
726 IpInstance = NetAllocatePool (sizeof (IP4_PROTOCOL));
727
728 if (IpInstance == NULL) {
729 return EFI_OUT_OF_RESOURCES;
730 }
731
732 Ip4InitProtocol (IpSb, IpInstance);
733
734 //
735 // Install Ip4 onto ChildHandle
736 //
737 Status = gBS->InstallMultipleProtocolInterfaces (
738 ChildHandle,
739 &gEfiIp4ProtocolGuid,
740 &IpInstance->Ip4Proto,
741 NULL
742 );
743
744 if (EFI_ERROR (Status)) {
745 goto ON_ERROR;
746 }
747
748 IpInstance->Handle = *ChildHandle;
749
750 //
751 // Open the Managed Network protocol BY_CHILD.
752 //
753 Status = gBS->OpenProtocol (
754 IpSb->MnpChildHandle,
755 &gEfiManagedNetworkProtocolGuid,
756 (VOID **) &Mnp,
757 gIp4DriverBinding.DriverBindingHandle,
758 IpInstance->Handle,
759 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
760 );
761 if (EFI_ERROR (Status)) {
762 gBS->UninstallMultipleProtocolInterfaces (
763 ChildHandle,
764 &gEfiIp4ProtocolGuid,
765 &IpInstance->Ip4Proto,
766 NULL
767 );
768
769 goto ON_ERROR;
770 }
771
772 //
773 // Insert it into the service binding instance.
774 //
775 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
776
777 NetListInsertTail (&IpSb->Children, &IpInstance->Link);
778 IpSb->NumChildren++;
779
780 NET_RESTORE_TPL (OldTpl);
781
782 ON_ERROR:
783
784 if (EFI_ERROR (Status)) {
785
786 Ip4CleanProtocol (IpInstance);
787
788 NetFreePool (IpInstance);
789 }
790
791 return Status;
792 }
793
794
795 /**
796 Destroys a child handle with a set of I/O services.
797
798 @param This Protocol instance pointer.
799 @param ChildHandle Handle of the child to destroy
800
801 @retval EFI_SUCCES The I/O services were removed from the child
802 handle
803 @retval EFI_UNSUPPORTED The child handle does not support the I/O services
804 that are being removed
805 @retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
806 @retval EFI_ACCESS_DENIED The child handle could not be destroyed because
807 its I/O services are being used.
808 @retval other The child handle was not destroyed
809
810 **/
811 EFI_STATUS
812 EFIAPI
813 Ip4ServiceBindingDestroyChild (
814 IN EFI_SERVICE_BINDING_PROTOCOL *This,
815 IN EFI_HANDLE ChildHandle
816 )
817 {
818 EFI_STATUS Status;
819 IP4_SERVICE *IpSb;
820 IP4_PROTOCOL *IpInstance;
821 EFI_IP4_PROTOCOL *Ip4;
822 EFI_TPL OldTpl;
823 INTN State;
824
825 if ((This == NULL) || (ChildHandle == NULL)) {
826 return EFI_INVALID_PARAMETER;
827 }
828
829 //
830 // Retrieve the private context data structures
831 //
832 IpSb = IP4_SERVICE_FROM_PROTOCOL (This);
833
834 Status = gBS->OpenProtocol (
835 ChildHandle,
836 &gEfiIp4ProtocolGuid,
837 (VOID **) &Ip4,
838 gIp4DriverBinding.DriverBindingHandle,
839 ChildHandle,
840 EFI_OPEN_PROTOCOL_GET_PROTOCOL
841 );
842
843 if (EFI_ERROR (Status)) {
844 return EFI_UNSUPPORTED;
845 }
846
847 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (Ip4);
848
849 if (IpInstance->Service != IpSb) {
850 return EFI_INVALID_PARAMETER;
851 }
852
853 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
854
855 //
856 // A child can be destoried more than once. For example,
857 // Ip4DriverBindingStop will destory all of its children.
858 // when UDP driver is being stopped, it will destory all
859 // the IP child it opens.
860 //
861 if (IpInstance->State == IP4_STATE_DESTORY) {
862 NET_RESTORE_TPL (OldTpl);
863 return EFI_SUCCESS;
864 }
865
866 State = IpInstance->State;
867 IpInstance->State = IP4_STATE_DESTORY;
868
869 //
870 // Close the Managed Network protocol.
871 //
872 gBS->CloseProtocol (
873 IpSb->MnpChildHandle,
874 &gEfiManagedNetworkProtocolGuid,
875 gIp4DriverBinding.DriverBindingHandle,
876 ChildHandle
877 );
878
879 //
880 // Uninstall the IP4 protocol first. Many thing happens during
881 // this:
882 // 1. The consumer of the IP4 protocol will be stopped if it
883 // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
884 // stopped, IP driver's stop function will be called, and uninstall
885 // EFI_IP4_PROTOCOL will trigger the UDP's stop function. This
886 // makes it possible to create the network stack bottom up, and
887 // stop it top down.
888 // 2. the upper layer will recycle the received packet. The recycle
889 // event's TPL is higher than this function. The recycle events
890 // will be called back before preceeding. If any packets not recycled,
891 // that means there is a resource leak.
892 //
893 Status = gBS->UninstallProtocolInterface (
894 ChildHandle,
895 &gEfiIp4ProtocolGuid,
896 &IpInstance->Ip4Proto
897 );
898
899 if (EFI_ERROR (Status)) {
900 goto ON_ERROR;
901 }
902
903 Status = Ip4CleanProtocol (IpInstance);
904
905 Ip4SetVariableData (IpSb);
906
907 if (EFI_ERROR (Status)) {
908 gBS->InstallMultipleProtocolInterfaces (
909 &ChildHandle,
910 &gEfiIp4ProtocolGuid,
911 Ip4,
912 NULL
913 );
914
915 goto ON_ERROR;
916 }
917
918 NetListRemoveEntry (&IpInstance->Link);
919 IpSb->NumChildren--;
920
921 NET_RESTORE_TPL (OldTpl);
922
923 NetFreePool (IpInstance);
924 return EFI_SUCCESS;
925
926 ON_ERROR:
927 IpInstance->State = State;
928 NET_RESTORE_TPL (OldTpl);
929
930 return Status;
931 }