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