3 Copyright (c) 2006 - 2007, 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
42 Dhcp4DriverEntryPoint (
43 IN EFI_HANDLE ImageHandle
,
44 IN EFI_SYSTEM_TABLE
*SystemTable
50 Entry point of the DHCP driver to install various protocols.
54 ImageHandle - The driver's image handle
55 SystemTable - The system table
59 EFI_SUCCESS - All the related protocols are installed.
60 Others - Failed to install the protocols.
64 return EfiLibInstallDriverBindingComponentName2 (
76 Test to see if DHCP driver supports the ControllerHandle.
78 @param This Protocol instance pointer.
79 @param ControllerHandle Handle of device to test
80 @param RemainingDevicePath Optional parameter use to pick a specific child
83 @retval EFI_SUCCES This driver supports this device
84 @retval other This driver does not support this device
89 Dhcp4DriverBindingSupported (
90 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
91 IN EFI_HANDLE ControllerHandle
,
92 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
97 Status
= gBS
->OpenProtocol (
99 &gEfiUdp4ServiceBindingProtocolGuid
,
101 This
->DriverBindingHandle
,
103 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
112 Configure the default UDP child to receive all the DHCP traffics
113 on this network interface.
115 @param UdpIo The UDP IO port to configure
116 @param Context The context to the function
118 @retval EFI_SUCCESS The UDP IO port is successfully configured.
119 @retval Others Failed to configure the UDP child.
124 IN UDP_IO_PORT
*UdpIo
,
128 EFI_UDP4_CONFIG_DATA UdpConfigData
;
130 UdpConfigData
.AcceptBroadcast
= TRUE
;
131 UdpConfigData
.AcceptPromiscuous
= FALSE
;
132 UdpConfigData
.AcceptAnyPort
= FALSE
;
133 UdpConfigData
.AllowDuplicatePort
= TRUE
;
134 UdpConfigData
.TypeOfService
= 0;
135 UdpConfigData
.TimeToLive
= 64;
136 UdpConfigData
.DoNotFragment
= FALSE
;
137 UdpConfigData
.ReceiveTimeout
= 0;
138 UdpConfigData
.TransmitTimeout
= 0;
140 UdpConfigData
.UseDefaultAddress
= FALSE
;
141 UdpConfigData
.StationPort
= DHCP_CLIENT_PORT
;
142 UdpConfigData
.RemotePort
= DHCP_SERVER_PORT
;
144 ZeroMem (&UdpConfigData
.StationAddress
, sizeof (EFI_IPv4_ADDRESS
));
145 ZeroMem (&UdpConfigData
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
146 ZeroMem (&UdpConfigData
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
));
148 return UdpIo
->Udp
->Configure (UdpIo
->Udp
, &UdpConfigData
);;
154 Destory the DHCP service. The Dhcp4 service may be partly initialized,
155 or partly destoried. If a resource is destoried, it is marked as so in
156 case the destory failed and being called again later.
158 @param DhcpSb The DHCP service instance to destory.
160 @retval EFI_SUCCESS The DHCP service is successfully closed.
165 IN DHCP_SERVICE
*DhcpSb
168 DhcpCleanLease (DhcpSb
);
170 if (DhcpSb
->UdpIo
!= NULL
) {
171 UdpIoFreePort (DhcpSb
->UdpIo
);
172 DhcpSb
->UdpIo
= NULL
;
175 if (DhcpSb
->Timer
!= NULL
) {
176 gBS
->SetTimer (DhcpSb
->Timer
, TimerCancel
, 0);
177 gBS
->CloseEvent (DhcpSb
->Timer
);
179 DhcpSb
->Timer
= NULL
;
188 Create a new DHCP service binding instance for the controller.
190 @param Controller The controller to install DHCP service binding
192 @param ImageHandle The driver's image handle
193 @param Service The variable to receive the created DHCP service
196 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource .
197 @retval EFI_SUCCESS The DHCP service instance is created.
202 IN EFI_HANDLE Controller
,
203 IN EFI_HANDLE ImageHandle
,
204 OUT DHCP_SERVICE
**Service
207 DHCP_SERVICE
*DhcpSb
;
211 DhcpSb
= AllocateZeroPool (sizeof (DHCP_SERVICE
));
213 if (DhcpSb
== NULL
) {
214 return EFI_OUT_OF_RESOURCES
;
217 DhcpSb
->Signature
= DHCP_SERVICE_SIGNATURE
;
218 DhcpSb
->ServiceBinding
= mDhcp4ServiceBindingTemplete
;
219 DhcpSb
->ServiceState
= DHCP_UNCONFIGED
;
220 DhcpSb
->InDestory
= FALSE
;
221 DhcpSb
->Controller
= Controller
;
222 DhcpSb
->Image
= ImageHandle
;
223 InitializeListHead (&DhcpSb
->Children
);
224 DhcpSb
->DhcpState
= Dhcp4Stopped
;
225 DhcpSb
->Xid
= NET_RANDOM (NetRandomInitSeed ());
228 // Create various resources, UdpIo, Timer, and get Mac address
230 Status
= gBS
->CreateEvent (
231 EVT_NOTIFY_SIGNAL
| EVT_TIMER
,
238 if (EFI_ERROR (Status
)) {
242 DhcpSb
->UdpIo
= UdpIoCreatePort (Controller
, ImageHandle
, DhcpConfigUdpIo
, NULL
);
244 if (DhcpSb
->UdpIo
== NULL
) {
245 Status
= EFI_OUT_OF_RESOURCES
;
249 DhcpSb
->HwLen
= (UINT8
) DhcpSb
->UdpIo
->SnpMode
.HwAddressSize
;
250 DhcpSb
->HwType
= DhcpSb
->UdpIo
->SnpMode
.IfType
;
251 CopyMem (&DhcpSb
->Mac
, &DhcpSb
->UdpIo
->SnpMode
.CurrentAddress
, sizeof (DhcpSb
->Mac
));
257 Dhcp4CloseService (DhcpSb
);
258 gBS
->FreePool (DhcpSb
);
265 Start this driver on ControllerHandle.
267 @param This Protocol instance pointer.
268 @param ControllerHandle Handle of device to bind driver to
269 @param RemainingDevicePath Optional parameter use to pick a specific child
272 @retval EFI_SUCCES This driver is added to ControllerHandle
273 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
274 @retval other This driver does not support this device
279 Dhcp4DriverBindingStart (
280 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
281 IN EFI_HANDLE ControllerHandle
,
282 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
285 DHCP_SERVICE
*DhcpSb
;
289 // First: test for the DHCP4 Protocol
291 Status
= gBS
->OpenProtocol (
293 &gEfiDhcp4ServiceBindingProtocolGuid
,
295 This
->DriverBindingHandle
,
297 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
300 if (Status
== EFI_SUCCESS
) {
301 return EFI_ALREADY_STARTED
;
304 Status
= Dhcp4CreateService (ControllerHandle
, This
->DriverBindingHandle
, &DhcpSb
);
306 if (EFI_ERROR (Status
)) {
310 Status
= gBS
->SetTimer (DhcpSb
->Timer
, TimerPeriodic
, TICKS_PER_SECOND
);
312 if (EFI_ERROR (Status
)) {
317 // Install the Dhcp4ServiceBinding Protocol onto ControlerHandle
319 Status
= gBS
->InstallMultipleProtocolInterfaces (
321 &gEfiDhcp4ServiceBindingProtocolGuid
,
322 &DhcpSb
->ServiceBinding
,
326 if (EFI_ERROR (Status
)) {
333 Dhcp4CloseService (DhcpSb
);
334 gBS
->FreePool (DhcpSb
);
340 Stop this driver on ControllerHandle.
342 @param This Protocol instance pointer.
343 @param ControllerHandle Handle of device to stop driver on
344 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number
345 of children is zero stop the entire bus driver.
346 @param ChildHandleBuffer List of Child Handles to Stop.
348 @retval EFI_SUCCES This driver is removed ControllerHandle
349 @retval other This driver was not removed from this device
354 Dhcp4DriverBindingStop (
355 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
356 IN EFI_HANDLE ControllerHandle
,
357 IN UINTN NumberOfChildren
,
358 IN EFI_HANDLE
*ChildHandleBuffer
361 EFI_SERVICE_BINDING_PROTOCOL
*ServiceBinding
;
362 DHCP_SERVICE
*DhcpSb
;
363 DHCP_PROTOCOL
*Instance
;
364 EFI_HANDLE NicHandle
;
369 // DHCP driver opens UDP child, So, the ControllerHandle is the
370 // UDP child handle. locate the Nic handle first.
372 NicHandle
= NetLibGetNicHandle (ControllerHandle
, &gEfiUdp4ProtocolGuid
);
374 if (NicHandle
== NULL
) {
375 return EFI_DEVICE_ERROR
;
378 Status
= gBS
->OpenProtocol (
380 &gEfiDhcp4ServiceBindingProtocolGuid
,
381 (VOID
**) &ServiceBinding
,
382 This
->DriverBindingHandle
,
384 EFI_OPEN_PROTOCOL_GET_PROTOCOL
387 if (EFI_ERROR (Status
)) {
388 return EFI_DEVICE_ERROR
;
391 DhcpSb
= DHCP_SERVICE_FROM_THIS (ServiceBinding
);
393 if (DhcpSb
->InDestory
) {
397 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
399 if (NumberOfChildren
== 0) {
401 DhcpSb
->InDestory
= TRUE
;
402 DhcpSb
->ServiceState
= DHCP_DESTORY
;
404 gBS
->UninstallProtocolInterface (
406 &gEfiDhcp4ServiceBindingProtocolGuid
,
410 Dhcp4CloseService (DhcpSb
);
412 gBS
->FreePool (DhcpSb
);
415 // Don't use NET_LIST_FOR_EACH_SAFE here, Dhcp4ServiceBindingDestoryChild
416 // may cause other child to be deleted.
418 while (!IsListEmpty (&DhcpSb
->Children
)) {
419 Instance
= NET_LIST_HEAD (&DhcpSb
->Children
, DHCP_PROTOCOL
, Link
);
420 ServiceBinding
->DestroyChild (ServiceBinding
, Instance
->Handle
);
423 if (DhcpSb
->NumChildren
!= 0) {
424 Status
= EFI_DEVICE_ERROR
;
428 gBS
->RestoreTPL (OldTpl
);
435 Initialize a new DHCP child
437 @param DhcpSb The dhcp service instance
438 @param Instance The dhcp instance to initialize
445 IN DHCP_SERVICE
*DhcpSb
,
446 IN DHCP_PROTOCOL
*Instance
449 Instance
->Signature
= DHCP_PROTOCOL_SIGNATURE
;
450 CopyMem (&Instance
->Dhcp4Protocol
, &mDhcp4ProtocolTemplate
, sizeof (Instance
->Dhcp4Protocol
));
451 InitializeListHead (&Instance
->Link
);
452 Instance
->Handle
= NULL
;
453 Instance
->Service
= DhcpSb
;
454 Instance
->InDestory
= FALSE
;
455 Instance
->CompletionEvent
= NULL
;
456 Instance
->RenewRebindEvent
= NULL
;
457 Instance
->Token
= NULL
;
458 Instance
->UdpIo
= NULL
;
459 NetbufQueInit (&Instance
->ResponseQueue
);
464 Creates a child handle with a set of DHCP4 services.
466 @param This Protocol instance pointer.
467 @param ChildHandle Pointer to the handle of the child to create. If
468 it is NULL, then a new handle is created. If it
469 is not NULL, then the DHCP4 services are added to
470 the existing child handle.
472 @retval EFI_SUCCES The child handle was created with the DHCP4
474 @retval EFI_OUT_OF_RESOURCES There are not enough resources to create the child
475 @retval other The child handle was not created
480 Dhcp4ServiceBindingCreateChild (
481 IN EFI_SERVICE_BINDING_PROTOCOL
*This
,
482 IN EFI_HANDLE
*ChildHandle
485 DHCP_SERVICE
*DhcpSb
;
486 DHCP_PROTOCOL
*Instance
;
491 if ((This
== NULL
) || (ChildHandle
== NULL
)) {
492 return EFI_INVALID_PARAMETER
;
495 Instance
= AllocatePool (sizeof (*Instance
));
497 if (Instance
== NULL
) {
498 return EFI_OUT_OF_RESOURCES
;
501 DhcpSb
= DHCP_SERVICE_FROM_THIS (This
);
502 DhcpInitProtocol (DhcpSb
, Instance
);
505 // Install DHCP4 onto ChildHandle
507 Status
= gBS
->InstallMultipleProtocolInterfaces (
509 &gEfiDhcp4ProtocolGuid
,
510 &Instance
->Dhcp4Protocol
,
514 if (EFI_ERROR (Status
)) {
515 gBS
->FreePool (Instance
);
519 Instance
->Handle
= *ChildHandle
;
522 // Open the Udp4 protocol BY_CHILD.
524 Status
= gBS
->OpenProtocol (
525 DhcpSb
->UdpIo
->UdpHandle
,
526 &gEfiUdp4ProtocolGuid
,
528 gDhcp4DriverBinding
.DriverBindingHandle
,
530 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
532 if (EFI_ERROR (Status
)) {
533 gBS
->UninstallMultipleProtocolInterfaces (
535 &gEfiDhcp4ProtocolGuid
,
536 &Instance
->Dhcp4Protocol
,
540 gBS
->FreePool (Instance
);
544 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
546 InsertTailList (&DhcpSb
->Children
, &Instance
->Link
);
547 DhcpSb
->NumChildren
++;
549 gBS
->RestoreTPL (OldTpl
);
556 Destroys a child handle with a set of DHCP4 services.
558 @param This Protocol instance pointer.
559 @param ChildHandle Handle of the child to destroy
561 @retval EFI_SUCCES The DHCP4 service is removed from the child handle
562 @retval EFI_UNSUPPORTED The child handle does not support the DHCP4
564 @retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
565 @retval EFI_ACCESS_DENIED The child handle could not be destroyed because
566 its DHCP4 services are being used.
567 @retval other The child handle was not destroyed
572 Dhcp4ServiceBindingDestroyChild (
573 IN EFI_SERVICE_BINDING_PROTOCOL
*This
,
574 IN EFI_HANDLE ChildHandle
577 DHCP_SERVICE
*DhcpSb
;
578 DHCP_PROTOCOL
*Instance
;
579 EFI_DHCP4_PROTOCOL
*Dhcp
;
583 if ((This
== NULL
) || (ChildHandle
== NULL
)) {
584 return EFI_INVALID_PARAMETER
;
588 // Retrieve the private context data structures
590 Status
= gBS
->OpenProtocol (
592 &gEfiDhcp4ProtocolGuid
,
594 gDhcp4DriverBinding
.DriverBindingHandle
,
596 EFI_OPEN_PROTOCOL_GET_PROTOCOL
599 if (EFI_ERROR (Status
)) {
600 return EFI_UNSUPPORTED
;
603 Instance
= DHCP_INSTANCE_FROM_THIS (Dhcp
);
604 DhcpSb
= DHCP_SERVICE_FROM_THIS (This
);
606 if (Instance
->Service
!= DhcpSb
) {
607 return EFI_INVALID_PARAMETER
;
611 // A child can be destoried more than once. For example,
612 // Dhcp4DriverBindingStop will destory all of its children.
613 // when caller driver is being stopped, it will destory the
614 // dhcp child it opens.
616 if (Instance
->InDestory
) {
620 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
621 Instance
->InDestory
= TRUE
;
624 // Close the Udp4 protocol.
627 DhcpSb
->UdpIo
->UdpHandle
,
628 &gEfiUdp4ProtocolGuid
,
629 gDhcp4DriverBinding
.DriverBindingHandle
,
634 // Uninstall the DHCP4 protocol first to enable a top down destruction.
636 Status
= gBS
->UninstallProtocolInterface (
638 &gEfiDhcp4ProtocolGuid
,
642 if (EFI_ERROR (Status
)) {
643 Instance
->InDestory
= FALSE
;
645 gBS
->RestoreTPL (OldTpl
);
649 if (DhcpSb
->ActiveChild
== Instance
) {
650 DhcpYieldControl (DhcpSb
);
653 RemoveEntryList (&Instance
->Link
);
654 DhcpSb
->NumChildren
--;
656 gBS
->RestoreTPL (OldTpl
);
658 gBS
->FreePool (Instance
);