• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   The driver binding and service binding protocol for IP4 driver.
3 
4 Copyright (c) 2005 - 2016, 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, ReconfigEvent 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 = gBS->CreateEvent (
280                   EVT_NOTIFY_SIGNAL,
281                   TPL_NOTIFY,
282                   Ip4AutoReconfigCallBack,
283                   IpSb,
284                   &IpSb->ReconfigEvent
285                   );
286   if (EFI_ERROR (Status)) {
287     goto ON_ERROR;
288   }
289 
290   Status = NetLibCreateServiceChild (
291              Controller,
292              ImageHandle,
293              &gEfiManagedNetworkServiceBindingProtocolGuid,
294              &IpSb->MnpChildHandle
295              );
296 
297   if (EFI_ERROR (Status)) {
298     goto ON_ERROR;
299   }
300 
301   Status = gBS->OpenProtocol (
302                   IpSb->MnpChildHandle,
303                   &gEfiManagedNetworkProtocolGuid,
304                   (VOID **) &IpSb->Mnp,
305                   ImageHandle,
306                   Controller,
307                   EFI_OPEN_PROTOCOL_BY_DRIVER
308                   );
309 
310   if (EFI_ERROR (Status)) {
311     goto ON_ERROR;
312   }
313 
314   Status = Ip4ServiceConfigMnp (IpSb, TRUE);
315 
316   if (EFI_ERROR (Status)) {
317     goto ON_ERROR;
318   }
319 
320   Status = IpSb->Mnp->GetModeData (IpSb->Mnp, NULL, &IpSb->SnpMode);
321 
322   if (EFI_ERROR (Status)) {
323     goto ON_ERROR;
324   }
325 
326   Status = Ip4InitIgmp (IpSb);
327 
328   if (EFI_ERROR (Status)) {
329     goto ON_ERROR;
330   }
331 
332   IpSb->MacString = NULL;
333   Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &IpSb->MacString);
334 
335   if (EFI_ERROR (Status)) {
336     goto ON_ERROR;
337   }
338 
339   IpSb->DefaultInterface = Ip4CreateInterface (IpSb->Mnp, Controller, ImageHandle);
340 
341   if (IpSb->DefaultInterface == NULL) {
342     Status = EFI_OUT_OF_RESOURCES;
343     goto ON_ERROR;
344   }
345 
346   InsertHeadList (&IpSb->Interfaces, &IpSb->DefaultInterface->Link);
347 
348   ZeroMem (&IpSb->Ip4Config2Instance, sizeof (IP4_CONFIG2_INSTANCE));
349 
350   Status = Ip4Config2InitInstance (&IpSb->Ip4Config2Instance);
351 
352   if (EFI_ERROR (Status)) {
353     goto ON_ERROR;
354   }
355 
356   IpSb->MaxPacketSize = IpSb->SnpMode.MaxPacketSize - sizeof (IP4_HEAD);
357   if (NetLibGetVlanId (IpSb->Controller) != 0) {
358     //
359     // This is a VLAN device, reduce MTU by VLAN tag length
360     //
361     IpSb->MaxPacketSize -= NET_VLAN_TAG_LEN;
362   }
363   IpSb->OldMaxPacketSize = IpSb->MaxPacketSize;
364   *Service = IpSb;
365 
366   return EFI_SUCCESS;
367 
368 ON_ERROR:
369   Ip4CleanService (IpSb);
370   FreePool (IpSb);
371 
372   return Status;
373 }
374 
375 
376 /**
377   Clean up a IP4 service binding instance. It will release all
378   the resource allocated by the instance. The instance may be
379   partly initialized, or partly destroyed. If a resource is
380   destroyed, it is marked as that in case the destroy failed and
381   being called again later.
382 
383   @param[in]  IpSb               The IP4 service binding instance to clean up
384 
385   @retval EFI_SUCCESS            The resource used by the instance are cleaned up
386   @retval other                  Failed to clean up some of the resources.
387 
388 **/
389 EFI_STATUS
Ip4CleanService(IN IP4_SERVICE * IpSb)390 Ip4CleanService (
391   IN IP4_SERVICE            *IpSb
392   )
393 {
394   EFI_STATUS                Status;
395 
396   IpSb->State     = IP4_SERVICE_DESTROY;
397 
398   if (IpSb->Timer != NULL) {
399     gBS->SetTimer (IpSb->Timer, TimerCancel, 0);
400     gBS->CloseEvent (IpSb->Timer);
401 
402     IpSb->Timer = NULL;
403   }
404 
405   if (IpSb->DefaultInterface != NULL) {
406     Status = Ip4FreeInterface (IpSb->DefaultInterface, NULL);
407 
408     if (EFI_ERROR (Status)) {
409       return Status;
410     }
411 
412     IpSb->DefaultInterface = NULL;
413   }
414 
415   if (IpSb->DefaultRouteTable != NULL) {
416     Ip4FreeRouteTable (IpSb->DefaultRouteTable);
417     IpSb->DefaultRouteTable = NULL;
418   }
419 
420   Ip4CleanAssembleTable (&IpSb->Assemble);
421 
422   if (IpSb->MnpChildHandle != NULL) {
423     if (IpSb->Mnp != NULL) {
424       gBS->CloseProtocol (
425              IpSb->MnpChildHandle,
426              &gEfiManagedNetworkProtocolGuid,
427              IpSb->Image,
428              IpSb->Controller
429              );
430 
431       IpSb->Mnp = NULL;
432     }
433 
434     NetLibDestroyServiceChild (
435       IpSb->Controller,
436       IpSb->Image,
437       &gEfiManagedNetworkServiceBindingProtocolGuid,
438       IpSb->MnpChildHandle
439       );
440 
441     IpSb->MnpChildHandle = NULL;
442   }
443 
444   if (IpSb->ReconfigEvent != NULL) {
445     gBS->CloseEvent (IpSb->ReconfigEvent);
446 
447     IpSb->ReconfigEvent = NULL;
448   }
449 
450   IpSb->Reconfig = FALSE;
451 
452   if (IpSb->MacString != NULL) {
453     FreePool (IpSb->MacString);
454   }
455 
456   Ip4Config2CleanInstance (&IpSb->Ip4Config2Instance);
457 
458   return EFI_SUCCESS;
459 }
460 
461 /**
462   Callback function which provided by user to remove one node in NetDestroyLinkList process.
463 
464   @param[in]    Entry           The entry to be removed.
465   @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
466 
467   @retval EFI_SUCCESS           The entry has been removed successfully.
468   @retval Others                Fail to remove the entry.
469 
470 **/
471 EFI_STATUS
472 EFIAPI
Ip4DestroyChildEntryInHandleBuffer(IN LIST_ENTRY * Entry,IN VOID * Context)473 Ip4DestroyChildEntryInHandleBuffer (
474   IN LIST_ENTRY         *Entry,
475   IN VOID               *Context
476   )
477 {
478   IP4_PROTOCOL                  *IpInstance;
479   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
480   UINTN                         NumberOfChildren;
481   EFI_HANDLE                    *ChildHandleBuffer;
482 
483   if (Entry == NULL || Context == NULL) {
484     return EFI_INVALID_PARAMETER;
485   }
486 
487   IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP4_PROTOCOL, Link, IP4_PROTOCOL_SIGNATURE);
488   ServiceBinding    = ((IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
489   NumberOfChildren  = ((IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
490   ChildHandleBuffer = ((IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
491 
492   if (!NetIsInHandleBuffer (IpInstance->Handle, NumberOfChildren, ChildHandleBuffer)) {
493     return EFI_SUCCESS;
494   }
495 
496   return ServiceBinding->DestroyChild (ServiceBinding, IpInstance->Handle);
497 }
498 
499 /**
500   Start this driver on ControllerHandle. This service is called by the
501   EFI boot service ConnectController(). In order to make
502   drivers as small as possible, there are a few calling restrictions for
503   this service. ConnectController() must follow these
504   calling restrictions. If any other agent wishes to call Start() it
505   must also follow these calling restrictions.
506 
507   @param[in]  This                 Protocol instance pointer.
508   @param[in]  ControllerHandle     Handle of device to bind driver to
509   @param[in]  RemainingDevicePath  Optional parameter use to pick a specific child
510                                    device to start.
511 
512   @retval EFI_SUCCESS          This driver is added to ControllerHandle
513   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
514   @retval other                This driver does not support this device
515 
516 **/
517 EFI_STATUS
518 EFIAPI
Ip4DriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)519 Ip4DriverBindingStart (
520   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
521   IN EFI_HANDLE                   ControllerHandle,
522   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
523   )
524 {
525   EFI_STATUS                    Status;
526   IP4_SERVICE                   *IpSb;
527   EFI_IP4_CONFIG2_PROTOCOL      *Ip4Cfg2;
528   UINTN                         Index;
529   IP4_CONFIG2_DATA_ITEM         *DataItem;
530 
531   IpSb     = NULL;
532   Ip4Cfg2  = NULL;
533   DataItem = NULL;
534 
535   //
536   // Test for the Ip4 service binding protocol
537   //
538   Status = gBS->OpenProtocol (
539                   ControllerHandle,
540                   &gEfiIp4ServiceBindingProtocolGuid,
541                   NULL,
542                   This->DriverBindingHandle,
543                   ControllerHandle,
544                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
545                   );
546 
547   if (Status == EFI_SUCCESS) {
548     return EFI_ALREADY_STARTED;
549   }
550 
551   Status = Ip4CreateService (ControllerHandle, This->DriverBindingHandle, &IpSb);
552 
553   if (EFI_ERROR (Status)) {
554     return Status;
555   }
556 
557   ASSERT (IpSb != NULL);
558 
559   Ip4Cfg2  = &IpSb->Ip4Config2Instance.Ip4Config2;
560 
561   //
562   // Install the Ip4ServiceBinding Protocol onto ControlerHandle
563   //
564   Status = gBS->InstallMultipleProtocolInterfaces (
565                   &ControllerHandle,
566                   &gEfiIp4ServiceBindingProtocolGuid,
567                   &IpSb->ServiceBinding,
568                   &gEfiIp4Config2ProtocolGuid,
569                   Ip4Cfg2,
570                   NULL
571                   );
572 
573   if (EFI_ERROR (Status)) {
574     goto FREE_SERVICE;
575   }
576 
577   //
578   // Read the config data from NV variable again.
579   // The default data can be changed by other drivers.
580   //
581   Status = Ip4Config2ReadConfigData (IpSb->MacString, &IpSb->Ip4Config2Instance);
582   if (EFI_ERROR (Status)) {
583     goto UNINSTALL_PROTOCOL;
584   }
585 
586   //
587   // Consume the installed EFI_IP4_CONFIG2_PROTOCOL to set the default data items.
588   //
589   for (Index = Ip4Config2DataTypePolicy; Index < Ip4Config2DataTypeMaximum; Index++) {
590     DataItem = &IpSb->Ip4Config2Instance.DataItem[Index];
591     if (DataItem->Data.Ptr != NULL) {
592       Status = Ip4Cfg2->SetData (
593                           Ip4Cfg2,
594                           Index,
595                           DataItem->DataSize,
596                           DataItem->Data.Ptr
597                           );
598       if (EFI_ERROR(Status)) {
599         goto UNINSTALL_PROTOCOL;
600       }
601 
602       if (Index == Ip4Config2DataTypePolicy && (*(DataItem->Data.Policy) == Ip4Config2PolicyDhcp)) {
603         break;
604       }
605     }
606   }
607 
608   //
609   // Ready to go: start the receiving and timer.
610   // Ip4Config2SetPolicy maybe call Ip4ReceiveFrame() to set the default interface's RecvRequest first after
611   // Ip4Config2 instance is initialized. So, EFI_ALREADY_STARTED is the allowed return status.
612   //
613   Status = Ip4ReceiveFrame (IpSb->DefaultInterface, NULL, Ip4AccpetFrame, IpSb);
614 
615   if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
616     goto UNINSTALL_PROTOCOL;
617   }
618 
619   Status = gBS->SetTimer (IpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
620 
621   if (EFI_ERROR (Status)) {
622     goto UNINSTALL_PROTOCOL;
623   }
624 
625   //
626   // Initialize the IP4 ID
627   //
628   mIp4Id = (UINT16)NET_RANDOM (NetRandomInitSeed ());
629 
630   return Status;
631 
632 UNINSTALL_PROTOCOL:
633   gBS->UninstallProtocolInterface (
634          ControllerHandle,
635          &gEfiIp4ServiceBindingProtocolGuid,
636          &IpSb->ServiceBinding
637          );
638 
639 FREE_SERVICE:
640   Ip4CleanService (IpSb);
641   FreePool (IpSb);
642   return Status;
643 }
644 
645 
646 /**
647   Stop this driver on ControllerHandle. This service is called by the
648   EFI boot service DisconnectController(). In order to
649   make drivers as small as possible, there are a few calling
650   restrictions for this service. DisconnectController()
651   must follow these calling restrictions. If any other agent wishes
652   to call Stop() it must also follow these calling restrictions.
653 
654   @param[in]  This              Protocol instance pointer.
655   @param[in]  ControllerHandle  Handle of device to stop driver on
656   @param[in]  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number
657                                 of children is zero stop the entire bus driver.
658   @param[in]  ChildHandleBuffer List of Child Handles to Stop.
659 
660   @retval EFI_SUCCESS           This driver is removed ControllerHandle
661   @retval other                 This driver was not removed from this device
662 
663 **/
664 EFI_STATUS
665 EFIAPI
Ip4DriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)666 Ip4DriverBindingStop (
667   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
668   IN  EFI_HANDLE                   ControllerHandle,
669   IN  UINTN                        NumberOfChildren,
670   IN  EFI_HANDLE                   *ChildHandleBuffer
671   )
672 {
673   EFI_SERVICE_BINDING_PROTOCOL             *ServiceBinding;
674   IP4_SERVICE                              *IpSb;
675   EFI_HANDLE                               NicHandle;
676   EFI_STATUS                               Status;
677   INTN                                     State;
678   LIST_ENTRY                               *List;
679   IP4_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT  Context;
680   IP4_INTERFACE                            *IpIf;
681   IP4_ROUTE_TABLE                          *RouteTable;
682 
683   BOOLEAN                                  IsDhcp4;
684 
685   IsDhcp4   = FALSE;
686 
687   NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiManagedNetworkProtocolGuid);
688   if (NicHandle == NULL) {
689     NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid);
690     if (NicHandle == NULL) {
691       NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4ProtocolGuid);
692       if (NicHandle != NULL) {
693         IsDhcp4 = TRUE;
694       } else {
695         return EFI_SUCCESS;
696       }
697     }
698   }
699 
700   Status = gBS->OpenProtocol (
701                   NicHandle,
702                   &gEfiIp4ServiceBindingProtocolGuid,
703                   (VOID **) &ServiceBinding,
704                   This->DriverBindingHandle,
705                   NicHandle,
706                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
707                   );
708   if (EFI_ERROR (Status)) {
709     return EFI_DEVICE_ERROR;
710   }
711 
712   IpSb = IP4_SERVICE_FROM_PROTOCOL (ServiceBinding);
713 
714   if (IsDhcp4) {
715     Status = Ip4Config2DestroyDhcp4 (&IpSb->Ip4Config2Instance);
716     gBS->CloseEvent (IpSb->Ip4Config2Instance.Dhcp4Event);
717     IpSb->Ip4Config2Instance.Dhcp4Event = NULL;
718   } else if (NumberOfChildren != 0) {
719     List = &IpSb->Children;
720     Context.ServiceBinding    = ServiceBinding;
721     Context.NumberOfChildren  = NumberOfChildren;
722     Context.ChildHandleBuffer = ChildHandleBuffer;
723     Status = NetDestroyLinkList (
724                List,
725                Ip4DestroyChildEntryInHandleBuffer,
726                &Context,
727                NULL
728                );
729   } else if (IpSb->DefaultInterface->ArpHandle == ControllerHandle) {
730 
731     //
732     // The ARP protocol for the default interface is being uninstalled and all
733     // its IP child handles should have been destroyed before. So, release the
734     // default interface and route table, create a new one and mark it as not started.
735     //
736     Ip4CancelReceive (IpSb->DefaultInterface);
737     Ip4FreeInterface (IpSb->DefaultInterface, NULL);
738     Ip4FreeRouteTable (IpSb->DefaultRouteTable);
739 
740     IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
741     if (IpIf == NULL) {
742       goto ON_ERROR;
743     }
744     RouteTable = Ip4CreateRouteTable ();
745     if (RouteTable == NULL) {
746       Ip4FreeInterface (IpIf, NULL);
747       goto ON_ERROR;;
748     }
749 
750     IpSb->DefaultInterface  = IpIf;
751     InsertHeadList (&IpSb->Interfaces, &IpIf->Link);
752     IpSb->DefaultRouteTable = RouteTable;
753     Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);
754 
755     IpSb->State = IP4_SERVICE_UNSTARTED;
756 
757   } else if (IsListEmpty (&IpSb->Children)) {
758     State           = IpSb->State;
759     //
760     // OK, clean other resources then uninstall the service binding protocol.
761     //
762     Status = Ip4CleanService (IpSb);
763     if (EFI_ERROR (Status)) {
764       IpSb->State = State;
765       goto ON_ERROR;
766     }
767 
768     gBS->UninstallMultipleProtocolInterfaces (
769            NicHandle,
770            &gEfiIp4ServiceBindingProtocolGuid,
771            ServiceBinding,
772            &gEfiIp4Config2ProtocolGuid,
773            &IpSb->Ip4Config2Instance.Ip4Config2,
774            NULL
775            );
776 
777     if (gIp4ControllerNameTable != NULL) {
778       FreeUnicodeStringTable (gIp4ControllerNameTable);
779       gIp4ControllerNameTable = NULL;
780     }
781     FreePool (IpSb);
782   }
783 
784 ON_ERROR:
785   return Status;
786 }
787 
788 
789 /**
790   Creates a child handle and installs a protocol.
791 
792   The CreateChild() function installs a protocol on ChildHandle.
793   If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
794   If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
795 
796   @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
797   @param  ChildHandle Pointer to the handle of the child to create. If it is NULL,
798                       then a new handle is created. If it is a pointer to an existing UEFI handle,
799                       then the protocol is added to the existing UEFI handle.
800 
801   @retval EFI_SUCCES            The protocol was added to ChildHandle.
802   @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
803   @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to create
804                                 the child
805   @retval other                 The child handle was not created
806 
807 **/
808 EFI_STATUS
809 EFIAPI
Ip4ServiceBindingCreateChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN OUT EFI_HANDLE * ChildHandle)810 Ip4ServiceBindingCreateChild (
811   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
812   IN OUT EFI_HANDLE                *ChildHandle
813   )
814 {
815   IP4_SERVICE               *IpSb;
816   IP4_PROTOCOL              *IpInstance;
817   EFI_TPL                   OldTpl;
818   EFI_STATUS                Status;
819   VOID                      *Mnp;
820 
821   if ((This == NULL) || (ChildHandle == NULL)) {
822     return EFI_INVALID_PARAMETER;
823   }
824 
825   IpSb       = IP4_SERVICE_FROM_PROTOCOL (This);
826   IpInstance = AllocatePool (sizeof (IP4_PROTOCOL));
827 
828   if (IpInstance == NULL) {
829     return EFI_OUT_OF_RESOURCES;
830   }
831 
832   Ip4InitProtocol (IpSb, IpInstance);
833 
834   //
835   // Install Ip4 onto ChildHandle
836   //
837   Status = gBS->InstallMultipleProtocolInterfaces (
838                   ChildHandle,
839                   &gEfiIp4ProtocolGuid,
840                   &IpInstance->Ip4Proto,
841                   NULL
842                   );
843 
844   if (EFI_ERROR (Status)) {
845     goto ON_ERROR;
846   }
847 
848   IpInstance->Handle = *ChildHandle;
849 
850   //
851   // Open the Managed Network protocol BY_CHILD.
852   //
853   Status = gBS->OpenProtocol (
854                   IpSb->MnpChildHandle,
855                   &gEfiManagedNetworkProtocolGuid,
856                   (VOID **) &Mnp,
857                   gIp4DriverBinding.DriverBindingHandle,
858                   IpInstance->Handle,
859                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
860                   );
861   if (EFI_ERROR (Status)) {
862     gBS->UninstallMultipleProtocolInterfaces (
863            ChildHandle,
864            &gEfiIp4ProtocolGuid,
865            &IpInstance->Ip4Proto,
866            NULL
867            );
868 
869     goto ON_ERROR;
870   }
871 
872   //
873   // Insert it into the service binding instance.
874   //
875   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
876 
877   InsertTailList (&IpSb->Children, &IpInstance->Link);
878   IpSb->NumChildren++;
879 
880   gBS->RestoreTPL (OldTpl);
881 
882 ON_ERROR:
883 
884   if (EFI_ERROR (Status)) {
885 
886     Ip4CleanProtocol (IpInstance);
887 
888     FreePool (IpInstance);
889   }
890 
891   return Status;
892 }
893 
894 
895 /**
896   Destroys a child handle with a protocol installed on it.
897 
898   The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
899   that was installed by CreateChild() from ChildHandle. If the removed protocol is the
900   last protocol on ChildHandle, then ChildHandle is destroyed.
901 
902   @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
903   @param  ChildHandle Handle of the child to destroy
904 
905   @retval EFI_SUCCES            The protocol was removed from ChildHandle.
906   @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.
907   @retval EFI_INVALID_PARAMETER Child handle is NULL.
908   @retval EFI_ACCESS_DENIED     The protocol could not be removed from the ChildHandle
909                                 because its services are being used.
910   @retval other                 The child handle was not destroyed
911 
912 **/
913 EFI_STATUS
914 EFIAPI
Ip4ServiceBindingDestroyChild(IN EFI_SERVICE_BINDING_PROTOCOL * This,IN EFI_HANDLE ChildHandle)915 Ip4ServiceBindingDestroyChild (
916   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
917   IN EFI_HANDLE                    ChildHandle
918   )
919 {
920   EFI_STATUS                Status;
921   IP4_SERVICE               *IpSb;
922   IP4_PROTOCOL              *IpInstance;
923   EFI_IP4_PROTOCOL          *Ip4;
924   EFI_TPL                   OldTpl;
925   INTN                      State;
926 
927   if ((This == NULL) || (ChildHandle == NULL)) {
928     return EFI_INVALID_PARAMETER;
929   }
930 
931   //
932   // Retrieve the private context data structures
933   //
934   IpSb   = IP4_SERVICE_FROM_PROTOCOL (This);
935 
936   Status = gBS->OpenProtocol (
937                   ChildHandle,
938                   &gEfiIp4ProtocolGuid,
939                   (VOID **) &Ip4,
940                   gIp4DriverBinding.DriverBindingHandle,
941                   ChildHandle,
942                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
943                   );
944 
945   if (EFI_ERROR (Status)) {
946     return EFI_UNSUPPORTED;
947   }
948 
949   IpInstance = IP4_INSTANCE_FROM_PROTOCOL (Ip4);
950 
951   if (IpInstance->Service != IpSb) {
952     return EFI_INVALID_PARAMETER;
953   }
954 
955   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
956 
957   //
958   // A child can be destroyed more than once. For example,
959   // Ip4DriverBindingStop will destroy all of its children.
960   // when UDP driver is being stopped, it will destroy all
961   // the IP child it opens.
962   //
963   if (IpInstance->State == IP4_STATE_DESTROY) {
964     gBS->RestoreTPL (OldTpl);
965     return EFI_SUCCESS;
966   }
967 
968   State             = IpInstance->State;
969   IpInstance->State = IP4_STATE_DESTROY;
970 
971   //
972   // Close the Managed Network protocol.
973   //
974   gBS->CloseProtocol (
975          IpSb->MnpChildHandle,
976          &gEfiManagedNetworkProtocolGuid,
977          gIp4DriverBinding.DriverBindingHandle,
978          ChildHandle
979          );
980 
981   if (IpInstance->Interface != NULL && IpInstance->Interface->Arp != NULL) {
982     gBS->CloseProtocol (
983            IpInstance->Interface->ArpHandle,
984            &gEfiArpProtocolGuid,
985            gIp4DriverBinding.DriverBindingHandle,
986            ChildHandle
987            );
988   }
989 
990   //
991   // Uninstall the IP4 protocol first. Many thing happens during
992   // this:
993   // 1. The consumer of the IP4 protocol will be stopped if it
994   // opens the protocol BY_DRIVER. For eaxmple, if MNP driver is
995   // stopped, IP driver's stop function will be called, and uninstall
996   // EFI_IP4_PROTOCOL will trigger the UDP's stop function. This
997   // makes it possible to create the network stack bottom up, and
998   // stop it top down.
999   // 2. the upper layer will recycle the received packet. The recycle
1000   // event's TPL is higher than this function. The recycle events
1001   // will be called back before preceeding. If any packets not recycled,
1002   // that means there is a resource leak.
1003   //
1004   gBS->RestoreTPL (OldTpl);
1005   Status = gBS->UninstallProtocolInterface (
1006                   ChildHandle,
1007                   &gEfiIp4ProtocolGuid,
1008                   &IpInstance->Ip4Proto
1009                   );
1010   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1011   if (EFI_ERROR (Status)) {
1012     goto ON_ERROR;
1013   }
1014 
1015   Status = Ip4CleanProtocol (IpInstance);
1016   if (EFI_ERROR (Status)) {
1017     gBS->InstallMultipleProtocolInterfaces (
1018            &ChildHandle,
1019            &gEfiIp4ProtocolGuid,
1020            Ip4,
1021            NULL
1022            );
1023 
1024     goto ON_ERROR;
1025   }
1026 
1027   RemoveEntryList (&IpInstance->Link);
1028   IpSb->NumChildren--;
1029 
1030   gBS->RestoreTPL (OldTpl);
1031 
1032   FreePool (IpInstance);
1033   return EFI_SUCCESS;
1034 
1035 ON_ERROR:
1036   IpInstance->State = State;
1037   gBS->RestoreTPL (OldTpl);
1038 
1039   return Status;
1040 }
1041