1. Enable Network stack to pass SCT, currently MNP, ARP, IP4, TCP4 and DHCP4 have...
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Dhcp4Dxe / Dhcp4Driver.c
1 /** @file\r
2 \r
3 Copyright (c) 2006 - 2007, 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 \r
13 Module Name:\r
14 \r
15   Dhcp4Driver.c\r
16 \r
17 Abstract:\r
18 \r
19 \r
20 **/\r
21 \r
22 #include "Dhcp4Impl.h"\r
23 #include "Dhcp4Driver.h"\r
24 \r
25 EFI_DRIVER_BINDING_PROTOCOL gDhcp4DriverBinding = {\r
26   Dhcp4DriverBindingSupported,\r
27   Dhcp4DriverBindingStart,\r
28   Dhcp4DriverBindingStop,\r
29   0xa,\r
30   NULL,\r
31   NULL\r
32 };\r
33 \r
34 EFI_SERVICE_BINDING_PROTOCOL mDhcp4ServiceBindingTemplete = {\r
35   Dhcp4ServiceBindingCreateChild,\r
36   Dhcp4ServiceBindingDestroyChild\r
37 };\r
38 \r
39 \r
40 EFI_STATUS\r
41 EFIAPI\r
42 Dhcp4DriverEntryPoint (\r
43   IN EFI_HANDLE             ImageHandle,\r
44   IN EFI_SYSTEM_TABLE       *SystemTable\r
45   )\r
46 /*++\r
47 \r
48 Routine Description:\r
49 \r
50   Entry point of the DHCP driver to install various protocols.\r
51 \r
52 Arguments:\r
53 \r
54   ImageHandle - The driver's image handle\r
55   SystemTable - The system table\r
56 \r
57 Returns:\r
58 \r
59   EFI_SUCCESS - All the related protocols are installed.\r
60   Others      - Failed to install the protocols.\r
61 \r
62 --*/\r
63 {\r
64   return NetLibInstallAllDriverProtocols (\r
65            ImageHandle,\r
66            SystemTable,\r
67            &gDhcp4DriverBinding,\r
68            ImageHandle,\r
69            &gDhcp4ComponentName,\r
70            NULL,\r
71            NULL\r
72            );\r
73 }\r
74 \r
75 \r
76 /**\r
77   Test to see if DHCP driver supports the ControllerHandle.\r
78 \r
79   @param  This                   Protocol instance pointer.\r
80   @param  ControllerHandle       Handle of device to test\r
81   @param  RemainingDevicePath    Optional parameter use to pick a specific child\r
82                                  device to start.\r
83 \r
84   @retval EFI_SUCCES             This driver supports this device\r
85   @retval other                  This driver does not support this device\r
86 \r
87 **/\r
88 EFI_STATUS\r
89 EFIAPI\r
90 Dhcp4DriverBindingSupported (\r
91   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
92   IN EFI_HANDLE                   ControllerHandle,\r
93   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
94   )\r
95 {\r
96   EFI_STATUS  Status;\r
97 \r
98   Status = gBS->OpenProtocol (\r
99                   ControllerHandle,\r
100                   &gEfiUdp4ServiceBindingProtocolGuid,\r
101                   NULL,\r
102                   This->DriverBindingHandle,\r
103                   ControllerHandle,\r
104                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
105                   );\r
106 \r
107   return Status;\r
108 }\r
109 \r
110 \r
111 \r
112 /**\r
113   Configure the default UDP child to receive all the DHCP traffics\r
114   on this network interface.\r
115 \r
116   @param  UdpIo                  The UDP IO port to configure\r
117   @param  Context                The context to the function\r
118 \r
119   @retval EFI_SUCCESS            The UDP IO port is successfully configured.\r
120   @retval Others                 Failed to configure the UDP child.\r
121 \r
122 **/\r
123 EFI_STATUS\r
124 DhcpConfigUdpIo (\r
125   IN UDP_IO_PORT            *UdpIo,\r
126   IN VOID                   *Context\r
127   )\r
128 {\r
129   EFI_UDP4_CONFIG_DATA      UdpConfigData;\r
130 \r
131   UdpConfigData.AcceptBroadcast           = TRUE;\r
132   UdpConfigData.AcceptPromiscuous         = FALSE;\r
133   UdpConfigData.AcceptAnyPort             = FALSE;\r
134   UdpConfigData.AllowDuplicatePort        = TRUE;\r
135   UdpConfigData.TypeOfService             = 0;\r
136   UdpConfigData.TimeToLive                = 64;\r
137   UdpConfigData.DoNotFragment             = FALSE;\r
138   UdpConfigData.ReceiveTimeout            = 0;\r
139   UdpConfigData.TransmitTimeout           = 0;\r
140 \r
141   UdpConfigData.UseDefaultAddress         = FALSE;\r
142   UdpConfigData.StationPort               = DHCP_CLIENT_PORT;\r
143   UdpConfigData.RemotePort                = DHCP_SERVER_PORT;\r
144 \r
145   NetZeroMem (&UdpConfigData.StationAddress, sizeof (EFI_IPv4_ADDRESS));\r
146   NetZeroMem (&UdpConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
147   NetZeroMem (&UdpConfigData.RemoteAddress, sizeof (EFI_IPv4_ADDRESS));\r
148 \r
149   return UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfigData);;\r
150 }\r
151 \r
152 \r
153 \r
154 /**\r
155   Destory the DHCP service. The Dhcp4 service may be partly initialized,\r
156   or partly destoried. If a resource is destoried, it is marked as so in\r
157   case the destory failed and being called again later.\r
158 \r
159   @param  DhcpSb                 The DHCP service instance to destory.\r
160 \r
161   @retval EFI_SUCCESS            The DHCP service is successfully closed.\r
162 \r
163 **/\r
164 EFI_STATUS\r
165 Dhcp4CloseService (\r
166   IN DHCP_SERVICE           *DhcpSb\r
167   )\r
168 {\r
169   DhcpCleanLease (DhcpSb);\r
170 \r
171   if (DhcpSb->UdpIo != NULL) {\r
172     UdpIoFreePort (DhcpSb->UdpIo);\r
173     DhcpSb->UdpIo = NULL;\r
174   }\r
175 \r
176   if (DhcpSb->Timer != NULL) {\r
177     gBS->SetTimer (DhcpSb->Timer, TimerCancel, 0);\r
178     gBS->CloseEvent (DhcpSb->Timer);\r
179 \r
180     DhcpSb->Timer = NULL;\r
181   }\r
182 \r
183   return EFI_SUCCESS;\r
184 }\r
185 \r
186 \r
187 \r
188 /**\r
189   Create a new DHCP service binding instance for the controller.\r
190 \r
191   @param  Controller             The controller to install DHCP service binding\r
192                                  protocol onto\r
193   @param  ImageHandle            The driver's image handle\r
194   @param  Service                The variable to receive the created DHCP service\r
195                                  instance.\r
196 \r
197   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resource .\r
198   @retval EFI_SUCCESS            The DHCP service instance is created.\r
199 \r
200 **/\r
201 EFI_STATUS\r
202 Dhcp4CreateService (\r
203   IN  EFI_HANDLE            Controller,\r
204   IN  EFI_HANDLE            ImageHandle,\r
205   OUT DHCP_SERVICE          **Service\r
206   )\r
207 {\r
208   DHCP_SERVICE              *DhcpSb;\r
209   EFI_STATUS                Status;\r
210 \r
211   *Service  = NULL;\r
212   DhcpSb    = NetAllocateZeroPool (sizeof (DHCP_SERVICE));\r
213 \r
214   if (DhcpSb == NULL) {\r
215     return EFI_OUT_OF_RESOURCES;\r
216   }\r
217 \r
218   DhcpSb->Signature       = DHCP_SERVICE_SIGNATURE;\r
219   DhcpSb->ServiceBinding  = mDhcp4ServiceBindingTemplete;\r
220   DhcpSb->ServiceState    = DHCP_UNCONFIGED;\r
221   DhcpSb->InDestory       = FALSE;\r
222   DhcpSb->Controller      = Controller;\r
223   DhcpSb->Image           = ImageHandle;\r
224   NetListInit (&DhcpSb->Children);\r
225   DhcpSb->DhcpState       = Dhcp4Stopped;\r
226   DhcpSb->Xid             = NET_RANDOM (NetRandomInitSeed ());\r
227 \r
228   //\r
229   // Create various resources, UdpIo, Timer, and get Mac address\r
230   //\r
231   Status = gBS->CreateEvent (\r
232                   EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
233                   TPL_CALLBACK,\r
234                   DhcpOnTimerTick,\r
235                   DhcpSb,\r
236                   &DhcpSb->Timer\r
237                   );\r
238 \r
239   if (EFI_ERROR (Status)) {\r
240     goto ON_ERROR;\r
241   }\r
242 \r
243   DhcpSb->UdpIo = UdpIoCreatePort (Controller, ImageHandle, DhcpConfigUdpIo, NULL);\r
244 \r
245   if (DhcpSb->UdpIo == NULL) {\r
246     Status = EFI_OUT_OF_RESOURCES;\r
247     goto ON_ERROR;\r
248   }\r
249 \r
250   DhcpSb->HwLen  = (UINT8) DhcpSb->UdpIo->SnpMode.HwAddressSize;\r
251   DhcpSb->HwType = DhcpSb->UdpIo->SnpMode.IfType;\r
252   CopyMem (&DhcpSb->Mac, &DhcpSb->UdpIo->SnpMode.CurrentAddress, sizeof (DhcpSb->Mac));\r
253 \r
254   *Service       = DhcpSb;\r
255   return EFI_SUCCESS;\r
256 \r
257 ON_ERROR:\r
258   Dhcp4CloseService (DhcpSb);\r
259   NetFreePool (DhcpSb);\r
260 \r
261   return Status;\r
262 }\r
263 \r
264 \r
265 /**\r
266   Start this driver on ControllerHandle.\r
267 \r
268   @param  This                   Protocol instance pointer.\r
269   @param  ControllerHandle       Handle of device to bind driver to\r
270   @param  RemainingDevicePath    Optional parameter use to pick a specific child\r
271                                  device to start.\r
272 \r
273   @retval EFI_SUCCES             This driver is added to ControllerHandle\r
274   @retval EFI_ALREADY_STARTED    This driver is already running on ControllerHandle\r
275   @retval other                  This driver does not support this device\r
276 \r
277 **/\r
278 EFI_STATUS\r
279 EFIAPI\r
280 Dhcp4DriverBindingStart (\r
281   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
282   IN EFI_HANDLE                   ControllerHandle,\r
283   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
284   )\r
285 {\r
286   DHCP_SERVICE              *DhcpSb;\r
287   EFI_STATUS                Status;\r
288 \r
289   //\r
290   // First: test for the DHCP4 Protocol\r
291   //\r
292   Status = gBS->OpenProtocol (\r
293                   ControllerHandle,\r
294                   &gEfiDhcp4ServiceBindingProtocolGuid,\r
295                   NULL,\r
296                   This->DriverBindingHandle,\r
297                   ControllerHandle,\r
298                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
299                   );\r
300 \r
301   if (Status == EFI_SUCCESS) {\r
302     return EFI_ALREADY_STARTED;\r
303   }\r
304 \r
305   Status = Dhcp4CreateService (ControllerHandle, This->DriverBindingHandle, &DhcpSb);\r
306 \r
307   if (EFI_ERROR (Status)) {\r
308     return Status;\r
309   }\r
310 \r
311   Status = gBS->SetTimer (DhcpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);\r
312 \r
313   if (EFI_ERROR (Status)) {\r
314     goto ON_ERROR;\r
315   }\r
316 \r
317   //\r
318   // Install the Dhcp4ServiceBinding Protocol onto ControlerHandle\r
319   //\r
320   Status = gBS->InstallMultipleProtocolInterfaces (\r
321                   &ControllerHandle,\r
322                   &gEfiDhcp4ServiceBindingProtocolGuid,\r
323                   &DhcpSb->ServiceBinding,\r
324                   NULL\r
325                   );\r
326 \r
327   if (EFI_ERROR (Status)) {\r
328     goto ON_ERROR;\r
329   }\r
330 \r
331   return Status;\r
332 \r
333 ON_ERROR:\r
334   Dhcp4CloseService (DhcpSb);\r
335   NetFreePool (DhcpSb);\r
336   return Status;\r
337 }\r
338 \r
339 \r
340 /**\r
341   Stop this driver on ControllerHandle.\r
342 \r
343   @param  This                   Protocol instance pointer.\r
344   @param  ControllerHandle       Handle of device to stop driver on\r
345   @param  NumberOfChildren       Number of Handles in ChildHandleBuffer. If number\r
346                                  of  children is zero stop the entire bus driver.\r
347   @param  ChildHandleBuffer      List of Child Handles to Stop.\r
348 \r
349   @retval EFI_SUCCES             This driver is removed ControllerHandle\r
350   @retval other                  This driver was not removed from this device\r
351 \r
352 **/\r
353 EFI_STATUS\r
354 EFIAPI\r
355 Dhcp4DriverBindingStop (\r
356   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
357   IN  EFI_HANDLE                   ControllerHandle,\r
358   IN  UINTN                        NumberOfChildren,\r
359   IN  EFI_HANDLE                   *ChildHandleBuffer\r
360   )\r
361 {\r
362   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;\r
363   DHCP_SERVICE                  *DhcpSb;\r
364   DHCP_PROTOCOL                 *Instance;\r
365   EFI_HANDLE                    NicHandle;\r
366   EFI_STATUS                    Status;\r
367   EFI_TPL                       OldTpl;\r
368 \r
369   //\r
370   // DHCP driver opens UDP child, So, the ControllerHandle is the\r
371   // UDP child handle. locate the Nic handle first.\r
372   //\r
373   NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp4ProtocolGuid);\r
374 \r
375   if (NicHandle == NULL) {\r
376     return EFI_SUCCESS;\r
377   }\r
378 \r
379    Status = gBS->OpenProtocol (\r
380                   NicHandle,\r
381                   &gEfiDhcp4ServiceBindingProtocolGuid,\r
382                   (VOID **) &ServiceBinding,\r
383                   This->DriverBindingHandle,\r
384                   NicHandle,\r
385                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
386                   );\r
387 \r
388   if (EFI_ERROR (Status)) {\r
389     return EFI_DEVICE_ERROR;\r
390   }\r
391 \r
392   DhcpSb = DHCP_SERVICE_FROM_THIS (ServiceBinding);\r
393 \r
394   if (DhcpSb->InDestory) {\r
395     return EFI_SUCCESS;\r
396   }\r
397 \r
398   OldTpl            = NET_RAISE_TPL (NET_TPL_LOCK);\r
399   DhcpSb->InDestory = TRUE;\r
400 \r
401   //\r
402   // Don't use NET_LIST_FOR_EACH_SAFE here, Dhcp4ServiceBindingDestoryChild\r
403   // may cause other child to be deleted.\r
404   //\r
405   while (!NetListIsEmpty (&DhcpSb->Children)) {\r
406     Instance = NET_LIST_HEAD (&DhcpSb->Children, DHCP_PROTOCOL, Link);\r
407     Dhcp4ServiceBindingDestroyChild (ServiceBinding, Instance->Handle);\r
408   }\r
409 \r
410   if (DhcpSb->NumChildren != 0) {\r
411     Status = EFI_DEVICE_ERROR;\r
412     goto ON_ERROR;\r
413   }\r
414 \r
415   DhcpSb->ServiceState  = DHCP_DESTORY;\r
416 \r
417   Status = gBS->UninstallProtocolInterface (\r
418                   NicHandle,\r
419                   &gEfiDhcp4ServiceBindingProtocolGuid,\r
420                   ServiceBinding\r
421                   );\r
422 \r
423   if (EFI_ERROR (Status)) {\r
424     goto ON_ERROR;\r
425   }\r
426 \r
427   Dhcp4CloseService (DhcpSb);\r
428   NET_RESTORE_TPL (OldTpl);\r
429 \r
430   NetFreePool (DhcpSb);\r
431   return EFI_SUCCESS;\r
432 \r
433 ON_ERROR:\r
434   DhcpSb->InDestory = FALSE;\r
435   NET_RESTORE_TPL (OldTpl);\r
436   return Status;\r
437 }\r
438 \r
439 \r
440 /**\r
441   Initialize a new DHCP child\r
442 \r
443   @param  DhcpSb                 The dhcp service instance\r
444   @param  Instance               The dhcp instance to initialize\r
445 \r
446   @return None\r
447 \r
448 **/\r
449 VOID\r
450 DhcpInitProtocol (\r
451   IN DHCP_SERVICE           *DhcpSb,\r
452   IN DHCP_PROTOCOL          *Instance\r
453   )\r
454 {\r
455   Instance->Signature         = DHCP_PROTOCOL_SIGNATURE;\r
456   CopyMem (&Instance->Dhcp4Protocol, &mDhcp4ProtocolTemplate, sizeof (Instance->Dhcp4Protocol));\r
457   NetListInit (&Instance->Link);\r
458   Instance->Handle            = NULL;\r
459   Instance->Service           = DhcpSb;\r
460   Instance->InDestory         = FALSE;\r
461   Instance->CompletionEvent   = NULL;\r
462   Instance->RenewRebindEvent  = NULL;\r
463   Instance->Token             = NULL;\r
464 }\r
465 \r
466 \r
467 /**\r
468   Creates a child handle with a set of DHCP4 services.\r
469 \r
470   @param  This                   Protocol instance pointer.\r
471   @param  ChildHandle            Pointer to the handle of the child to create.  If\r
472                                  it  is NULL, then a new handle is created.  If it\r
473                                  is not  NULL, then the DHCP4 services are added to\r
474                                  the existing  child handle.\r
475 \r
476   @retval EFI_SUCCES             The child handle was created with the DHCP4\r
477                                  services\r
478   @retval EFI_OUT_OF_RESOURCES   There are not enough resources to create the child\r
479   @retval other                  The child handle was not created\r
480 \r
481 **/\r
482 EFI_STATUS\r
483 EFIAPI\r
484 Dhcp4ServiceBindingCreateChild (\r
485   IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
486   IN EFI_HANDLE                    *ChildHandle\r
487   )\r
488 {\r
489   DHCP_SERVICE              *DhcpSb;\r
490   DHCP_PROTOCOL             *Instance;\r
491   EFI_STATUS                Status;\r
492   EFI_TPL                   OldTpl;\r
493   VOID                      *Udp4;\r
494 \r
495   if ((This == NULL) || (ChildHandle == NULL)) {\r
496     return EFI_INVALID_PARAMETER;\r
497   }\r
498 \r
499   Instance = NetAllocatePool (sizeof (*Instance));\r
500 \r
501   if (Instance == NULL) {\r
502     return EFI_OUT_OF_RESOURCES;\r
503   }\r
504 \r
505   DhcpSb = DHCP_SERVICE_FROM_THIS (This);\r
506   DhcpInitProtocol (DhcpSb, Instance);\r
507 \r
508   //\r
509   // Install DHCP4 onto ChildHandle\r
510   //\r
511   Status = gBS->InstallMultipleProtocolInterfaces (\r
512                   ChildHandle,\r
513                   &gEfiDhcp4ProtocolGuid,\r
514                   &Instance->Dhcp4Protocol,\r
515                   NULL\r
516                   );\r
517 \r
518   if (EFI_ERROR (Status)) {\r
519     NetFreePool (Instance);\r
520     return Status;\r
521   }\r
522 \r
523   Instance->Handle  = *ChildHandle;\r
524 \r
525   //\r
526   // Open the Udp4 protocol BY_CHILD.\r
527   //\r
528   Status = gBS->OpenProtocol (\r
529                   DhcpSb->UdpIo->UdpHandle,\r
530                   &gEfiUdp4ProtocolGuid,\r
531                   (VOID **) &Udp4,\r
532                   gDhcp4DriverBinding.DriverBindingHandle,\r
533                   Instance->Handle,\r
534                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
535                   );\r
536   if (EFI_ERROR (Status)) {\r
537     gBS->UninstallMultipleProtocolInterfaces (\r
538            Instance->Handle,\r
539            &gEfiDhcp4ProtocolGuid,\r
540            &Instance->Dhcp4Protocol,\r
541            NULL\r
542            );\r
543 \r
544     NetFreePool (Instance);\r
545     return Status;\r
546   }\r
547 \r
548   OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
549 \r
550   NetListInsertTail (&DhcpSb->Children, &Instance->Link);\r
551   DhcpSb->NumChildren++;\r
552 \r
553   NET_RESTORE_TPL (OldTpl);\r
554 \r
555   return EFI_SUCCESS;\r
556 }\r
557 \r
558 \r
559 /**\r
560   Destroys a child handle with a set of DHCP4 services.\r
561 \r
562   @param  This                   Protocol instance pointer.\r
563   @param  ChildHandle            Handle of the child to destroy\r
564 \r
565   @retval EFI_SUCCES             The DHCP4 service is removed from the child handle\r
566   @retval EFI_UNSUPPORTED        The child handle does not support the DHCP4\r
567                                  service\r
568   @retval EFI_INVALID_PARAMETER  Child handle is not a valid EFI Handle.\r
569   @retval EFI_ACCESS_DENIED      The child handle could not be destroyed because\r
570                                  its  DHCP4 services are being used.\r
571   @retval other                  The child handle was not destroyed\r
572 \r
573 **/\r
574 EFI_STATUS\r
575 EFIAPI\r
576 Dhcp4ServiceBindingDestroyChild (\r
577   IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
578   IN EFI_HANDLE                    ChildHandle\r
579   )\r
580 {\r
581   DHCP_SERVICE              *DhcpSb;\r
582   DHCP_PROTOCOL             *Instance;\r
583   EFI_DHCP4_PROTOCOL        *Dhcp;\r
584   EFI_TPL                   OldTpl;\r
585   EFI_STATUS                Status;\r
586 \r
587   if ((This == NULL) || (ChildHandle == NULL)) {\r
588     return EFI_INVALID_PARAMETER;\r
589   }\r
590 \r
591   //\r
592   // Retrieve the private context data structures\r
593   //\r
594   Status = gBS->OpenProtocol (\r
595                   ChildHandle,\r
596                   &gEfiDhcp4ProtocolGuid,\r
597                   (VOID **) &Dhcp,\r
598                   gDhcp4DriverBinding.DriverBindingHandle,\r
599                   ChildHandle,\r
600                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
601                   );\r
602 \r
603   if (EFI_ERROR (Status)) {\r
604     return EFI_UNSUPPORTED;\r
605   }\r
606 \r
607   Instance  = DHCP_INSTANCE_FROM_THIS (Dhcp);\r
608   DhcpSb    = DHCP_SERVICE_FROM_THIS (This);\r
609 \r
610   if (Instance->Service != DhcpSb) {\r
611     return EFI_INVALID_PARAMETER;\r
612   }\r
613 \r
614   //\r
615   // A child can be destoried more than once. For example,\r
616   // Dhcp4DriverBindingStop will destory all of its children.\r
617   // when caller driver is being stopped, it will destory the\r
618   // dhcp child it opens.\r
619   //\r
620   if (Instance->InDestory) {\r
621     return EFI_SUCCESS;\r
622   }\r
623 \r
624   OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);\r
625   Instance->InDestory = TRUE;\r
626 \r
627   //\r
628   // Close the Udp4 protocol.\r
629   //\r
630   gBS->CloseProtocol (\r
631          DhcpSb->UdpIo->UdpHandle,\r
632          &gEfiUdp4ProtocolGuid,\r
633          gDhcp4DriverBinding.DriverBindingHandle,\r
634          ChildHandle\r
635          );\r
636 \r
637   //\r
638   // Uninstall the DHCP4 protocol first to enable a top down destruction.\r
639   //\r
640   Status = gBS->UninstallProtocolInterface (\r
641                   ChildHandle,\r
642                   &gEfiDhcp4ProtocolGuid,\r
643                   Dhcp\r
644                   );\r
645 \r
646   if (EFI_ERROR (Status)) {\r
647     Instance->InDestory = FALSE;\r
648 \r
649     NET_RESTORE_TPL (OldTpl);\r
650     return Status;\r
651   }\r
652 \r
653   if (DhcpSb->ActiveChild == Instance) {\r
654     DhcpYieldControl (DhcpSb);\r
655   }\r
656 \r
657   NetListRemoveEntry (&Instance->Link);\r
658   DhcpSb->NumChildren--;\r
659 \r
660   NET_RESTORE_TPL (OldTpl);\r
661 \r
662   NetFreePool (Instance);\r
663   return EFI_SUCCESS;\r
664 }\r