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