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