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