1. clean up codes.
[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 NetLibInstallAllDriverProtocols (
60 ImageHandle,
61 SystemTable,
62 &gIp4DriverBinding,
63 ImageHandle,
64 &gIp4ComponentName,
65 NULL,
66 NULL
67 );
68 }
69
70
71 /**
72 Test to see if this driver supports ControllerHandle.
73
74 @param This Protocol instance pointer.
75 @param ControllerHandle Handle of device to test
76 @param RemainingDevicePath Optional parameter use to pick a specific child
77 device to start.
78
79 @retval EFI_SUCCES This driver supports this device
80 @retval EFI_ALREADY_STARTED This driver is already running on this device
81 @retval other This driver does not support this device
82
83 **/
84 EFI_STATUS
85 EFIAPI
86 Ip4DriverBindingSupported (
87 IN EFI_DRIVER_BINDING_PROTOCOL * This,
88 IN EFI_HANDLE ControllerHandle,
89 IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
90 )
91 {
92 EFI_STATUS Status;
93
94 //
95 // Test for the MNP service binding Protocol
96 //
97 Status = gBS->OpenProtocol (
98 ControllerHandle,
99 &gEfiManagedNetworkServiceBindingProtocolGuid,
100 NULL,
101 This->DriverBindingHandle,
102 ControllerHandle,
103 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
104 );
105
106 if (EFI_ERROR (Status)) {
107 return Status;
108 }
109
110 //
111 // Test for the Arp service binding Protocol
112 //
113 Status = gBS->OpenProtocol (
114 ControllerHandle,
115 &gEfiArpServiceBindingProtocolGuid,
116 NULL,
117 This->DriverBindingHandle,
118 ControllerHandle,
119 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
120 );
121
122 return Status;
123 }
124
125 STATIC
126 EFI_STATUS
127 Ip4CleanService (
128 IN IP4_SERVICE *IpSb
129 );
130
131
132 /**
133 Create a new IP4 driver service binding protocol
134
135 @param Controller The controller that has MNP service binding
136 installed
137 @param ImageHandle The IP4 driver's image handle
138 @param Service The variable to receive the newly created IP4
139 service.
140
141 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resource
142 @retval EFI_SUCCESS A new IP4 service binding private is created.
143
144 **/
145 STATIC
146 EFI_STATUS
147 Ip4CreateService (
148 IN EFI_HANDLE Controller,
149 IN EFI_HANDLE ImageHandle,
150 OUT IP4_SERVICE **Service
151 )
152 {
153 IP4_SERVICE *IpSb;
154 EFI_STATUS Status;
155
156 ASSERT (Service != NULL);
157
158 *Service = NULL;
159
160 //
161 // allocate a service private data then initialize all the filed to
162 // empty resources, so if any thing goes wrong when allocating
163 // resources, Ip4CleanService can be called to clean it up.
164 //
165 IpSb = NetAllocatePool (sizeof (IP4_SERVICE));
166
167 if (IpSb == NULL) {
168 return EFI_OUT_OF_RESOURCES;
169 }
170
171 IpSb->Signature = IP4_SERVICE_SIGNATURE;
172 IpSb->ServiceBinding.CreateChild = Ip4ServiceBindingCreateChild;
173 IpSb->ServiceBinding.DestroyChild = Ip4ServiceBindingDestroyChild;
174 IpSb->State = IP4_SERVICE_UNSTARTED;
175 IpSb->InDestory = FALSE;
176
177 IpSb->NumChildren = 0;
178 NetListInit (&IpSb->Children);
179
180 NetListInit (&IpSb->Interfaces);
181 IpSb->DefaultInterface = NULL;
182 IpSb->DefaultRouteTable = NULL;
183
184 Ip4InitAssembleTable (&IpSb->Assemble);
185
186 IpSb->IgmpCtrl.Igmpv1QuerySeen = 0;
187 NetListInit (&IpSb->IgmpCtrl.Groups);
188
189 IpSb->Image = ImageHandle;
190 IpSb->Controller = Controller;
191
192 IpSb->MnpChildHandle = NULL;
193 IpSb->Mnp = NULL;
194
195 IpSb->MnpConfigData.ReceivedQueueTimeoutValue = 0;
196 IpSb->MnpConfigData.TransmitQueueTimeoutValue = 0;
197 IpSb->MnpConfigData.ProtocolTypeFilter = IP4_ETHER_PROTO;
198 IpSb->MnpConfigData.EnableUnicastReceive = TRUE;
199 IpSb->MnpConfigData.EnableMulticastReceive = TRUE;
200 IpSb->MnpConfigData.EnableBroadcastReceive = TRUE;
201 IpSb->MnpConfigData.EnablePromiscuousReceive = FALSE;
202 IpSb->MnpConfigData.FlushQueuesOnReset = TRUE;
203 IpSb->MnpConfigData.EnableReceiveTimestamps = FALSE;
204 IpSb->MnpConfigData.DisableBackgroundPolling = FALSE;
205
206 NetZeroMem (&IpSb->SnpMode, sizeof (EFI_SIMPLE_NETWORK_MODE));
207
208 IpSb->Timer = NULL;
209 IpSb->Ip4Config = NULL;
210 IpSb->DoneEvent = NULL;
211 IpSb->ReconfigEvent = 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 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->Ip4Config = NULL;
380 }
381
382 return EFI_SUCCESS;
383 }
384
385
386 /**
387 Start this driver on ControllerHandle.
388
389 @param This Protocol instance pointer.
390 @param ControllerHandle Handle of device to bind driver to
391 @param RemainingDevicePath Optional parameter use to pick a specific child
392 device to start.
393
394 @retval EFI_SUCCES This driver is added to ControllerHandle
395 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
396 @retval other This driver does not support this device
397
398 **/
399 EFI_STATUS
400 EFIAPI
401 Ip4DriverBindingStart (
402 IN EFI_DRIVER_BINDING_PROTOCOL * This,
403 IN EFI_HANDLE ControllerHandle,
404 IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL
405 )
406 {
407 IP4_SERVICE *IpSb;
408 EFI_STATUS Status;
409
410 //
411 // Test for the Ip4 service binding protocol
412 //
413 Status = gBS->OpenProtocol (
414 ControllerHandle,
415 &gEfiIp4ServiceBindingProtocolGuid,
416 NULL,
417 This->DriverBindingHandle,
418 ControllerHandle,
419 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
420 );
421
422 if (Status == EFI_SUCCESS) {
423 return EFI_ALREADY_STARTED;
424 }
425
426 Status = Ip4CreateService (ControllerHandle, This->DriverBindingHandle, &IpSb);
427
428 if (EFI_ERROR (Status)) {
429 return Status;
430 }
431
432 //
433 // Install the Ip4ServiceBinding Protocol onto ControlerHandle
434 //
435 Status = gBS->InstallMultipleProtocolInterfaces (
436 &ControllerHandle,
437 &gEfiIp4ServiceBindingProtocolGuid,
438 &IpSb->ServiceBinding,
439 NULL
440 );
441
442 if (EFI_ERROR (Status)) {
443 goto FREE_SERVICE;
444 }
445
446 //
447 // ready to go: start the receiving and timer
448 //
449 Status = Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);
450
451 if (EFI_ERROR (Status)) {
452 goto UNINSTALL_PROTOCOL;
453 }
454
455 Status = gBS->SetTimer (IpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
456
457 if (EFI_ERROR (Status)) {
458 goto UNINSTALL_PROTOCOL;
459 }
460
461 //
462 // Initialize the IP4 ID
463 //
464 mIp4Id = (UINT16)NET_RANDOM (NetRandomInitSeed ());
465
466 Ip4SetVariableData (IpSb);
467
468 return Status;
469
470 UNINSTALL_PROTOCOL:
471 gBS->UninstallProtocolInterface (
472 ControllerHandle,
473 &gEfiIp4ServiceBindingProtocolGuid,
474 &IpSb->ServiceBinding
475 );
476
477 FREE_SERVICE:
478 Ip4CleanService (IpSb);
479 NetFreePool (IpSb);
480
481 return Status;
482 }
483
484
485 /**
486 Stop this driver on ControllerHandle.
487
488 @param This Protocol instance pointer.
489 @param ControllerHandle Handle of device to stop driver on
490 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number
491 of children is zero stop the entire bus driver.
492 @param ChildHandleBuffer List of Child Handles to Stop.
493
494 @retval EFI_SUCCES This driver is removed ControllerHandle
495 @retval other This driver was not removed from this device
496
497 **/
498 EFI_STATUS
499 EFIAPI
500 Ip4DriverBindingStop (
501 IN EFI_DRIVER_BINDING_PROTOCOL *This,
502 IN EFI_HANDLE ControllerHandle,
503 IN UINTN NumberOfChildren,
504 IN EFI_HANDLE *ChildHandleBuffer
505 )
506 {
507 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
508 IP4_SERVICE *IpSb;
509 IP4_PROTOCOL *IpInstance;
510 EFI_HANDLE NicHandle;
511 EFI_STATUS Status;
512 EFI_TPL OldTpl;
513 INTN State;
514
515 //
516 // IP4 driver opens the MNP child, ARP children or the IP4_CONFIG protocol
517 // by driver. So the ControllerHandle may be the MNP child handle, ARP child
518 // handle, or the NIC (UNDI) handle because IP4_CONFIG protocol is installed
519 // in the NIC handle.
520 //
521 //
522 // First, check whether it is the IP4_CONFIG protocol being uninstalled.
523 // IP4_CONFIG protocol is installed on the NIC handle. It isn't necessary
524 // to clean up the default configuration if IP4_CONFIG is being stopped.
525 //
526 Status = gBS->OpenProtocol (
527 ControllerHandle,
528 &gEfiIp4ConfigProtocolGuid,
529 NULL,
530 This->DriverBindingHandle,
531 ControllerHandle,
532 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
533 );
534
535 if (Status == EFI_SUCCESS) {
536 //
537 // Retrieve the IP4 service binding protocol. If failed, it is
538 // likely that Ip4 ServiceBinding is uninstalled already. In this
539 // case, return immediately.
540 //
541 Status = gBS->OpenProtocol (
542 ControllerHandle,
543 &gEfiIp4ServiceBindingProtocolGuid,
544 (VOID **) &ServiceBinding,
545 This->DriverBindingHandle,
546 ControllerHandle,
547 EFI_OPEN_PROTOCOL_GET_PROTOCOL
548 );
549
550 if (EFI_ERROR (Status)) {
551 return EFI_SUCCESS;
552 }
553
554 IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
555
556 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
557
558 if (IpSb->Ip4Config && (IpSb->State != IP4_SERVICE_DESTORY)) {
559
560 IpSb->Ip4Config->Stop (IpSb->Ip4Config);
561
562 Status = gBS->CloseProtocol (
563 ControllerHandle,
564 &gEfiIp4ConfigProtocolGuid,
565 IpSb->Image,
566 ControllerHandle
567 );
568
569 if (EFI_ERROR (Status)) {
570 NET_RESTORE_TPL (OldTpl);
571 return Status;
572 }
573
574 //
575 // If the auto configure hasn't complete, mark it as not started.
576 //
577 if (IpSb->State == IP4_SERVICE_STARTED) {
578 IpSb->State = IP4_SERVICE_UNSTARTED;
579 }
580
581 IpSb->Ip4Config = NULL;
582 gBS->CloseEvent (IpSb->DoneEvent);
583 gBS->CloseEvent (IpSb->ReconfigEvent);
584 }
585
586 NET_RESTORE_TPL (OldTpl);
587 return EFI_SUCCESS;
588 }
589
590 //
591 // Either MNP or ARP protocol is being uninstalled. The controller
592 // handle is either the MNP child or ARP child. But, the IP4's
593 // service binding is installed on the NIC handle. So, need to open
594 // the protocol info to find the NIC handle.
595 //
596 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
597
598 if (NicHandle == NULL) {
599 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid);
600 }
601
602 if (NicHandle == NULL) {
603 return EFI_SUCCESS;
604 }
605
606 //
607 // Retrieve the IP4 service binding protocol
608 //
609 Status = gBS->OpenProtocol (
610 NicHandle,
611 &gEfiIp4ServiceBindingProtocolGuid,
612 (VOID **) &ServiceBinding,
613 This->DriverBindingHandle,
614 NicHandle,
615 EFI_OPEN_PROTOCOL_GET_PROTOCOL
616 );
617
618 if (EFI_ERROR (Status)) {
619 return EFI_DEVICE_ERROR;
620 }
621
622 IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
623
624 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
625
626 if (IpSb->InDestory) {
627 NET_RESTORE_TPL (OldTpl);
628 return EFI_SUCCESS;
629 }
630
631 IpSb->InDestory = TRUE;
632
633 State = IpSb->State;
634 IpSb->State = IP4_SERVICE_DESTORY;
635
636 //
637 // Destory all the children first. If not all children are destoried,
638 // the IP driver can operate correctly, so restore it state. Don't
639 // use NET_LIST_FOR_EACH_SAFE here, because it will cache the next
640 // pointer, which may point to the child that has already been destoried.
641 // For example, if there are two child in the list, the first is UDP
642 // listen child, the send is the MTFTP's child. When Udp child is
643 // destoried, it will destory the MTFTP's child. Then Next point to
644 // a invalid child.
645 //
646 while (!NetListIsEmpty (&IpSb->Children)) {
647 IpInstance = NET_LIST_HEAD (&IpSb->Children, IP4_PROTOCOL, Link);
648 Ip4ServiceBindingDestroyChild (ServiceBinding, IpInstance->Handle);
649 }
650
651 if (IpSb->NumChildren != 0) {
652 IpSb->State = State;
653 Status = EFI_DEVICE_ERROR;
654 goto ON_ERROR;
655 }
656
657 //
658 // Clear the variable data.
659 //
660 Ip4ClearVariableData (IpSb);
661
662 //
663 // OK, clean other resources then uninstall the service binding protocol.
664 //
665 Status = Ip4CleanService (IpSb);
666
667 if (EFI_ERROR (Status)) {
668 goto ON_ERROR;
669 }
670
671 Status = gBS->UninstallProtocolInterface (
672 NicHandle,
673 &gEfiIp4ServiceBindingProtocolGuid,
674 ServiceBinding
675 );
676
677 if (EFI_ERROR (Status)) {
678 goto ON_ERROR;
679 }
680
681 NET_RESTORE_TPL (OldTpl);
682 NetFreePool (IpSb);
683 return EFI_SUCCESS;
684
685 ON_ERROR:
686 IpSb->InDestory = FALSE;
687 NET_RESTORE_TPL (OldTpl);
688 return Status;
689 }
690
691
692 /**
693 Creates a child handle with a set of I/O services.
694
695 @param This Protocol instance pointer.
696 @param ChildHandle Pointer to the handle of the child to create. If
697 it is NULL, then a new handle is created. If it
698 is not NULL, then the I/O services are added to
699 the existing child handle.
700
701 @retval EFI_SUCCES The child handle was created with the I/O services
702 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
703 the child
704 @retval other The child handle was not created
705
706 **/
707 EFI_STATUS
708 EFIAPI
709 Ip4ServiceBindingCreateChild (
710 IN EFI_SERVICE_BINDING_PROTOCOL *This,
711 IN EFI_HANDLE *ChildHandle
712 )
713 {
714 IP4_SERVICE *IpSb;
715 IP4_PROTOCOL *IpInstance;
716 EFI_TPL OldTpl;
717 EFI_STATUS Status;
718 VOID *Mnp;
719
720 if ((This == NULL) || (ChildHandle == NULL)) {
721 return EFI_INVALID_PARAMETER;
722 }
723
724 IpSb = IP4_SERVICE_FROM_PROTOCOL (This);
725 IpInstance = NetAllocatePool (sizeof (IP4_PROTOCOL));
726
727 if (IpInstance == NULL) {
728 return EFI_OUT_OF_RESOURCES;
729 }
730
731 Ip4InitProtocol (IpSb, IpInstance);
732
733 //
734 // Install Ip4 onto ChildHandle
735 //
736 Status = gBS->InstallMultipleProtocolInterfaces (
737 ChildHandle,
738 &gEfiIp4ProtocolGuid,
739 &IpInstance->Ip4Proto,
740 NULL
741 );
742
743 if (EFI_ERROR (Status)) {
744 goto ON_ERROR;
745 }
746
747 IpInstance->Handle = *ChildHandle;
748
749 //
750 // Open the Managed Network protocol BY_CHILD.
751 //
752 Status = gBS->OpenProtocol (
753 IpSb->MnpChildHandle,
754 &gEfiManagedNetworkProtocolGuid,
755 (VOID **) &Mnp,
756 gIp4DriverBinding.DriverBindingHandle,
757 IpInstance->Handle,
758 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
759 );
760 if (EFI_ERROR (Status)) {
761 gBS->UninstallMultipleProtocolInterfaces (
762 ChildHandle,
763 &gEfiIp4ProtocolGuid,
764 &IpInstance->Ip4Proto,
765 NULL
766 );
767
768 goto ON_ERROR;
769 }
770
771 //
772 // Insert it into the service binding instance.
773 //
774 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
775
776 NetListInsertTail (&IpSb->Children, &IpInstance->Link);
777 IpSb->NumChildren++;
778
779 NET_RESTORE_TPL (OldTpl);
780
781 ON_ERROR:
782
783 if (EFI_ERROR (Status)) {
784
785 Ip4CleanProtocol (IpInstance);
786
787 NetFreePool (IpInstance);
788 }
789
790 return Status;
791 }
792
793
794 /**
795 Destroys a child handle with a set of I/O services.
796
797 @param This Protocol instance pointer.
798 @param ChildHandle Handle of the child to destroy
799
800 @retval EFI_SUCCES The I/O services were removed from the child
801 handle
802 @retval EFI_UNSUPPORTED The child handle does not support the I/O services
803 that are being removed
804 @retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
805 @retval EFI_ACCESS_DENIED The child handle could not be destroyed because
806 its I/O services are being used.
807 @retval other The child handle was not destroyed
808
809 **/
810 EFI_STATUS
811 EFIAPI
812 Ip4ServiceBindingDestroyChild (
813 IN EFI_SERVICE_BINDING_PROTOCOL *This,
814 IN EFI_HANDLE ChildHandle
815 )
816 {
817 EFI_STATUS Status;
818 IP4_SERVICE *IpSb;
819 IP4_PROTOCOL *IpInstance;
820 EFI_IP4_PROTOCOL *Ip4;
821 EFI_TPL OldTpl;
822 INTN State;
823
824 if ((This == NULL) || (ChildHandle == NULL)) {
825 return EFI_INVALID_PARAMETER;
826 }
827
828 //
829 // Retrieve the private context data structures
830 //
831 IpSb = IP4_SERVICE_FROM_PROTOCOL (This);
832
833 Status = gBS->OpenProtocol (
834 ChildHandle,
835 &gEfiIp4ProtocolGuid,
836 (VOID **) &Ip4,
837 gIp4DriverBinding.DriverBindingHandle,
838 ChildHandle,
839 EFI_OPEN_PROTOCOL_GET_PROTOCOL
840 );
841
842 if (EFI_ERROR (Status)) {
843 return EFI_UNSUPPORTED;
844 }
845
846 IpInstance = IP4_INSTANCE_FROM_PROTOCOL (Ip4);
847
848 if (IpInstance->Service != IpSb) {
849 return EFI_INVALID_PARAMETER;
850 }
851
852 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
853
854 //
855 // A child can be destoried more than once. For example,
856 // Ip4DriverBindingStop will destory all of its children.
857 // when UDP driver is being stopped, it will destory all
858 // the IP child it opens.
859 //
860 if (IpInstance->State == IP4_STATE_DESTORY) {
861 NET_RESTORE_TPL (OldTpl);
862 return EFI_SUCCESS;
863 }
864
865 State = IpInstance->State;
866 IpInstance->State = IP4_STATE_DESTORY;
867
868 //
869 // Close the Managed Network protocol.
870 //
871 gBS->CloseProtocol (
872 IpSb->MnpChildHandle,
873 &gEfiManagedNetworkProtocolGuid,
874 gIp4DriverBinding.DriverBindingHandle,
875 ChildHandle
876 );
877
878 //
879 // Uninstall the IP4 protocol first. Many thing happens during
880 // this:
881 // 1. The consumer of the IP4 protocol will be stopped if it
882 // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
883 // stopped, IP driver's stop function will be called, and uninstall
884 // EFI_IP4_PROTOCOL will trigger the UDP's stop function. This
885 // makes it possible to create the network stack bottom up, and
886 // stop it top down.
887 // 2. the upper layer will recycle the received packet. The recycle
888 // event's TPL is higher than this function. The recycle events
889 // will be called back before preceeding. If any packets not recycled,
890 // that means there is a resource leak.
891 //
892 Status = gBS->UninstallProtocolInterface (
893 ChildHandle,
894 &gEfiIp4ProtocolGuid,
895 &IpInstance->Ip4Proto
896 );
897
898 if (EFI_ERROR (Status)) {
899 goto ON_ERROR;
900 }
901
902 Status = Ip4CleanProtocol (IpInstance);
903
904 Ip4SetVariableData (IpSb);
905
906 if (EFI_ERROR (Status)) {
907 gBS->InstallMultipleProtocolInterfaces (
908 &ChildHandle,
909 &gEfiIp4ProtocolGuid,
910 Ip4,
911 NULL
912 );
913
914 goto ON_ERROR;
915 }
916
917 NetListRemoveEntry (&IpInstance->Link);
918 IpSb->NumChildren--;
919
920 NET_RESTORE_TPL (OldTpl);
921
922 NetFreePool (IpInstance);
923 return EFI_SUCCESS;
924
925 ON_ERROR:
926 IpInstance->State = State;
927 NET_RESTORE_TPL (OldTpl);
928
929 return Status;
930 }