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 mDhcp4ServiceBindingTemplate
= {
35 Dhcp4ServiceBindingCreateChild
,
36 Dhcp4ServiceBindingDestroyChild
40 This is the declaration of an EFI image entry point. This entry point is
41 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
42 both device drivers and bus drivers.
44 Entry point of the DHCP driver to install various protocols.
46 @param ImageHandle The firmware allocated handle for the UEFI image.
47 @param SystemTable A pointer to the EFI System Table.
49 @retval EFI_SUCCESS The operation completed successfully.
50 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
55 Dhcp4DriverEntryPoint (
56 IN EFI_HANDLE ImageHandle
,
57 IN EFI_SYSTEM_TABLE
*SystemTable
60 return EfiLibInstallDriverBindingComponentName2 (
72 Test to see if this driver supports ControllerHandle. This service
73 is called by the EFI boot service ConnectController(). In
74 order to make drivers as small as possible, there are a few calling
75 restrictions for this service. ConnectController() must
76 follow these calling restrictions. If any other agent wishes to call
77 Supported() it must also follow these calling restrictions.
79 @param This Protocol instance pointer.
80 @param ControllerHandle Handle of device to test
81 @param RemainingDevicePath Optional parameter use to pick a specific child
84 @retval EFI_SUCCESS This driver supports this device
85 @retval EFI_ALREADY_STARTED This driver is already running on this device
86 @retval other This driver does not support this device
91 Dhcp4DriverBindingSupported (
92 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
93 IN EFI_HANDLE ControllerHandle
,
94 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
99 Status
= gBS
->OpenProtocol (
101 &gEfiUdp4ServiceBindingProtocolGuid
,
103 This
->DriverBindingHandle
,
105 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
114 Configure the default UDP child to receive all the DHCP traffics
115 on this network interface.
117 @param UdpIo The UDP IO port to configure
118 @param Context The context to the function
120 @retval EFI_SUCCESS The UDP IO port is successfully configured.
121 @retval Others Failed to configure the UDP child.
126 IN UDP_IO_PORT
*UdpIo
,
130 EFI_UDP4_CONFIG_DATA UdpConfigData
;
132 UdpConfigData
.AcceptBroadcast
= TRUE
;
133 UdpConfigData
.AcceptPromiscuous
= FALSE
;
134 UdpConfigData
.AcceptAnyPort
= FALSE
;
135 UdpConfigData
.AllowDuplicatePort
= TRUE
;
136 UdpConfigData
.TypeOfService
= 0;
137 UdpConfigData
.TimeToLive
= 64;
138 UdpConfigData
.DoNotFragment
= FALSE
;
139 UdpConfigData
.ReceiveTimeout
= 0;
140 UdpConfigData
.TransmitTimeout
= 0;
142 UdpConfigData
.UseDefaultAddress
= FALSE
;
143 UdpConfigData
.StationPort
= DHCP_CLIENT_PORT
;
144 UdpConfigData
.RemotePort
= DHCP_SERVER_PORT
;
146 ZeroMem (&UdpConfigData
.StationAddress
, sizeof (EFI_IPv4_ADDRESS
));
147 ZeroMem (&UdpConfigData
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
148 ZeroMem (&UdpConfigData
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
));
150 return UdpIo
->Udp
->Configure (UdpIo
->Udp
, &UdpConfigData
);;
156 Destory the DHCP service. The Dhcp4 service may be partly initialized,
157 or partly destroyed. If a resource is destroyed, it is marked as so in
158 case the destroy failed and being called again later.
160 @param DhcpSb The DHCP service instance to destory.
162 @retval EFI_SUCCESS Always return success.
167 IN DHCP_SERVICE
*DhcpSb
170 DhcpCleanLease (DhcpSb
);
172 if (DhcpSb
->UdpIo
!= NULL
) {
173 UdpIoFreePort (DhcpSb
->UdpIo
);
174 DhcpSb
->UdpIo
= NULL
;
177 if (DhcpSb
->Timer
!= NULL
) {
178 gBS
->SetTimer (DhcpSb
->Timer
, TimerCancel
, 0);
179 gBS
->CloseEvent (DhcpSb
->Timer
);
181 DhcpSb
->Timer
= NULL
;
190 Create a new DHCP service binding instance for the controller.
192 @param Controller The controller to install DHCP service binding
194 @param ImageHandle The driver's image handle
195 @param Service The variable to receive the created DHCP service
198 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource .
199 @retval EFI_SUCCESS The DHCP service instance is created.
200 @retval other Other error occurs.
205 IN EFI_HANDLE Controller
,
206 IN EFI_HANDLE ImageHandle
,
207 OUT DHCP_SERVICE
**Service
210 DHCP_SERVICE
*DhcpSb
;
214 DhcpSb
= AllocateZeroPool (sizeof (DHCP_SERVICE
));
216 if (DhcpSb
== NULL
) {
217 return EFI_OUT_OF_RESOURCES
;
220 DhcpSb
->Signature
= DHCP_SERVICE_SIGNATURE
;
221 DhcpSb
->ServiceState
= DHCP_UNCONFIGED
;
222 DhcpSb
->InDestory
= FALSE
;
223 DhcpSb
->Controller
= Controller
;
224 DhcpSb
->Image
= ImageHandle
;
225 InitializeListHead (&DhcpSb
->Children
);
226 DhcpSb
->DhcpState
= Dhcp4Stopped
;
227 DhcpSb
->Xid
= NET_RANDOM (NetRandomInitSeed ());
229 &DhcpSb
->ServiceBinding
,
230 &mDhcp4ServiceBindingTemplate
,
231 sizeof (EFI_SERVICE_BINDING_PROTOCOL
)
234 // Create various resources, UdpIo, Timer, and get Mac address
236 Status
= gBS
->CreateEvent (
237 EVT_NOTIFY_SIGNAL
| EVT_TIMER
,
244 if (EFI_ERROR (Status
)) {
248 DhcpSb
->UdpIo
= UdpIoCreatePort (Controller
, ImageHandle
, DhcpConfigUdpIo
, NULL
);
250 if (DhcpSb
->UdpIo
== NULL
) {
251 Status
= EFI_OUT_OF_RESOURCES
;
255 DhcpSb
->HwLen
= (UINT8
) DhcpSb
->UdpIo
->SnpMode
.HwAddressSize
;
256 DhcpSb
->HwType
= DhcpSb
->UdpIo
->SnpMode
.IfType
;
257 CopyMem (&DhcpSb
->Mac
, &DhcpSb
->UdpIo
->SnpMode
.CurrentAddress
, sizeof (DhcpSb
->Mac
));
263 Dhcp4CloseService (DhcpSb
);
264 gBS
->FreePool (DhcpSb
);
271 Start this driver on ControllerHandle. This service is called by the
272 EFI boot service ConnectController(). In order to make
273 drivers as small as possible, there are a few calling restrictions for
274 this service. ConnectController() must follow these
275 calling restrictions. If any other agent wishes to call Start() it
276 must also follow these calling restrictions.
278 @param This Protocol instance pointer.
279 @param ControllerHandle Handle of device to bind driver to
280 @param RemainingDevicePath Optional parameter use to pick a specific child
283 @retval EFI_SUCCESS This driver is added to ControllerHandle
284 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
285 @retval other This driver does not support this device
290 Dhcp4DriverBindingStart (
291 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
292 IN EFI_HANDLE ControllerHandle
,
293 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
296 DHCP_SERVICE
*DhcpSb
;
300 // First: test for the DHCP4 Protocol
302 Status
= gBS
->OpenProtocol (
304 &gEfiDhcp4ServiceBindingProtocolGuid
,
306 This
->DriverBindingHandle
,
308 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
311 if (Status
== EFI_SUCCESS
) {
312 return EFI_ALREADY_STARTED
;
315 Status
= Dhcp4CreateService (ControllerHandle
, This
->DriverBindingHandle
, &DhcpSb
);
317 if (EFI_ERROR (Status
)) {
321 Status
= gBS
->SetTimer (DhcpSb
->Timer
, TimerPeriodic
, TICKS_PER_SECOND
);
323 if (EFI_ERROR (Status
)) {
328 // Install the Dhcp4ServiceBinding Protocol onto ControlerHandle
330 Status
= gBS
->InstallMultipleProtocolInterfaces (
332 &gEfiDhcp4ServiceBindingProtocolGuid
,
333 &DhcpSb
->ServiceBinding
,
337 if (EFI_ERROR (Status
)) {
344 Dhcp4CloseService (DhcpSb
);
345 gBS
->FreePool (DhcpSb
);
351 Stop this driver on ControllerHandle. This service is called by the
352 EFI boot service DisconnectController(). In order to
353 make drivers as small as possible, there are a few calling
354 restrictions for this service. DisconnectController()
355 must follow these calling restrictions. If any other agent wishes
356 to call Stop() it must also follow these calling restrictions.
358 @param This Protocol instance pointer.
359 @param ControllerHandle Handle of device to stop driver on
360 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
361 children is zero stop the entire bus driver.
362 @param ChildHandleBuffer List of Child Handles to Stop.
364 @retval EFI_SUCCESS This driver is removed ControllerHandle
365 @retval other This driver was not removed from this device
370 Dhcp4DriverBindingStop (
371 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
372 IN EFI_HANDLE ControllerHandle
,
373 IN UINTN NumberOfChildren
,
374 IN EFI_HANDLE
*ChildHandleBuffer
377 EFI_SERVICE_BINDING_PROTOCOL
*ServiceBinding
;
378 DHCP_SERVICE
*DhcpSb
;
379 DHCP_PROTOCOL
*Instance
;
380 EFI_HANDLE NicHandle
;
385 // DHCP driver opens UDP child, So, the ControllerHandle is the
386 // UDP child handle. locate the Nic handle first.
388 NicHandle
= NetLibGetNicHandle (ControllerHandle
, &gEfiUdp4ProtocolGuid
);
390 if (NicHandle
== NULL
) {
391 return EFI_DEVICE_ERROR
;
394 Status
= gBS
->OpenProtocol (
396 &gEfiDhcp4ServiceBindingProtocolGuid
,
397 (VOID
**) &ServiceBinding
,
398 This
->DriverBindingHandle
,
400 EFI_OPEN_PROTOCOL_GET_PROTOCOL
403 if (EFI_ERROR (Status
)) {
404 return EFI_DEVICE_ERROR
;
407 DhcpSb
= DHCP_SERVICE_FROM_THIS (ServiceBinding
);
409 if (DhcpSb
->InDestory
) {
413 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
415 if (NumberOfChildren
== 0) {
417 DhcpSb
->InDestory
= TRUE
;
418 DhcpSb
->ServiceState
= DHCP_DESTORY
;
420 gBS
->UninstallProtocolInterface (
422 &gEfiDhcp4ServiceBindingProtocolGuid
,
426 Dhcp4CloseService (DhcpSb
);
428 gBS
->FreePool (DhcpSb
);
431 // Don't use NET_LIST_FOR_EACH_SAFE here, Dhcp4ServiceBindingDestoryChild
432 // may cause other child to be deleted.
434 while (!IsListEmpty (&DhcpSb
->Children
)) {
435 Instance
= NET_LIST_HEAD (&DhcpSb
->Children
, DHCP_PROTOCOL
, Link
);
436 ServiceBinding
->DestroyChild (ServiceBinding
, Instance
->Handle
);
439 if (DhcpSb
->NumChildren
!= 0) {
440 Status
= EFI_DEVICE_ERROR
;
444 gBS
->RestoreTPL (OldTpl
);
451 Initialize a new DHCP instance.
453 @param DhcpSb The dhcp service instance
454 @param Instance The dhcp instance to initialize
461 IN DHCP_SERVICE
*DhcpSb
,
462 IN OUT DHCP_PROTOCOL
*Instance
465 Instance
->Signature
= DHCP_PROTOCOL_SIGNATURE
;
466 CopyMem (&Instance
->Dhcp4Protocol
, &mDhcp4ProtocolTemplate
, sizeof (Instance
->Dhcp4Protocol
));
467 InitializeListHead (&Instance
->Link
);
468 Instance
->Handle
= NULL
;
469 Instance
->Service
= DhcpSb
;
470 Instance
->InDestory
= FALSE
;
471 Instance
->CompletionEvent
= NULL
;
472 Instance
->RenewRebindEvent
= NULL
;
473 Instance
->Token
= NULL
;
474 Instance
->UdpIo
= NULL
;
475 NetbufQueInit (&Instance
->ResponseQueue
);
480 Creates a child handle with a set of I/O services.
482 @param This Protocol instance pointer.
483 @param ChildHandle Pointer to the handle of the child to create. If it is NULL,
484 then a new handle is created. If it is not NULL, then the
485 I/O services are added to the existing child handle.
487 @retval EFI_SUCCES The child handle was created with the I/O services
488 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
489 @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create
491 @retval other The child handle was not created
496 Dhcp4ServiceBindingCreateChild (
497 IN EFI_SERVICE_BINDING_PROTOCOL
*This
,
498 IN EFI_HANDLE
*ChildHandle
501 DHCP_SERVICE
*DhcpSb
;
502 DHCP_PROTOCOL
*Instance
;
507 if ((This
== NULL
) || (ChildHandle
== NULL
)) {
508 return EFI_INVALID_PARAMETER
;
511 Instance
= AllocatePool (sizeof (*Instance
));
513 if (Instance
== NULL
) {
514 return EFI_OUT_OF_RESOURCES
;
517 DhcpSb
= DHCP_SERVICE_FROM_THIS (This
);
518 DhcpInitProtocol (DhcpSb
, Instance
);
521 // Install DHCP4 onto ChildHandle
523 Status
= gBS
->InstallMultipleProtocolInterfaces (
525 &gEfiDhcp4ProtocolGuid
,
526 &Instance
->Dhcp4Protocol
,
530 if (EFI_ERROR (Status
)) {
531 gBS
->FreePool (Instance
);
535 Instance
->Handle
= *ChildHandle
;
538 // Open the Udp4 protocol BY_CHILD.
540 Status
= gBS
->OpenProtocol (
541 DhcpSb
->UdpIo
->UdpHandle
,
542 &gEfiUdp4ProtocolGuid
,
544 gDhcp4DriverBinding
.DriverBindingHandle
,
546 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
548 if (EFI_ERROR (Status
)) {
549 gBS
->UninstallMultipleProtocolInterfaces (
551 &gEfiDhcp4ProtocolGuid
,
552 &Instance
->Dhcp4Protocol
,
556 gBS
->FreePool (Instance
);
560 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
562 InsertTailList (&DhcpSb
->Children
, &Instance
->Link
);
563 DhcpSb
->NumChildren
++;
565 gBS
->RestoreTPL (OldTpl
);
572 Destroys a child handle with a set of I/O services.
574 @param This Protocol instance pointer.
575 @param ChildHandle Handle of the child to destroy
577 @retval EFI_SUCCES The I/O services were removed from the child handle
578 @retval EFI_UNSUPPORTED The child handle does not support the I/O services
579 that are being removed.
580 @retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
581 @retval EFI_ACCESS_DENIED The child handle could not be destroyed because its
582 I/O services are being used.
583 @retval other The child handle was not destroyed
588 Dhcp4ServiceBindingDestroyChild (
589 IN EFI_SERVICE_BINDING_PROTOCOL
*This
,
590 IN EFI_HANDLE ChildHandle
593 DHCP_SERVICE
*DhcpSb
;
594 DHCP_PROTOCOL
*Instance
;
595 EFI_DHCP4_PROTOCOL
*Dhcp
;
599 if ((This
== NULL
) || (ChildHandle
== NULL
)) {
600 return EFI_INVALID_PARAMETER
;
604 // Retrieve the private context data structures
606 Status
= gBS
->OpenProtocol (
608 &gEfiDhcp4ProtocolGuid
,
610 gDhcp4DriverBinding
.DriverBindingHandle
,
612 EFI_OPEN_PROTOCOL_GET_PROTOCOL
615 if (EFI_ERROR (Status
)) {
616 return EFI_UNSUPPORTED
;
619 Instance
= DHCP_INSTANCE_FROM_THIS (Dhcp
);
620 DhcpSb
= DHCP_SERVICE_FROM_THIS (This
);
622 if (Instance
->Service
!= DhcpSb
) {
623 return EFI_INVALID_PARAMETER
;
627 // A child can be destroyed more than once. For example,
628 // Dhcp4DriverBindingStop will destroy all of its children.
629 // when caller driver is being stopped, it will destory the
630 // dhcp child it opens.
632 if (Instance
->InDestory
) {
636 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
637 Instance
->InDestory
= TRUE
;
640 // Close the Udp4 protocol.
643 DhcpSb
->UdpIo
->UdpHandle
,
644 &gEfiUdp4ProtocolGuid
,
645 gDhcp4DriverBinding
.DriverBindingHandle
,
650 // Uninstall the DHCP4 protocol first to enable a top down destruction.
652 Status
= gBS
->UninstallProtocolInterface (
654 &gEfiDhcp4ProtocolGuid
,
658 if (EFI_ERROR (Status
)) {
659 Instance
->InDestory
= FALSE
;
661 gBS
->RestoreTPL (OldTpl
);
665 if (DhcpSb
->ActiveChild
== Instance
) {
666 DhcpYieldControl (DhcpSb
);
669 RemoveEntryList (&Instance
->Link
);
670 DhcpSb
->NumChildren
--;
672 gBS
->RestoreTPL (OldTpl
);
674 gBS
->FreePool (Instance
);