1 /** @file
2   The driver binding and service binding protocol for IP4 driver.
3 
4 Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
6 
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution.  The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11 
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include "Ip4Impl.h"
18 
19 EFI_DRIVER_BINDING_PROTOCOL gIp4DriverBinding = {
20   Ip4DriverBindingSupported,
21   Ip4DriverBindingStart,
22   Ip4DriverBindingStop,
23   0xa,
24   NULL,
25   NULL
26 };
27 
28 BOOLEAN  mIpSec2Installed = FALSE;
29 
30 /**
31    Callback function for IpSec2 Protocol install.
32 
33    @param[in] Event           Event whose notification function is being invoked
34    @param[in] Context         Pointer to the notification function's context
35 
36 **/
37 VOID
38 EFIAPI
IpSec2InstalledCallback(IN EFI_EVENT Event,IN VOID * Context)39 IpSec2InstalledCallback (
40   IN EFI_EVENT  Event,
41   IN VOID       *Context
42   )
43 {
44   //
45   // Close the event so it does not get called again.
46   //
47   gBS->CloseEvent (Event);
48 
49   mIpSec2Installed = TRUE;
50 }
51 
52 /**
53   This is the declaration of an EFI image entry point. This entry point is
54   the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
55   both device drivers and bus drivers.
56 
57   The entry point for IP4 driver which install the driver
58   binding and component name protocol on its image.
59 
60   @param[in]  ImageHandle           The firmware allocated handle for the UEFI image.
61   @param[in]  SystemTable           A pointer to the EFI System Table.
62 
63   @retval EFI_SUCCESS           The operation completed successfully.
64   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
65 
66 **/
67 EFI_STATUS
68 EFIAPI
Ip4DriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)69 Ip4DriverEntryPoint (
70   IN EFI_HANDLE             ImageHandle,
71   IN EFI_SYSTEM_TABLE       *SystemTable
72   )
73 {
74   VOID            *Registration;
75 
76   EfiCreateProtocolNotifyEvent (
77     &gEfiIpSec2ProtocolGuid,
78     TPL_CALLBACK,
79     IpSec2InstalledCallback,
80     NULL,
81     &Registration
82     );
83 
84   return EfiLibInstallDriverBindingComponentName2 (
85            ImageHandle,
86            SystemTable,
87            &gIp4DriverBinding,
88            ImageHandle,
89            &gIp4ComponentName,
90            &gIp4ComponentName2
91            );
92 }
93 
94 /**
95   Test to see if this driver supports ControllerHandle. This service
96   is called by the EFI boot service ConnectController(). In
97   order to make drivers as small as possible, there are a few calling
98   restrictions for this service. ConnectController() must
99   follow these calling restrictions. If any other agent wishes to call
100   Supported() it must also follow these calling restrictions.
101 
102   @param[in]  This                Protocol instance pointer.
103   @param[in]  ControllerHandle    Handle of device to test
104   @param[in]  RemainingDevicePath Optional parameter use to pick a specific child
105                                   device to start.
106 
107   @retval EFI_SUCCESS         This driver supports this device
108   @retval EFI_ALREADY_STARTED This driver is already running on this device
109   @retval other               This driver does not support this device
110 
111 **/
112 EFI_STATUS
113 EFIAPI
Ip4DriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)114 Ip4DriverBindingSupported (
115   IN EFI_DRIVER_BINDING_PROTOCOL  * This,
116   IN EFI_HANDLE                   ControllerHandle,
117   IN EFI_DEVICE_PATH_PROTOCOL     * RemainingDevicePath OPTIONAL
118   )
119 {
120   EFI_STATUS                Status;
121 
122   //
123   // Test for the MNP service binding Protocol
124   //
125   Status = gBS->OpenProtocol (
126                   ControllerHandle,
127                   &gEfiManagedNetworkServiceBindingProtocolGuid,
128                   NULL,
129                   This->DriverBindingHandle,
130                   ControllerHandle,
131                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
132                   );
133 
134   if (EFI_ERROR (Status)) {
135     return Status;
136   }
137 
138   //
139   // Test for the Arp service binding Protocol
140   //
141   Status = gBS->OpenProtocol (
142                   ControllerHandle,
143                   &gEfiArpServiceBindingProtocolGuid,
144                   NULL,
145                   This->DriverBindingHandle,
146                   ControllerHandle,
147                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
148                   );
149 
150   return Status;
151 }
152 
153 /**
154   Clean up a IP4 service binding instance. It will release all
155   the resource allocated by the instance. The instance may be
156   partly initialized, or partly destroyed. If a resource is
157   destroyed, it is marked as that in case the destroy failed and
158   being called again later.
159 
160   @param[in]  IpSb               The IP4 service binding instance to clean up
161 
162   @retval EFI_SUCCESS            The resource used by the instance are cleaned up
163   @retval other                  Failed to clean up some of the resources.
164 
165 **/
166 EFI_STATUS
167 Ip4CleanService (
168   IN IP4_SERVICE            *IpSb
169   );
170 
171 
172 /**
173   Create a new IP4 driver service binding private instance.
174 
175   @param  Controller         The controller that has MNP service binding
176                              installed
177   @param  ImageHandle        The IP4 driver's image handle
178   @param  Service            The variable to receive the newly created IP4
179                              service.
180 
181   @retval EFI_OUT_OF_RESOURCES   Failed to allocate some resource
182   @retval EFI_SUCCESS            A new IP4 service binding private is created.
183   @retval other                  Other error occurs.
184 
185 **/
186 EFI_STATUS
Ip4CreateService(IN EFI_HANDLE Controller,IN EFI_HANDLE ImageHandle,OUT IP4_SERVICE ** Service)187 Ip4CreateService (
188   IN  EFI_HANDLE            Controller,
189   IN  EFI_HANDLE            ImageHandle,
190   OUT IP4_SERVICE           **Service
191   )
192 {
193   IP4_SERVICE               *IpSb;
194   EFI_STATUS                Status;
195 
196   ASSERT (Service != NULL);
197 
198   *Service = NULL;
199 
200   //
201   // allocate a service private data then initialize all the filed to
202   // empty resources, so if any thing goes wrong when allocating
203   // resources, Ip4CleanService can be called to clean it up.
204   //
205   IpSb = AllocateZeroPool (sizeof (IP4_SERVICE));
206 
207   if (IpSb == NULL) {
208     return EFI_OUT_OF_RESOURCES;
209   }
210 
211   IpSb->Signature                   = IP4_SERVICE_SIGNATURE;
212   IpSb->ServiceBinding.CreateChild  = Ip4ServiceBindingCreateChild;
213   IpSb->ServiceBinding.DestroyChild = Ip4ServiceBindingDestroyChild;
214   IpSb->State                       = IP4_SERVICE_UNSTARTED;
215 
216   IpSb->NumChildren                 = 0;
217   InitializeListHead (&IpSb->Children);
218 
219   InitializeListHead (&IpSb->Interfaces);
220   IpSb->DefaultInterface            = NULL;
221   IpSb->DefaultRouteTable           = NULL;
222 
223   Ip4InitAssembleTable (&IpSb->Assemble);
224 
225   IpSb->IgmpCtrl.Igmpv1QuerySeen    = 0;
226   InitializeListHead (&IpSb->IgmpCtrl.Groups);
227 
228   IpSb->Image                       = ImageHandle;
229   IpSb->Controller                  = Controller;
230 
231   IpSb->MnpChildHandle              = NULL;
232   IpSb->Mnp                         = NULL;
233 
234   IpSb->MnpConfigData.ReceivedQueueTimeoutValue = 0;
235   IpSb->MnpConfigData.TransmitQueueTimeoutValue = 0;
236   IpSb->MnpConfigData.ProtocolTypeFilter        = IP4_ETHER_PROTO;
237   IpSb->MnpConfigData.EnableUnicastReceive      = TRUE;
238   IpSb->MnpConfigData.EnableMulticastReceive    = TRUE;
239   IpSb->MnpConfigData.EnableBroadcastReceive    = TRUE;
240   IpSb->MnpConfigData.EnablePromiscuousReceive  = FALSE;
241   IpSb->MnpConfigData.FlushQueuesOnReset        = TRUE;
242   IpSb->MnpConfigData.EnableReceiveTimestamps   = FALSE;
243   IpSb->MnpConfigData.DisableBackgroundPolling  = FALSE;
244 
245   ZeroMem (&IpSb->SnpMode, sizeof (EFI_SIMPLE_NETWORK_MODE));
246 
247   IpSb->Timer = NULL;
248 
249   IpSb->ReconfigEvent = NULL;
250 
251   IpSb->Reconfig = FALSE;
252 
253   IpSb->MediaPresent = TRUE;
254 
255   //
256   // Create various resources. First create the route table, timer
257   // event and MNP child. IGMP, interface's initialization depend
258   // on the MNP child.
259   //
260   IpSb->DefaultRouteTable = Ip4CreateRouteTable ();
261 
262   if (IpSb->DefaultRouteTable == NULL) {
263     Status = EFI_OUT_OF_RESOURCES;
264     goto ON_ERROR;
265   }
266 
267   Status = gBS->CreateEvent (
268                   EVT_NOTIFY_SIGNAL | EVT_TIMER,
269                   TPL_CALLBACK,
270                   Ip4TimerTicking,
271                   IpSb,
272                   &IpSb->Timer
273                   );
274 
275   if (EFI_ERROR (Status)) {
276     goto ON_ERROR;
277   }
278 
279   Status = NetLibCreateServiceChild (
280              Controller,
281              ImageHandle,
282              &gEfiManagedNetworkServiceBindingProtocolGuid,
283              &IpSb->MnpChildHandle
284              );
285 
286   if (EFI_ERROR (Status)) {
287     goto ON_ERROR;
288   }
289 
290   Status = gBS->OpenProtocol (
291                   IpSb->MnpChildHandle,
292                   &gEfiManagedNetworkProtocolGuid,
293                   (VOID **) &IpSb->Mnp,
294                   ImageHandle,
295                   Controller,
296                   EFI_OPEN_PROTOCOL_BY_DRIVER
297                   );
298 
299   if (EFI_ERROR (Status)) {
300     goto ON_ERROR;
301   }
302 
303   Status = Ip4ServiceConfigMnp (IpSb, TRUE);
304 
305   if (EFI_ERROR (Status)) {
306     goto ON_ERROR;
307   }
308 
309   Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &IpSb->SnpMode);
310 
311   if (EFI_ERROR (Status)) {
312     goto ON_ERROR;
313   }
314 
315   Status = Ip4InitIgmp (IpSb);
316 
317   if (EFI_ERROR (Status)) {
318     goto ON_ERROR;
319   }
320 
321   IpSb->MacString = NULL;
322   Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &IpSb->MacString);
323 
324   if (EFI_ERROR (Status)) {
325     goto ON_ERROR;
326   }
327 
328   IpSb->DefaultInterface = Ip4CreateInterface (IpSb->Mnp, Controller, ImageHandle);
329 
330   if (IpSb->DefaultInterface == NULL) {
331     Status = EFI_OUT_OF_RESOURCES;
332     goto ON_ERROR;
333   }
334 
335   InsertHeadList (&IpSb->Interfaces, &IpSb->DefaultInterface->Link);
336 
337   ZeroMem (&IpSb->Ip4Config2Instance, sizeof (IP4_CONFIG2_INSTANCE));
338 
339   Status = Ip4Config2InitInstance (&IpSb->Ip4Config2Instance);
340 
341   if (EFI_ERROR (Status)) {
342     goto ON_ERROR;
343   }
344 
345   IpSb->MaxPacketSize = IpSb->SnpMode.MaxPacketSize - sizeof (IP4_HEAD);
346   if (NetLibGetVlanId (IpSb->Controller) != 0) {
347     //
348     // This is a VLAN device, reduce MTU by VLAN tag length
349     //
350     IpSb->MaxPacketSize -= NET_VLAN_TAG_LEN;
351   }
352   IpSb->OldMaxPacketSize = IpSb->MaxPacketSize;
353   *Service = IpSb;
354 
355   return EFI_SUCCESS;
356 
357 ON_ERROR:
358   Ip4CleanService (IpSb);
359   FreePool (IpSb);
360 
361   return Status;
362 }
363 
364 
365 /**
366   Clean up a IP4 service binding instance. It will release all
367   the resource allocated by the instance. The instance may be
368   partly initialized, or partly destroyed. If a resource is
369   destroyed, it is marked as that in case the destroy failed and
370   being called again later.
371 
372   @param[in]  IpSb               The IP4 service binding instance to clean up
373 
374   @retval EFI_SUCCESS            The resource used by the instance are cleaned up
375   @retval other                  Failed to clean up some of the resources.
376 
377 **/
378 EFI_STATUS
Ip4CleanService(IN IP4_SERVICE * IpSb)379 Ip4CleanService (
380   IN IP4_SERVICE            *IpSb
381   )
382 {
383   EFI_STATUS                Status;
384 
385   if (IpSb->DefaultInterface != NULL) {
386     Status = Ip4FreeInterface (IpSb->DefaultInterface, NULL);
387 
388     if (EFI_ERROR (Status)) {
389       return Status;
390     }
391 
392     IpSb->DefaultInterface = NULL;
393   }
394 
395   if (IpSb->DefaultRouteTable != NULL) {
396     Ip4FreeRouteTable (IpSb->DefaultRouteTable);
397     IpSb->DefaultRouteTable = NULL;
398   }
399 
400   Ip4CleanAssembleTable (&IpSb->Assemble);
401 
402   if (IpSb->MnpChildHandle != NULL) {
403     if (IpSb->Mnp != NULL) {
404       gBS->CloseProtocol (
405              IpSb->MnpChildHandle,
406              &gEfiManagedNetworkProtocolGuid,
407              IpSb->Image,
408              IpSb->Controller
409              );
410 
411       IpSb->Mnp = NULL;
412     }
413 
414     NetLibDestroyServiceChild (
415       IpSb->Controller,
416       IpSb->Image,
417       &gEfiManagedNetworkServiceBindingProtocolGuid,
418       IpSb->MnpChildHandle
419       );
420 
421     IpSb->MnpChildHandle = NULL;
422   }
423 
424   if (IpSb->Timer != NULL) {
425     gBS->SetTimer (IpSb->Timer, TimerCancel, 0);
426     gBS->CloseEvent (IpSb->Timer);
427 
428     IpSb->Timer = NULL;
429   }
430 
431   if (IpSb->ReconfigEvent != NULL) {
432     gBS->CloseEvent (IpSb->ReconfigEvent);
433 
434     IpSb->ReconfigEvent = NULL;
435   }
436 
437   IpSb->Reconfig = FALSE;
438 
439   if (IpSb->MacString != NULL) {
440     FreePool (IpSb->MacString);
441   }
442 
443   Ip4Config2CleanInstance (&IpSb->Ip4Config2Instance);
444 
445   return EFI_SUCCESS;
446 }
447 
448 /**
449   Callback function which provided by user to remove one node in NetDestroyLinkList process.
450 
451   @param[in]    Entry           The entry to be removed.
452   @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
453 
454   @retval EFI_SUCCESS           The entry has been removed successfully.
455   @retval Others                Fail to remove the entry.
456 
457 **/
458 EFI_STATUS
459 EFIAPI
Ip4DestroyChildEntryInHandleBuffer(IN LIST_ENTRY * Entry,IN VOID * Context)460 Ip4DestroyChildEntryInHandleBuffer (
461   IN LIST_ENTRY         *Entry,
462   IN VOID               *Context
463   )
464 {
465   IP4_PROTOCOL                  *IpInstance;
466   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
467   UINTN                         NumberOfChildren;
468   EFI_HANDLE                    *ChildHandleBuffer;
469 
470   if (Entry == NULL || Context == NULL) {
471     return EFI_INVALID_PARAMETER;
472   }
473 
474   IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP4_PROTOCOL, Link, IP4_PROTOCOL_SIGNATURE);
475   ServiceBinding    = ((IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
476   NumberOfChildren  = ((IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
477   ChildHandleBuffer = ((IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
478 
479   if (!NetIsInHandleBuffer (IpInstance->Handle, NumberOfChildren, ChildHandleBuffer)) {
480     return EFI_SUCCESS;
481   }
482 
483   return ServiceBinding->DestroyChild (ServiceBinding, IpInstance->Handle);
484 }
485 
486 /**
487   Start this driver on ControllerHandle. This service is called by the
488   EFI boot service ConnectController(). In order to make
489   drivers as small as possible, there are a few calling restrictions for
490   this service. ConnectController() must follow these
491   calling restrictions. If any other agent wishes to call Start() it
492   must also follow these calling restrictions.
493 
494   @param[in]  This                 Protocol instance pointer.
495   @param[in]  ControllerHandle     Handle of device to bind driver to
496   @param[in]  RemainingDevicePath  Optional parameter use to pick a specific child
497                                    device to start.
498 
499   @retval EFI_SUCCESS          This driver is added to ControllerHandle
500   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
501   @retval other                This driver does not support this device
502 
503 **/
504 EFI_STATUS
505 EFIAPI
Ip4DriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)506 Ip4DriverBindingStart (
507   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
508   IN EFI_HANDLE                   ControllerHandle,
509   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
510   )
511 {
512   EFI_STATUS                    Status;
513   IP4_SERVICE                   *IpSb;
514 
515   //
516   // Test for the Ip4 service binding protocol
517   //
518   Status = gBS->OpenProtocol (
519                   ControllerHandle,
520                   &gEfiIp4ServiceBindingProtocolGuid,
521                   NULL,
522                   This->DriverBindingHandle,
523                   ControllerHandle,
524                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
525                   );
526 
527   if (Status == EFI_SUCCESS) {
528     return EFI_ALREADY_STARTED;
529   }
530 
531   Status = Ip4CreateService (ControllerHandle, This->DriverBindingHandle, &IpSb);
532 
533   if (EFI_ERROR (Status)) {
534     return Status;
535   }
536 
537   ASSERT (IpSb != NULL);
538 
539   //
540   // Install the Ip4ServiceBinding Protocol onto ControlerHandle
541   //
542   Status = gBS->InstallMultipleProtocolInterfaces (
543                   &ControllerHandle,
544                   &gEfiIp4ServiceBindingProtocolGuid,
545                   &IpSb->ServiceBinding,
546                   &gEfiIp4Config2ProtocolGuid,
547                   &IpSb->Ip4Config2Instance.Ip4Config2,
548                   NULL
549                   );
550 
551   if (EFI_ERROR (Status)) {
552     goto FREE_SERVICE;
553   }
554 
555   //
556   // Ready to go: start the receiving and timer.
557   // Ip4Config2SetPolicy maybe call Ip4ReceiveFrame() to set the default interface's RecvRequest first after
558   // Ip4Config2 instance is initialized. So, EFI_ALREADY_STARTED is the allowed return status.
559   //
560   Status = Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);
561 
562   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
563     goto UNINSTALL_PROTOCOL;
564   }
565 
566   Status = gBS->SetTimer (IpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
567 
568   if (EFI_ERROR (Status)) {
569     goto UNINSTALL_PROTOCOL;
570   }
571 
572   //
573   // Initialize the IP4 ID
574   //
575   mIp4Id = (UINT16)NET_RANDOM (NetRandomInitSeed ());
576 
577   return Status;
578 
579 UNINSTALL_PROTOCOL:
580   gBS->UninstallProtocolInterface (
581          ControllerHandle,
582          &gEfiIp4ServiceBindingProtocolGuid,
583          &IpSb->ServiceBinding
584          );
585 
586 FREE_SERVICE:
587   Ip4CleanService (IpSb);
588   FreePool (IpSb);
589   return Status;
590 }
591 
592 
593 /**
594   Stop this driver on ControllerHandle. This service is called by the
595   EFI boot service DisconnectController(). In order to
596   make drivers as small as possible, there are a few calling
597   restrictions for this service. DisconnectController()
598   must follow these calling restrictions. If any other agent wishes
599   to call Stop() it must also follow these calling restrictions.
600 
601   @param[in]  This              Protocol instance pointer.
602   @param[in]  ControllerHandle  Handle of device to stop driver on
603   @param[in]  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number
604                                 of children is zero stop the entire bus driver.
605   @param[in]  ChildHandleBuffer List of Child Handles to Stop.
606 
607   @retval EFI_SUCCESS           This driver is removed ControllerHandle
608   @retval other                 This driver was not removed from this device
609 
610 **/
611 EFI_STATUS
612 EFIAPI
Ip4DriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)613 Ip4DriverBindingStop (
614   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
615   IN  EFI_HANDLE                   ControllerHandle,
616   IN  UINTN                        NumberOfChildren,
617   IN  EFI_HANDLE                   *ChildHandleBuffer
618   )
619 {
620   EFI_SERVICE_BINDING_PROTOCOL             *ServiceBinding;
621   IP4_SERVICE                              *IpSb;
622   EFI_HANDLE                               NicHandle;
623   EFI_STATUS                               Status;
624   INTN                                     State;
625   LIST_ENTRY                               *List;
626   IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT  Context;
627   IP4_INTERFACE                            *IpIf;
628   IP4_ROUTE_TABLE                          *RouteTable;
629 
630   BOOLEAN                                  IsDhcp4;
631 
632   IsDhcp4   = FALSE;
633 
634   NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
635   if (NicHandle == NULL) {
636     NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid);
637     if (NicHandle == NULL) {
638       NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);
639       if (NicHandle != NULL) {
640         IsDhcp4 = TRUE;
641       } else {
642         return EFI_SUCCESS;
643       }
644     }
645   }
646 
647   Status = gBS->OpenProtocol (
648                   NicHandle,
649                   &gEfiIp4ServiceBindingProtocolGuid,
650                   (VOID **) &ServiceBinding,
651                   This->DriverBindingHandle,
652                   NicHandle,
653                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
654                   );
655   if (EFI_ERROR (Status)) {
656     return EFI_DEVICE_ERROR;
657   }
658 
659   IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
660 
661   if (IsDhcp4) {
662     Status = Ip4Config2DestroyDhcp4 (&IpSb->Ip4Config2Instance);
663     gBS->CloseEvent (IpSb->Ip4Config2Instance.Dhcp4Event);
664     IpSb->Ip4Config2Instance.Dhcp4Event = NULL;
665   } else if (NumberOfChildren != 0) {
666     List = &IpSb->Children;
667     Context.ServiceBinding    = ServiceBinding;
668     Context.NumberOfChildren  = NumberOfChildren;
669     Context.ChildHandleBuffer = ChildHandleBuffer;
670     Status = NetDestroyLinkList (
671                List,
672                Ip4DestroyChildEntryInHandleBuffer,
673                &Context,
674                NULL
675                );
676   } else if (IpSb->DefaultInterface->ArpHandle == ControllerHandle) {
677 
678     //
679     // The ARP protocol for the default interface is being uninstalled and all
680     // its IP child handles should have been destroyed before. So, release the
681     // default interface and route table, create a new one and mark it as not started.
682     //
683     Ip4CancelReceive (IpSb->DefaultInterface);
684     Ip4FreeInterface (IpSb->DefaultInterface, NULL);
685     Ip4FreeRouteTable (IpSb->DefaultRouteTable);
686 
687     IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
688     if (IpIf == NULL) {
689       goto ON_ERROR;
690     }
691     RouteTable = Ip4CreateRouteTable ();
692     if (RouteTable == NULL) {
693       Ip4FreeInterface (IpIf, NULL);
694       goto ON_ERROR;;
695     }
696 
697     IpSb->DefaultInterface  = IpIf;
698     InsertHeadList (&IpSb->Interfaces, &IpIf->Link);
699     IpSb->DefaultRouteTable = RouteTable;
700     Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);
701 
702     IpSb->State = IP4_SERVICE_UNSTARTED;
703 
704   } else if (IsListEmpty (&IpSb->Children)) {
705     State           = IpSb->State;
706     IpSb->State     = IP4_SERVICE_DESTROY;
707 
708     //
709     // OK, clean other resources then uninstall the service binding protocol.
710     //
711     Status = Ip4CleanService (IpSb);
712     if (EFI_ERROR (Status)) {
713       IpSb->State = State;
714       goto ON_ERROR;
715     }
716 
717     gBS->UninstallMultipleProtocolInterfaces (
718            NicHandle,
719            &gEfiIp4ServiceBindingProtocolGuid,
720            ServiceBinding,
721            &gEfiIp4Config2ProtocolGuid,
722            &IpSb->Ip4Config2Instance.Ip4Config2,
723            NULL
724            );
725 
726     if (gIp4ControllerNameTable != NULL) {
727       FreeUnicodeStringTable (gIp4ControllerNameTable);
728       gIp4ControllerNameTable = NULL;
729     }
730     FreePool (IpSb);
731   }
732 
733 ON_ERROR:
734   return Status;
735 }
736 
737 
738 /**
739   Creates a child handle and installs a protocol.
740 
741   The CreateChild() function installs a protocol on ChildHandle.
742   If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
743   If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
744 
745   @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
746   @param  ChildHandle Pointer to the handle of the child to create. If it is NULL,
747                       then a new handle is created. If it is a pointer to an existing UEFI handle,
748                       then the protocol is added to the existing UEFI handle.
749 
750   @retval EFI_SUCCES            The protocol was added to ChildHandle.
751   @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
752   @retval EFI_OUT_OF_RESOURCES  There are not enough resources availabe to create
753                                 the child
754   @retval other                 The child handle was not created
755 
756 **/
757 EFI_STATUS
758 EFIAPI
Ip4ServiceBindingCreateChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN OUT EFI_HANDLE * ChildHandle)759 Ip4ServiceBindingCreateChild (
760   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
761   IN OUT EFI_HANDLE                *ChildHandle
762   )
763 {
764   IP4_SERVICE               *IpSb;
765   IP4_PROTOCOL              *IpInstance;
766   EFI_TPL                   OldTpl;
767   EFI_STATUS                Status;
768   VOID                      *Mnp;
769 
770   if ((This == NULL) || (ChildHandle == NULL)) {
771     return EFI_INVALID_PARAMETER;
772   }
773 
774   IpSb       = IP4_SERVICE_FROM_PROTOCOL (This);
775   IpInstance = AllocatePool (sizeof (IP4_PROTOCOL));
776 
777   if (IpInstance == NULL) {
778     return EFI_OUT_OF_RESOURCES;
779   }
780 
781   Ip4InitProtocol (IpSb, IpInstance);
782 
783   //
784   // Install Ip4 onto ChildHandle
785   //
786   Status = gBS->InstallMultipleProtocolInterfaces (
787                   ChildHandle,
788                   &gEfiIp4ProtocolGuid,
789                   &IpInstance->Ip4Proto,
790                   NULL
791                   );
792 
793   if (EFI_ERROR (Status)) {
794     goto ON_ERROR;
795   }
796 
797   IpInstance->Handle = *ChildHandle;
798 
799   //
800   // Open the Managed Network protocol BY_CHILD.
801   //
802   Status = gBS->OpenProtocol (
803                   IpSb->MnpChildHandle,
804                   &gEfiManagedNetworkProtocolGuid,
805                   (VOID **) &Mnp,
806                   gIp4DriverBinding.DriverBindingHandle,
807                   IpInstance->Handle,
808                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
809                   );
810   if (EFI_ERROR (Status)) {
811     gBS->UninstallMultipleProtocolInterfaces (
812            ChildHandle,
813            &gEfiIp4ProtocolGuid,
814            &IpInstance->Ip4Proto,
815            NULL
816            );
817 
818     goto ON_ERROR;
819   }
820 
821   //
822   // Insert it into the service binding instance.
823   //
824   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
825 
826   InsertTailList (&IpSb->Children, &IpInstance->Link);
827   IpSb->NumChildren++;
828 
829   gBS->RestoreTPL (OldTpl);
830 
831 ON_ERROR:
832 
833   if (EFI_ERROR (Status)) {
834 
835     Ip4CleanProtocol (IpInstance);
836 
837     FreePool (IpInstance);
838   }
839 
840   return Status;
841 }
842 
843 
844 /**
845   Destroys a child handle with a protocol installed on it.
846 
847   The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
848   that was installed by CreateChild() from ChildHandle. If the removed protocol is the
849   last protocol on ChildHandle, then ChildHandle is destroyed.
850 
851   @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
852   @param  ChildHandle Handle of the child to destroy
853 
854   @retval EFI_SUCCES            The protocol was removed from ChildHandle.
855   @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.
856   @retval EFI_INVALID_PARAMETER Child handle is NULL.
857   @retval EFI_ACCESS_DENIED     The protocol could not be removed from the ChildHandle
858                                 because its services are being used.
859   @retval other                 The child handle was not destroyed
860 
861 **/
862 EFI_STATUS
863 EFIAPI
Ip4ServiceBindingDestroyChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN EFI_HANDLE ChildHandle)864 Ip4ServiceBindingDestroyChild (
865   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
866   IN EFI_HANDLE                    ChildHandle
867   )
868 {
869   EFI_STATUS                Status;
870   IP4_SERVICE               *IpSb;
871   IP4_PROTOCOL              *IpInstance;
872   EFI_IP4_PROTOCOL          *Ip4;
873   EFI_TPL                   OldTpl;
874   INTN                      State;
875 
876   if ((This == NULL) || (ChildHandle == NULL)) {
877     return EFI_INVALID_PARAMETER;
878   }
879 
880   //
881   // Retrieve the private context data structures
882   //
883   IpSb   = IP4_SERVICE_FROM_PROTOCOL (This);
884 
885   Status = gBS->OpenProtocol (
886                   ChildHandle,
887                   &gEfiIp4ProtocolGuid,
888                   (VOID **) &Ip4,
889                   gIp4DriverBinding.DriverBindingHandle,
890                   ChildHandle,
891                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
892                   );
893 
894   if (EFI_ERROR (Status)) {
895     return EFI_UNSUPPORTED;
896   }
897 
898   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (Ip4);
899 
900   if (IpInstance->Service != IpSb) {
901     return EFI_INVALID_PARAMETER;
902   }
903 
904   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
905 
906   //
907   // A child can be destroyed more than once. For example,
908   // Ip4DriverBindingStop will destroy all of its children.
909   // when UDP driver is being stopped, it will destroy all
910   // the IP child it opens.
911   //
912   if (IpInstance->State == IP4_STATE_DESTROY) {
913     gBS->RestoreTPL (OldTpl);
914     return EFI_SUCCESS;
915   }
916 
917   State             = IpInstance->State;
918   IpInstance->State = IP4_STATE_DESTROY;
919 
920   //
921   // Close the Managed Network protocol.
922   //
923   gBS->CloseProtocol (
924          IpSb->MnpChildHandle,
925          &gEfiManagedNetworkProtocolGuid,
926          gIp4DriverBinding.DriverBindingHandle,
927          ChildHandle
928          );
929 
930   if (IpInstance->Interface != NULL && IpInstance->Interface->Arp != NULL) {
931     gBS->CloseProtocol (
932            IpInstance->Interface->ArpHandle,
933            &gEfiArpProtocolGuid,
934            gIp4DriverBinding.DriverBindingHandle,
935            ChildHandle
936            );
937   }
938 
939   //
940   // Uninstall the IP4 protocol first. Many thing happens during
941   // this:
942   // 1. The consumer of the IP4 protocol will be stopped if it
943   // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
944   // stopped, IP driver's stop function will be called, and uninstall
945   // EFI_IP4_PROTOCOL will trigger the UDP's stop function. This
946   // makes it possible to create the network stack bottom up, and
947   // stop it top down.
948   // 2. the upper layer will recycle the received packet. The recycle
949   // event's TPL is higher than this function. The recycle events
950   // will be called back before preceeding. If any packets not recycled,
951   // that means there is a resource leak.
952   //
953   gBS->RestoreTPL (OldTpl);
954   Status = gBS->UninstallProtocolInterface (
955                   ChildHandle,
956                   &gEfiIp4ProtocolGuid,
957                   &IpInstance->Ip4Proto
958                   );
959   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
960   if (EFI_ERROR (Status)) {
961     goto ON_ERROR;
962   }
963 
964   Status = Ip4CleanProtocol (IpInstance);
965   if (EFI_ERROR (Status)) {
966     gBS->InstallMultipleProtocolInterfaces (
967            &ChildHandle,
968            &gEfiIp4ProtocolGuid,
969            Ip4,
970            NULL
971            );
972 
973     goto ON_ERROR;
974   }
975 
976   RemoveEntryList (&IpInstance->Link);
977   IpSb->NumChildren--;
978 
979   gBS->RestoreTPL (OldTpl);
980 
981   FreePool (IpInstance);
982   return EFI_SUCCESS;
983 
984 ON_ERROR:
985   IpInstance->State = State;
986   gBS->RestoreTPL (OldTpl);
987 
988   return Status;
989 }
990