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