]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Driver.c
Scrubbed part of the code.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Dhcp4Dxe / Dhcp4Driver.c
... / ...
CommitLineData
1/** @file\r
2\r
3Copyright (c) 2006 - 2008, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12\r
13Module Name:\r
14\r
15 Dhcp4Driver.c\r
16\r
17Abstract:\r
18\r
19\r
20**/\r
21\r
22#include "Dhcp4Impl.h"\r
23#include "Dhcp4Driver.h"\r
24\r
25EFI_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
34EFI_SERVICE_BINDING_PROTOCOL mDhcp4ServiceBindingTemplate = {\r
35 Dhcp4ServiceBindingCreateChild,\r
36 Dhcp4ServiceBindingDestroyChild\r
37};\r
38\r
39/**\r
40 This is the declaration of an EFI image entry point. This entry point is\r
41 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including\r
42 both device drivers and bus drivers.\r
43 \r
44 Entry point of the DHCP driver to install various protocols.\r
45\r
46 @param ImageHandle The firmware allocated handle for the UEFI image.\r
47 @param SystemTable A pointer to the EFI System Table.\r
48\r
49 @retval EFI_SUCCESS The operation completed successfully.\r
50 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
51\r
52**/\r
53EFI_STATUS\r
54EFIAPI\r
55Dhcp4DriverEntryPoint (\r
56 IN EFI_HANDLE ImageHandle,\r
57 IN EFI_SYSTEM_TABLE *SystemTable\r
58 )\r
59{\r
60 return EfiLibInstallDriverBindingComponentName2 (\r
61 ImageHandle,\r
62 SystemTable,\r
63 &gDhcp4DriverBinding,\r
64 ImageHandle,\r
65 &gDhcp4ComponentName,\r
66 &gDhcp4ComponentName2\r
67 );\r
68}\r
69\r
70\r
71/**\r
72 Test to see if this driver supports ControllerHandle. This service\r
73 is called by the EFI boot service ConnectController(). In\r
74 order to make drivers as small as possible, there are a few calling\r
75 restrictions for this service. ConnectController() must\r
76 follow these calling restrictions. If any other agent wishes to call\r
77 Supported() it must also follow these calling restrictions.\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_SUCCESS This driver supports this device\r
85 @retval EFI_ALREADY_STARTED This driver is already running on this device\r
86 @retval other This driver does not support this device\r
87\r
88**/\r
89EFI_STATUS\r
90EFIAPI\r
91Dhcp4DriverBindingSupported (\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
124EFI_STATUS\r
125DhcpConfigUdpIo (\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 ZeroMem (&UdpConfigData.StationAddress, sizeof (EFI_IPv4_ADDRESS));\r
147 ZeroMem (&UdpConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
148 ZeroMem (&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 destroyed. If a resource is destroyed, it is marked as so in\r
158 case the destroy 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 Always return success.\r
163\r
164**/\r
165EFI_STATUS\r
166Dhcp4CloseService (\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 @retval other Other error occurs.\r
201\r
202**/\r
203EFI_STATUS\r
204Dhcp4CreateService (\r
205 IN EFI_HANDLE Controller,\r
206 IN EFI_HANDLE ImageHandle,\r
207 OUT DHCP_SERVICE **Service\r
208 )\r
209{\r
210 DHCP_SERVICE *DhcpSb;\r
211 EFI_STATUS Status;\r
212\r
213 *Service = NULL;\r
214 DhcpSb = AllocateZeroPool (sizeof (DHCP_SERVICE));\r
215\r
216 if (DhcpSb == NULL) {\r
217 return EFI_OUT_OF_RESOURCES;\r
218 }\r
219\r
220 DhcpSb->Signature = DHCP_SERVICE_SIGNATURE;\r
221 DhcpSb->ServiceState = DHCP_UNCONFIGED;\r
222 DhcpSb->InDestory = FALSE;\r
223 DhcpSb->Controller = Controller;\r
224 DhcpSb->Image = ImageHandle;\r
225 InitializeListHead (&DhcpSb->Children);\r
226 DhcpSb->DhcpState = Dhcp4Stopped;\r
227 DhcpSb->Xid = NET_RANDOM (NetRandomInitSeed ());\r
228 CopyMem (\r
229 &DhcpSb->ServiceBinding,\r
230 &mDhcp4ServiceBindingTemplate,\r
231 sizeof (EFI_SERVICE_BINDING_PROTOCOL)\r
232 );\r
233 //\r
234 // Create various resources, UdpIo, Timer, and get Mac address\r
235 //\r
236 Status = gBS->CreateEvent (\r
237 EVT_NOTIFY_SIGNAL | EVT_TIMER,\r
238 TPL_CALLBACK,\r
239 DhcpOnTimerTick,\r
240 DhcpSb,\r
241 &DhcpSb->Timer\r
242 );\r
243\r
244 if (EFI_ERROR (Status)) {\r
245 goto ON_ERROR;\r
246 }\r
247\r
248 DhcpSb->UdpIo = UdpIoCreatePort (Controller, ImageHandle, DhcpConfigUdpIo, NULL);\r
249\r
250 if (DhcpSb->UdpIo == NULL) {\r
251 Status = EFI_OUT_OF_RESOURCES;\r
252 goto ON_ERROR;\r
253 }\r
254\r
255 DhcpSb->HwLen = (UINT8) DhcpSb->UdpIo->SnpMode.HwAddressSize;\r
256 DhcpSb->HwType = DhcpSb->UdpIo->SnpMode.IfType;\r
257 CopyMem (&DhcpSb->Mac, &DhcpSb->UdpIo->SnpMode.CurrentAddress, sizeof (DhcpSb->Mac));\r
258\r
259 *Service = DhcpSb;\r
260 return EFI_SUCCESS;\r
261\r
262ON_ERROR:\r
263 Dhcp4CloseService (DhcpSb);\r
264 gBS->FreePool (DhcpSb);\r
265\r
266 return Status;\r
267}\r
268\r
269\r
270/**\r
271 Start this driver on ControllerHandle. This service is called by the\r
272 EFI boot service ConnectController(). In order to make\r
273 drivers as small as possible, there are a few calling restrictions for\r
274 this service. ConnectController() must follow these\r
275 calling restrictions. If any other agent wishes to call Start() it\r
276 must also follow these calling restrictions.\r
277\r
278 @param This Protocol instance pointer.\r
279 @param ControllerHandle Handle of device to bind driver to\r
280 @param RemainingDevicePath Optional parameter use to pick a specific child\r
281 device to start.\r
282\r
283 @retval EFI_SUCCESS This driver is added to ControllerHandle\r
284 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle\r
285 @retval other This driver does not support this device\r
286\r
287**/\r
288EFI_STATUS\r
289EFIAPI\r
290Dhcp4DriverBindingStart (\r
291 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
292 IN EFI_HANDLE ControllerHandle,\r
293 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
294 )\r
295{\r
296 DHCP_SERVICE *DhcpSb;\r
297 EFI_STATUS Status;\r
298\r
299 //\r
300 // First: test for the DHCP4 Protocol\r
301 //\r
302 Status = gBS->OpenProtocol (\r
303 ControllerHandle,\r
304 &gEfiDhcp4ServiceBindingProtocolGuid,\r
305 NULL,\r
306 This->DriverBindingHandle,\r
307 ControllerHandle,\r
308 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
309 );\r
310\r
311 if (Status == EFI_SUCCESS) {\r
312 return EFI_ALREADY_STARTED;\r
313 }\r
314\r
315 Status = Dhcp4CreateService (ControllerHandle, This->DriverBindingHandle, &DhcpSb);\r
316\r
317 if (EFI_ERROR (Status)) {\r
318 return Status;\r
319 }\r
320\r
321 Status = gBS->SetTimer (DhcpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);\r
322\r
323 if (EFI_ERROR (Status)) {\r
324 goto ON_ERROR;\r
325 }\r
326\r
327 //\r
328 // Install the Dhcp4ServiceBinding Protocol onto ControlerHandle\r
329 //\r
330 Status = gBS->InstallMultipleProtocolInterfaces (\r
331 &ControllerHandle,\r
332 &gEfiDhcp4ServiceBindingProtocolGuid,\r
333 &DhcpSb->ServiceBinding,\r
334 NULL\r
335 );\r
336\r
337 if (EFI_ERROR (Status)) {\r
338 goto ON_ERROR;\r
339 }\r
340\r
341 return Status;\r
342\r
343ON_ERROR:\r
344 Dhcp4CloseService (DhcpSb);\r
345 gBS->FreePool (DhcpSb);\r
346 return Status;\r
347}\r
348\r
349\r
350/**\r
351 Stop this driver on ControllerHandle. This service is called by the\r
352 EFI boot service DisconnectController(). In order to\r
353 make drivers as small as possible, there are a few calling\r
354 restrictions for this service. DisconnectController()\r
355 must follow these calling restrictions. If any other agent wishes\r
356 to call Stop() it must also follow these calling restrictions.\r
357 \r
358 @param This Protocol instance pointer.\r
359 @param ControllerHandle Handle of device to stop driver on\r
360 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
361 children is zero stop the entire bus driver.\r
362 @param ChildHandleBuffer List of Child Handles to Stop.\r
363\r
364 @retval EFI_SUCCESS This driver is removed ControllerHandle\r
365 @retval other This driver was not removed from this device\r
366\r
367**/\r
368EFI_STATUS\r
369EFIAPI\r
370Dhcp4DriverBindingStop (\r
371 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
372 IN EFI_HANDLE ControllerHandle,\r
373 IN UINTN NumberOfChildren,\r
374 IN EFI_HANDLE *ChildHandleBuffer\r
375 )\r
376{\r
377 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;\r
378 DHCP_SERVICE *DhcpSb;\r
379 DHCP_PROTOCOL *Instance;\r
380 EFI_HANDLE NicHandle;\r
381 EFI_STATUS Status;\r
382 EFI_TPL OldTpl;\r
383\r
384 //\r
385 // DHCP driver opens UDP child, So, the ControllerHandle is the\r
386 // UDP child handle. locate the Nic handle first.\r
387 //\r
388 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp4ProtocolGuid);\r
389\r
390 if (NicHandle == NULL) {\r
391 return EFI_DEVICE_ERROR;\r
392 }\r
393\r
394 Status = gBS->OpenProtocol (\r
395 NicHandle,\r
396 &gEfiDhcp4ServiceBindingProtocolGuid,\r
397 (VOID **) &ServiceBinding,\r
398 This->DriverBindingHandle,\r
399 NicHandle,\r
400 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
401 );\r
402\r
403 if (EFI_ERROR (Status)) {\r
404 return EFI_DEVICE_ERROR;\r
405 }\r
406\r
407 DhcpSb = DHCP_SERVICE_FROM_THIS (ServiceBinding);\r
408\r
409 if (DhcpSb->InDestory) {\r
410 return EFI_SUCCESS;\r
411 }\r
412\r
413 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
414\r
415 if (NumberOfChildren == 0) {\r
416\r
417 DhcpSb->InDestory = TRUE;\r
418 DhcpSb->ServiceState = DHCP_DESTORY;\r
419\r
420 gBS->UninstallProtocolInterface (\r
421 NicHandle,\r
422 &gEfiDhcp4ServiceBindingProtocolGuid,\r
423 ServiceBinding\r
424 );\r
425\r
426 Dhcp4CloseService (DhcpSb);\r
427\r
428 gBS->FreePool (DhcpSb);\r
429 } else {\r
430 //\r
431 // Don't use NET_LIST_FOR_EACH_SAFE here, Dhcp4ServiceBindingDestoryChild\r
432 // may cause other child to be deleted.\r
433 //\r
434 while (!IsListEmpty (&DhcpSb->Children)) {\r
435 Instance = NET_LIST_HEAD (&DhcpSb->Children, DHCP_PROTOCOL, Link);\r
436 ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);\r
437 }\r
438\r
439 if (DhcpSb->NumChildren != 0) {\r
440 Status = EFI_DEVICE_ERROR;\r
441 }\r
442 }\r
443\r
444 gBS->RestoreTPL (OldTpl);\r
445\r
446 return Status;\r
447}\r
448\r
449\r
450/**\r
451 Initialize a new DHCP instance.\r
452\r
453 @param DhcpSb The dhcp service instance\r
454 @param Instance The dhcp instance to initialize\r
455\r
456 @return None\r
457\r
458**/\r
459VOID\r
460DhcpInitProtocol (\r
461 IN DHCP_SERVICE *DhcpSb,\r
462 IN OUT DHCP_PROTOCOL *Instance\r
463 )\r
464{\r
465 Instance->Signature = DHCP_PROTOCOL_SIGNATURE;\r
466 CopyMem (&Instance->Dhcp4Protocol, &mDhcp4ProtocolTemplate, sizeof (Instance->Dhcp4Protocol));\r
467 InitializeListHead (&Instance->Link);\r
468 Instance->Handle = NULL;\r
469 Instance->Service = DhcpSb;\r
470 Instance->InDestory = FALSE;\r
471 Instance->CompletionEvent = NULL;\r
472 Instance->RenewRebindEvent = NULL;\r
473 Instance->Token = NULL;\r
474 Instance->UdpIo = NULL;\r
475 NetbufQueInit (&Instance->ResponseQueue);\r
476}\r
477\r
478\r
479/**\r
480 Creates a child handle with a set of I/O services.\r
481\r
482 @param This Protocol instance pointer.\r
483 @param ChildHandle Pointer to the handle of the child to create. If it is NULL,\r
484 then a new handle is created. If it is not NULL, then the\r
485 I/O services are added to the existing child handle.\r
486\r
487 @retval EFI_SUCCES The child handle was created with the I/O services\r
488 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.\r
489 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create\r
490 the child\r
491 @retval other The child handle was not created\r
492\r
493**/\r
494EFI_STATUS\r
495EFIAPI\r
496Dhcp4ServiceBindingCreateChild (\r
497 IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
498 IN EFI_HANDLE *ChildHandle\r
499 )\r
500{\r
501 DHCP_SERVICE *DhcpSb;\r
502 DHCP_PROTOCOL *Instance;\r
503 EFI_STATUS Status;\r
504 EFI_TPL OldTpl;\r
505 VOID *Udp4;\r
506\r
507 if ((This == NULL) || (ChildHandle == NULL)) {\r
508 return EFI_INVALID_PARAMETER;\r
509 }\r
510\r
511 Instance = AllocatePool (sizeof (*Instance));\r
512\r
513 if (Instance == NULL) {\r
514 return EFI_OUT_OF_RESOURCES;\r
515 }\r
516\r
517 DhcpSb = DHCP_SERVICE_FROM_THIS (This);\r
518 DhcpInitProtocol (DhcpSb, Instance);\r
519\r
520 //\r
521 // Install DHCP4 onto ChildHandle\r
522 //\r
523 Status = gBS->InstallMultipleProtocolInterfaces (\r
524 ChildHandle,\r
525 &gEfiDhcp4ProtocolGuid,\r
526 &Instance->Dhcp4Protocol,\r
527 NULL\r
528 );\r
529\r
530 if (EFI_ERROR (Status)) {\r
531 gBS->FreePool (Instance);\r
532 return Status;\r
533 }\r
534\r
535 Instance->Handle = *ChildHandle;\r
536\r
537 //\r
538 // Open the Udp4 protocol BY_CHILD.\r
539 //\r
540 Status = gBS->OpenProtocol (\r
541 DhcpSb->UdpIo->UdpHandle,\r
542 &gEfiUdp4ProtocolGuid,\r
543 (VOID **) &Udp4,\r
544 gDhcp4DriverBinding.DriverBindingHandle,\r
545 Instance->Handle,\r
546 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
547 );\r
548 if (EFI_ERROR (Status)) {\r
549 gBS->UninstallMultipleProtocolInterfaces (\r
550 Instance->Handle,\r
551 &gEfiDhcp4ProtocolGuid,\r
552 &Instance->Dhcp4Protocol,\r
553 NULL\r
554 );\r
555\r
556 gBS->FreePool (Instance);\r
557 return Status;\r
558 }\r
559\r
560 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
561\r
562 InsertTailList (&DhcpSb->Children, &Instance->Link);\r
563 DhcpSb->NumChildren++;\r
564\r
565 gBS->RestoreTPL (OldTpl);\r
566\r
567 return EFI_SUCCESS;\r
568}\r
569\r
570\r
571/**\r
572 Destroys a child handle with a set of I/O services.\r
573\r
574 @param This Protocol instance pointer.\r
575 @param ChildHandle Handle of the child to destroy\r
576\r
577 @retval EFI_SUCCES The I/O services were removed from the child handle\r
578 @retval EFI_UNSUPPORTED The child handle does not support the I/O services\r
579 that are being removed.\r
580 @retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.\r
581 @retval EFI_ACCESS_DENIED The child handle could not be destroyed because its\r
582 I/O services are being used.\r
583 @retval other The child handle was not destroyed\r
584\r
585**/\r
586EFI_STATUS\r
587EFIAPI\r
588Dhcp4ServiceBindingDestroyChild (\r
589 IN EFI_SERVICE_BINDING_PROTOCOL *This,\r
590 IN EFI_HANDLE ChildHandle\r
591 )\r
592{\r
593 DHCP_SERVICE *DhcpSb;\r
594 DHCP_PROTOCOL *Instance;\r
595 EFI_DHCP4_PROTOCOL *Dhcp;\r
596 EFI_TPL OldTpl;\r
597 EFI_STATUS Status;\r
598\r
599 if ((This == NULL) || (ChildHandle == NULL)) {\r
600 return EFI_INVALID_PARAMETER;\r
601 }\r
602\r
603 //\r
604 // Retrieve the private context data structures\r
605 //\r
606 Status = gBS->OpenProtocol (\r
607 ChildHandle,\r
608 &gEfiDhcp4ProtocolGuid,\r
609 (VOID **) &Dhcp,\r
610 gDhcp4DriverBinding.DriverBindingHandle,\r
611 ChildHandle,\r
612 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
613 );\r
614\r
615 if (EFI_ERROR (Status)) {\r
616 return EFI_UNSUPPORTED;\r
617 }\r
618\r
619 Instance = DHCP_INSTANCE_FROM_THIS (Dhcp);\r
620 DhcpSb = DHCP_SERVICE_FROM_THIS (This);\r
621\r
622 if (Instance->Service != DhcpSb) {\r
623 return EFI_INVALID_PARAMETER;\r
624 }\r
625\r
626 //\r
627 // A child can be destroyed more than once. For example,\r
628 // Dhcp4DriverBindingStop will destroy all of its children.\r
629 // when caller driver is being stopped, it will destory the\r
630 // dhcp child it opens.\r
631 //\r
632 if (Instance->InDestory) {\r
633 return EFI_SUCCESS;\r
634 }\r
635\r
636 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
637 Instance->InDestory = TRUE;\r
638\r
639 //\r
640 // Close the Udp4 protocol.\r
641 //\r
642 gBS->CloseProtocol (\r
643 DhcpSb->UdpIo->UdpHandle,\r
644 &gEfiUdp4ProtocolGuid,\r
645 gDhcp4DriverBinding.DriverBindingHandle,\r
646 ChildHandle\r
647 );\r
648\r
649 //\r
650 // Uninstall the DHCP4 protocol first to enable a top down destruction.\r
651 //\r
652 Status = gBS->UninstallProtocolInterface (\r
653 ChildHandle,\r
654 &gEfiDhcp4ProtocolGuid,\r
655 Dhcp\r
656 );\r
657\r
658 if (EFI_ERROR (Status)) {\r
659 Instance->InDestory = FALSE;\r
660\r
661 gBS->RestoreTPL (OldTpl);\r
662 return Status;\r
663 }\r
664\r
665 if (DhcpSb->ActiveChild == Instance) {\r
666 DhcpYieldControl (DhcpSb);\r
667 }\r
668\r
669 RemoveEntryList (&Instance->Link);\r
670 DhcpSb->NumChildren--;\r
671\r
672 gBS->RestoreTPL (OldTpl);\r
673\r
674 gBS->FreePool (Instance);\r
675 return EFI_SUCCESS;\r
676}\r