3 Copyright (c) 2006 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
22 #include "Dhcp4Impl.h"
23 #include "Dhcp4Driver.h"
25 EFI_DRIVER_BINDING_PROTOCOL gDhcp4DriverBinding
= {
26 Dhcp4DriverBindingSupported
,
27 Dhcp4DriverBindingStart
,
28 Dhcp4DriverBindingStop
,
34 EFI_SERVICE_BINDING_PROTOCOL mDhcp4ServiceBindingTemplete
= {
35 Dhcp4ServiceBindingCreateChild
,
36 Dhcp4ServiceBindingDestroyChild
40 Entry point of the DHCP driver to install various protocols.
42 @param ImageHandle The image handle of the driver.
43 @param SystemTable The system table.
45 @retval EFI_SUCCES if the driver binding and component name protocols are successfully
46 @retval Others Failed to install the protocols.
51 Dhcp4DriverEntryPoint (
52 IN EFI_HANDLE ImageHandle
,
53 IN EFI_SYSTEM_TABLE
*SystemTable
56 return EfiLibInstallDriverBindingComponentName2 (
68 Test to see if DHCP driver supports the ControllerHandle.
70 @param This Protocol instance pointer.
71 @param ControllerHandle Handle of device to test
72 @param RemainingDevicePath Optional parameter use to pick a specific child
75 @retval EFI_SUCCES This driver supports this device
76 @retval other This driver does not support this device
81 Dhcp4DriverBindingSupported (
82 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
83 IN EFI_HANDLE ControllerHandle
,
84 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
89 Status
= gBS
->OpenProtocol (
91 &gEfiUdp4ServiceBindingProtocolGuid
,
93 This
->DriverBindingHandle
,
95 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
104 Configure the default UDP child to receive all the DHCP traffics
105 on this network interface.
107 @param UdpIo The UDP IO port to configure
108 @param Context The context to the function
110 @retval EFI_SUCCESS The UDP IO port is successfully configured.
111 @retval Others Failed to configure the UDP child.
116 IN UDP_IO_PORT
*UdpIo
,
120 EFI_UDP4_CONFIG_DATA UdpConfigData
;
122 UdpConfigData
.AcceptBroadcast
= TRUE
;
123 UdpConfigData
.AcceptPromiscuous
= FALSE
;
124 UdpConfigData
.AcceptAnyPort
= FALSE
;
125 UdpConfigData
.AllowDuplicatePort
= TRUE
;
126 UdpConfigData
.TypeOfService
= 0;
127 UdpConfigData
.TimeToLive
= 64;
128 UdpConfigData
.DoNotFragment
= FALSE
;
129 UdpConfigData
.ReceiveTimeout
= 0;
130 UdpConfigData
.TransmitTimeout
= 0;
132 UdpConfigData
.UseDefaultAddress
= FALSE
;
133 UdpConfigData
.StationPort
= DHCP_CLIENT_PORT
;
134 UdpConfigData
.RemotePort
= DHCP_SERVER_PORT
;
136 ZeroMem (&UdpConfigData
.StationAddress
, sizeof (EFI_IPv4_ADDRESS
));
137 ZeroMem (&UdpConfigData
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
138 ZeroMem (&UdpConfigData
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
));
140 return UdpIo
->Udp
->Configure (UdpIo
->Udp
, &UdpConfigData
);;
146 Destory the DHCP service. The Dhcp4 service may be partly initialized,
147 or partly destoried. If a resource is destoried, it is marked as so in
148 case the destory failed and being called again later.
150 @param DhcpSb The DHCP service instance to destory.
152 @retval EFI_SUCCESS The DHCP service is successfully closed.
157 IN DHCP_SERVICE
*DhcpSb
160 DhcpCleanLease (DhcpSb
);
162 if (DhcpSb
->UdpIo
!= NULL
) {
163 UdpIoFreePort (DhcpSb
->UdpIo
);
164 DhcpSb
->UdpIo
= NULL
;
167 if (DhcpSb
->Timer
!= NULL
) {
168 gBS
->SetTimer (DhcpSb
->Timer
, TimerCancel
, 0);
169 gBS
->CloseEvent (DhcpSb
->Timer
);
171 DhcpSb
->Timer
= NULL
;
180 Create a new DHCP service binding instance for the controller.
182 @param Controller The controller to install DHCP service binding
184 @param ImageHandle The driver's image handle
185 @param Service The variable to receive the created DHCP service
188 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource .
189 @retval EFI_SUCCESS The DHCP service instance is created.
194 IN EFI_HANDLE Controller
,
195 IN EFI_HANDLE ImageHandle
,
196 OUT DHCP_SERVICE
**Service
199 DHCP_SERVICE
*DhcpSb
;
203 DhcpSb
= AllocateZeroPool (sizeof (DHCP_SERVICE
));
205 if (DhcpSb
== NULL
) {
206 return EFI_OUT_OF_RESOURCES
;
209 DhcpSb
->Signature
= DHCP_SERVICE_SIGNATURE
;
210 DhcpSb
->ServiceBinding
= mDhcp4ServiceBindingTemplete
;
211 DhcpSb
->ServiceState
= DHCP_UNCONFIGED
;
212 DhcpSb
->InDestory
= FALSE
;
213 DhcpSb
->Controller
= Controller
;
214 DhcpSb
->Image
= ImageHandle
;
215 InitializeListHead (&DhcpSb
->Children
);
216 DhcpSb
->DhcpState
= Dhcp4Stopped
;
217 DhcpSb
->Xid
= NET_RANDOM (NetRandomInitSeed ());
220 // Create various resources, UdpIo, Timer, and get Mac address
222 Status
= gBS
->CreateEvent (
223 EVT_NOTIFY_SIGNAL
| EVT_TIMER
,
230 if (EFI_ERROR (Status
)) {
234 DhcpSb
->UdpIo
= UdpIoCreatePort (Controller
, ImageHandle
, DhcpConfigUdpIo
, NULL
);
236 if (DhcpSb
->UdpIo
== NULL
) {
237 Status
= EFI_OUT_OF_RESOURCES
;
241 DhcpSb
->HwLen
= (UINT8
) DhcpSb
->UdpIo
->SnpMode
.HwAddressSize
;
242 DhcpSb
->HwType
= DhcpSb
->UdpIo
->SnpMode
.IfType
;
243 CopyMem (&DhcpSb
->Mac
, &DhcpSb
->UdpIo
->SnpMode
.CurrentAddress
, sizeof (DhcpSb
->Mac
));
249 Dhcp4CloseService (DhcpSb
);
250 gBS
->FreePool (DhcpSb
);
257 Start this driver on ControllerHandle.
259 @param This Protocol instance pointer.
260 @param ControllerHandle Handle of device to bind driver to
261 @param RemainingDevicePath Optional parameter use to pick a specific child
264 @retval EFI_SUCCES This driver is added to ControllerHandle
265 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
266 @retval other This driver does not support this device
271 Dhcp4DriverBindingStart (
272 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
273 IN EFI_HANDLE ControllerHandle
,
274 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
277 DHCP_SERVICE
*DhcpSb
;
281 // First: test for the DHCP4 Protocol
283 Status
= gBS
->OpenProtocol (
285 &gEfiDhcp4ServiceBindingProtocolGuid
,
287 This
->DriverBindingHandle
,
289 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
292 if (Status
== EFI_SUCCESS
) {
293 return EFI_ALREADY_STARTED
;
296 Status
= Dhcp4CreateService (ControllerHandle
, This
->DriverBindingHandle
, &DhcpSb
);
298 if (EFI_ERROR (Status
)) {
302 Status
= gBS
->SetTimer (DhcpSb
->Timer
, TimerPeriodic
, TICKS_PER_SECOND
);
304 if (EFI_ERROR (Status
)) {
309 // Install the Dhcp4ServiceBinding Protocol onto ControlerHandle
311 Status
= gBS
->InstallMultipleProtocolInterfaces (
313 &gEfiDhcp4ServiceBindingProtocolGuid
,
314 &DhcpSb
->ServiceBinding
,
318 if (EFI_ERROR (Status
)) {
325 Dhcp4CloseService (DhcpSb
);
326 gBS
->FreePool (DhcpSb
);
332 Stop this driver on ControllerHandle.
334 @param This Protocol instance pointer.
335 @param ControllerHandle Handle of device to stop driver on
336 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number
337 of children is zero stop the entire bus driver.
338 @param ChildHandleBuffer List of Child Handles to Stop.
340 @retval EFI_SUCCES This driver is removed ControllerHandle
341 @retval other This driver was not removed from this device
346 Dhcp4DriverBindingStop (
347 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
348 IN EFI_HANDLE ControllerHandle
,
349 IN UINTN NumberOfChildren
,
350 IN EFI_HANDLE
*ChildHandleBuffer
353 EFI_SERVICE_BINDING_PROTOCOL
*ServiceBinding
;
354 DHCP_SERVICE
*DhcpSb
;
355 DHCP_PROTOCOL
*Instance
;
356 EFI_HANDLE NicHandle
;
361 // DHCP driver opens UDP child, So, the ControllerHandle is the
362 // UDP child handle. locate the Nic handle first.
364 NicHandle
= NetLibGetNicHandle (ControllerHandle
, &gEfiUdp4ProtocolGuid
);
366 if (NicHandle
== NULL
) {
367 return EFI_DEVICE_ERROR
;
370 Status
= gBS
->OpenProtocol (
372 &gEfiDhcp4ServiceBindingProtocolGuid
,
373 (VOID
**) &ServiceBinding
,
374 This
->DriverBindingHandle
,
376 EFI_OPEN_PROTOCOL_GET_PROTOCOL
379 if (EFI_ERROR (Status
)) {
380 return EFI_DEVICE_ERROR
;
383 DhcpSb
= DHCP_SERVICE_FROM_THIS (ServiceBinding
);
385 if (DhcpSb
->InDestory
) {
389 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
391 if (NumberOfChildren
== 0) {
393 DhcpSb
->InDestory
= TRUE
;
394 DhcpSb
->ServiceState
= DHCP_DESTORY
;
396 gBS
->UninstallProtocolInterface (
398 &gEfiDhcp4ServiceBindingProtocolGuid
,
402 Dhcp4CloseService (DhcpSb
);
404 gBS
->FreePool (DhcpSb
);
407 // Don't use NET_LIST_FOR_EACH_SAFE here, Dhcp4ServiceBindingDestoryChild
408 // may cause other child to be deleted.
410 while (!IsListEmpty (&DhcpSb
->Children
)) {
411 Instance
= NET_LIST_HEAD (&DhcpSb
->Children
, DHCP_PROTOCOL
, Link
);
412 ServiceBinding
->DestroyChild (ServiceBinding
, Instance
->Handle
);
415 if (DhcpSb
->NumChildren
!= 0) {
416 Status
= EFI_DEVICE_ERROR
;
420 gBS
->RestoreTPL (OldTpl
);
427 Initialize a new DHCP child.
429 @param DhcpSb The dhcp service instance
430 @param Instance The dhcp instance to initialize
437 IN DHCP_SERVICE
*DhcpSb
,
438 IN DHCP_PROTOCOL
*Instance
441 Instance
->Signature
= DHCP_PROTOCOL_SIGNATURE
;
442 CopyMem (&Instance
->Dhcp4Protocol
, &mDhcp4ProtocolTemplate
, sizeof (Instance
->Dhcp4Protocol
));
443 InitializeListHead (&Instance
->Link
);
444 Instance
->Handle
= NULL
;
445 Instance
->Service
= DhcpSb
;
446 Instance
->InDestory
= FALSE
;
447 Instance
->CompletionEvent
= NULL
;
448 Instance
->RenewRebindEvent
= NULL
;
449 Instance
->Token
= NULL
;
450 Instance
->UdpIo
= NULL
;
451 NetbufQueInit (&Instance
->ResponseQueue
);
456 Creates a child handle with a set of DHCP4 services.
458 @param This Protocol instance pointer.
459 @param ChildHandle Pointer to the handle of the child to create. If
460 it is NULL, then a new handle is created. If it
461 is not NULL, then the DHCP4 services are added to
462 the existing child handle.
464 @retval EFI_SUCCES The child handle was created with the DHCP4
466 @retval EFI_OUT_OF_RESOURCES There are not enough resources to create the child
467 @retval other The child handle was not created
472 Dhcp4ServiceBindingCreateChild (
473 IN EFI_SERVICE_BINDING_PROTOCOL
*This
,
474 IN EFI_HANDLE
*ChildHandle
477 DHCP_SERVICE
*DhcpSb
;
478 DHCP_PROTOCOL
*Instance
;
483 if ((This
== NULL
) || (ChildHandle
== NULL
)) {
484 return EFI_INVALID_PARAMETER
;
487 Instance
= AllocatePool (sizeof (*Instance
));
489 if (Instance
== NULL
) {
490 return EFI_OUT_OF_RESOURCES
;
493 DhcpSb
= DHCP_SERVICE_FROM_THIS (This
);
494 DhcpInitProtocol (DhcpSb
, Instance
);
497 // Install DHCP4 onto ChildHandle
499 Status
= gBS
->InstallMultipleProtocolInterfaces (
501 &gEfiDhcp4ProtocolGuid
,
502 &Instance
->Dhcp4Protocol
,
506 if (EFI_ERROR (Status
)) {
507 gBS
->FreePool (Instance
);
511 Instance
->Handle
= *ChildHandle
;
514 // Open the Udp4 protocol BY_CHILD.
516 Status
= gBS
->OpenProtocol (
517 DhcpSb
->UdpIo
->UdpHandle
,
518 &gEfiUdp4ProtocolGuid
,
520 gDhcp4DriverBinding
.DriverBindingHandle
,
522 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
524 if (EFI_ERROR (Status
)) {
525 gBS
->UninstallMultipleProtocolInterfaces (
527 &gEfiDhcp4ProtocolGuid
,
528 &Instance
->Dhcp4Protocol
,
532 gBS
->FreePool (Instance
);
536 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
538 InsertTailList (&DhcpSb
->Children
, &Instance
->Link
);
539 DhcpSb
->NumChildren
++;
541 gBS
->RestoreTPL (OldTpl
);
548 Destroys a child handle with a set of DHCP4 services.
550 @param This Protocol instance pointer.
551 @param ChildHandle Handle of the child to destroy
553 @retval EFI_SUCCES The DHCP4 service is removed from the child handle
554 @retval EFI_UNSUPPORTED The child handle does not support the DHCP4
556 @retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
557 @retval EFI_ACCESS_DENIED The child handle could not be destroyed because
558 its DHCP4 services are being used.
559 @retval other The child handle was not destroyed
564 Dhcp4ServiceBindingDestroyChild (
565 IN EFI_SERVICE_BINDING_PROTOCOL
*This
,
566 IN EFI_HANDLE ChildHandle
569 DHCP_SERVICE
*DhcpSb
;
570 DHCP_PROTOCOL
*Instance
;
571 EFI_DHCP4_PROTOCOL
*Dhcp
;
575 if ((This
== NULL
) || (ChildHandle
== NULL
)) {
576 return EFI_INVALID_PARAMETER
;
580 // Retrieve the private context data structures
582 Status
= gBS
->OpenProtocol (
584 &gEfiDhcp4ProtocolGuid
,
586 gDhcp4DriverBinding
.DriverBindingHandle
,
588 EFI_OPEN_PROTOCOL_GET_PROTOCOL
591 if (EFI_ERROR (Status
)) {
592 return EFI_UNSUPPORTED
;
595 Instance
= DHCP_INSTANCE_FROM_THIS (Dhcp
);
596 DhcpSb
= DHCP_SERVICE_FROM_THIS (This
);
598 if (Instance
->Service
!= DhcpSb
) {
599 return EFI_INVALID_PARAMETER
;
603 // A child can be destoried more than once. For example,
604 // Dhcp4DriverBindingStop will destory all of its children.
605 // when caller driver is being stopped, it will destory the
606 // dhcp child it opens.
608 if (Instance
->InDestory
) {
612 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
613 Instance
->InDestory
= TRUE
;
616 // Close the Udp4 protocol.
619 DhcpSb
->UdpIo
->UdpHandle
,
620 &gEfiUdp4ProtocolGuid
,
621 gDhcp4DriverBinding
.DriverBindingHandle
,
626 // Uninstall the DHCP4 protocol first to enable a top down destruction.
628 Status
= gBS
->UninstallProtocolInterface (
630 &gEfiDhcp4ProtocolGuid
,
634 if (EFI_ERROR (Status
)) {
635 Instance
->InDestory
= FALSE
;
637 gBS
->RestoreTPL (OldTpl
);
641 if (DhcpSb
->ActiveChild
== Instance
) {
642 DhcpYieldControl (DhcpSb
);
645 RemoveEntryList (&Instance
->Link
);
646 DhcpSb
->NumChildren
--;
648 gBS
->RestoreTPL (OldTpl
);
650 gBS
->FreePool (Instance
);