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 EfiLibInstallAllDriverProtocols (
77 Test to see if DHCP driver supports the ControllerHandle.
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_SUCCES This driver supports this device
85 @retval other This driver does not support this device
90 Dhcp4DriverBindingSupported (
91 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
92 IN EFI_HANDLE ControllerHandle
,
93 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
98 Status
= gBS
->OpenProtocol (
100 &gEfiUdp4ServiceBindingProtocolGuid
,
102 This
->DriverBindingHandle
,
104 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
113 Configure the default UDP child to receive all the DHCP traffics
114 on this network interface.
116 @param UdpIo The UDP IO port to configure
117 @param Context The context to the function
119 @retval EFI_SUCCESS The UDP IO port is successfully configured.
120 @retval Others Failed to configure the UDP child.
125 IN UDP_IO_PORT
*UdpIo
,
129 EFI_UDP4_CONFIG_DATA UdpConfigData
;
131 UdpConfigData
.AcceptBroadcast
= TRUE
;
132 UdpConfigData
.AcceptPromiscuous
= FALSE
;
133 UdpConfigData
.AcceptAnyPort
= FALSE
;
134 UdpConfigData
.AllowDuplicatePort
= TRUE
;
135 UdpConfigData
.TypeOfService
= 0;
136 UdpConfigData
.TimeToLive
= 64;
137 UdpConfigData
.DoNotFragment
= FALSE
;
138 UdpConfigData
.ReceiveTimeout
= 0;
139 UdpConfigData
.TransmitTimeout
= 0;
141 UdpConfigData
.UseDefaultAddress
= FALSE
;
142 UdpConfigData
.StationPort
= DHCP_CLIENT_PORT
;
143 UdpConfigData
.RemotePort
= DHCP_SERVER_PORT
;
145 NetZeroMem (&UdpConfigData
.StationAddress
, sizeof (EFI_IPv4_ADDRESS
));
146 NetZeroMem (&UdpConfigData
.SubnetMask
, sizeof (EFI_IPv4_ADDRESS
));
147 NetZeroMem (&UdpConfigData
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
));
149 return UdpIo
->Udp
->Configure (UdpIo
->Udp
, &UdpConfigData
);;
155 Destory the DHCP service. The Dhcp4 service may be partly initialized,
156 or partly destoried. If a resource is destoried, it is marked as so in
157 case the destory failed and being called again later.
159 @param DhcpSb The DHCP service instance to destory.
161 @retval EFI_SUCCESS The DHCP service is successfully closed.
166 IN DHCP_SERVICE
*DhcpSb
169 DhcpCleanLease (DhcpSb
);
171 if (DhcpSb
->UdpIo
!= NULL
) {
172 UdpIoFreePort (DhcpSb
->UdpIo
);
173 DhcpSb
->UdpIo
= NULL
;
176 if (DhcpSb
->Timer
!= NULL
) {
177 gBS
->SetTimer (DhcpSb
->Timer
, TimerCancel
, 0);
178 gBS
->CloseEvent (DhcpSb
->Timer
);
180 DhcpSb
->Timer
= NULL
;
189 Create a new DHCP service binding instance for the controller.
191 @param Controller The controller to install DHCP service binding
193 @param ImageHandle The driver's image handle
194 @param Service The variable to receive the created DHCP service
197 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource .
198 @retval EFI_SUCCESS The DHCP service instance is created.
203 IN EFI_HANDLE Controller
,
204 IN EFI_HANDLE ImageHandle
,
205 OUT DHCP_SERVICE
**Service
208 DHCP_SERVICE
*DhcpSb
;
212 DhcpSb
= NetAllocateZeroPool (sizeof (DHCP_SERVICE
));
214 if (DhcpSb
== NULL
) {
215 return EFI_OUT_OF_RESOURCES
;
218 DhcpSb
->Signature
= DHCP_SERVICE_SIGNATURE
;
219 DhcpSb
->ServiceBinding
= mDhcp4ServiceBindingTemplete
;
220 DhcpSb
->ServiceState
= DHCP_UNCONFIGED
;
221 DhcpSb
->InDestory
= FALSE
;
222 DhcpSb
->Controller
= Controller
;
223 DhcpSb
->Image
= ImageHandle
;
224 NetListInit (&DhcpSb
->Children
);
225 DhcpSb
->DhcpState
= Dhcp4Stopped
;
226 DhcpSb
->Xid
= NET_RANDOM (NetRandomInitSeed ());
229 // Create various resources, UdpIo, Timer, and get Mac address
231 Status
= gBS
->CreateEvent (
232 EVT_NOTIFY_SIGNAL
| EVT_TIMER
,
239 if (EFI_ERROR (Status
)) {
243 DhcpSb
->UdpIo
= UdpIoCreatePort (Controller
, ImageHandle
, DhcpConfigUdpIo
, NULL
);
245 if (DhcpSb
->UdpIo
== NULL
) {
246 Status
= EFI_OUT_OF_RESOURCES
;
250 DhcpSb
->HwLen
= (UINT8
) DhcpSb
->UdpIo
->SnpMode
.HwAddressSize
;
251 DhcpSb
->HwType
= DhcpSb
->UdpIo
->SnpMode
.IfType
;
252 CopyMem (&DhcpSb
->Mac
, &DhcpSb
->UdpIo
->SnpMode
.CurrentAddress
, sizeof (DhcpSb
->Mac
));
258 Dhcp4CloseService (DhcpSb
);
259 NetFreePool (DhcpSb
);
266 Start this driver on ControllerHandle.
268 @param This Protocol instance pointer.
269 @param ControllerHandle Handle of device to bind driver to
270 @param RemainingDevicePath Optional parameter use to pick a specific child
273 @retval EFI_SUCCES This driver is added to ControllerHandle
274 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
275 @retval other This driver does not support this device
280 Dhcp4DriverBindingStart (
281 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
282 IN EFI_HANDLE ControllerHandle
,
283 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
286 DHCP_SERVICE
*DhcpSb
;
290 // First: test for the DHCP4 Protocol
292 Status
= gBS
->OpenProtocol (
294 &gEfiDhcp4ServiceBindingProtocolGuid
,
296 This
->DriverBindingHandle
,
298 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
301 if (Status
== EFI_SUCCESS
) {
302 return EFI_ALREADY_STARTED
;
305 Status
= Dhcp4CreateService (ControllerHandle
, This
->DriverBindingHandle
, &DhcpSb
);
307 if (EFI_ERROR (Status
)) {
311 Status
= gBS
->SetTimer (DhcpSb
->Timer
, TimerPeriodic
, TICKS_PER_SECOND
);
313 if (EFI_ERROR (Status
)) {
318 // Install the Dhcp4ServiceBinding Protocol onto ControlerHandle
320 Status
= gBS
->InstallMultipleProtocolInterfaces (
322 &gEfiDhcp4ServiceBindingProtocolGuid
,
323 &DhcpSb
->ServiceBinding
,
327 if (EFI_ERROR (Status
)) {
334 Dhcp4CloseService (DhcpSb
);
335 NetFreePool (DhcpSb
);
341 Stop this driver on ControllerHandle.
343 @param This Protocol instance pointer.
344 @param ControllerHandle Handle of device to stop driver on
345 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number
346 of children is zero stop the entire bus driver.
347 @param ChildHandleBuffer List of Child Handles to Stop.
349 @retval EFI_SUCCES This driver is removed ControllerHandle
350 @retval other This driver was not removed from this device
355 Dhcp4DriverBindingStop (
356 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
357 IN EFI_HANDLE ControllerHandle
,
358 IN UINTN NumberOfChildren
,
359 IN EFI_HANDLE
*ChildHandleBuffer
362 EFI_SERVICE_BINDING_PROTOCOL
*ServiceBinding
;
363 DHCP_SERVICE
*DhcpSb
;
364 DHCP_PROTOCOL
*Instance
;
365 EFI_HANDLE NicHandle
;
370 // DHCP driver opens UDP child, So, the ControllerHandle is the
371 // UDP child handle. locate the Nic handle first.
373 NicHandle
= NetLibGetNicHandle (ControllerHandle
, &gEfiUdp4ProtocolGuid
);
375 if (NicHandle
== NULL
) {
379 Status
= gBS
->OpenProtocol (
381 &gEfiDhcp4ServiceBindingProtocolGuid
,
382 (VOID
**) &ServiceBinding
,
383 This
->DriverBindingHandle
,
385 EFI_OPEN_PROTOCOL_GET_PROTOCOL
388 if (EFI_ERROR (Status
)) {
389 return EFI_DEVICE_ERROR
;
392 DhcpSb
= DHCP_SERVICE_FROM_THIS (ServiceBinding
);
394 if (DhcpSb
->InDestory
) {
398 OldTpl
= NET_RAISE_TPL (NET_TPL_LOCK
);
399 DhcpSb
->InDestory
= TRUE
;
402 // Don't use NET_LIST_FOR_EACH_SAFE here, Dhcp4ServiceBindingDestoryChild
403 // may cause other child to be deleted.
405 while (!NetListIsEmpty (&DhcpSb
->Children
)) {
406 Instance
= NET_LIST_HEAD (&DhcpSb
->Children
, DHCP_PROTOCOL
, Link
);
407 Dhcp4ServiceBindingDestroyChild (ServiceBinding
, Instance
->Handle
);
410 if (DhcpSb
->NumChildren
!= 0) {
411 Status
= EFI_DEVICE_ERROR
;
415 DhcpSb
->ServiceState
= DHCP_DESTORY
;
417 Status
= gBS
->UninstallProtocolInterface (
419 &gEfiDhcp4ServiceBindingProtocolGuid
,
423 if (EFI_ERROR (Status
)) {
427 Dhcp4CloseService (DhcpSb
);
428 NET_RESTORE_TPL (OldTpl
);
430 NetFreePool (DhcpSb
);
434 DhcpSb
->InDestory
= FALSE
;
435 NET_RESTORE_TPL (OldTpl
);
441 Initialize a new DHCP child
443 @param DhcpSb The dhcp service instance
444 @param Instance The dhcp instance to initialize
451 IN DHCP_SERVICE
*DhcpSb
,
452 IN DHCP_PROTOCOL
*Instance
455 Instance
->Signature
= DHCP_PROTOCOL_SIGNATURE
;
456 CopyMem (&Instance
->Dhcp4Protocol
, &mDhcp4ProtocolTemplate
, sizeof (Instance
->Dhcp4Protocol
));
457 NetListInit (&Instance
->Link
);
458 Instance
->Handle
= NULL
;
459 Instance
->Service
= DhcpSb
;
460 Instance
->InDestory
= FALSE
;
461 Instance
->CompletionEvent
= NULL
;
462 Instance
->RenewRebindEvent
= NULL
;
463 Instance
->Token
= NULL
;
468 Creates a child handle with a set of DHCP4 services.
470 @param This Protocol instance pointer.
471 @param ChildHandle Pointer to the handle of the child to create. If
472 it is NULL, then a new handle is created. If it
473 is not NULL, then the DHCP4 services are added to
474 the existing child handle.
476 @retval EFI_SUCCES The child handle was created with the DHCP4
478 @retval EFI_OUT_OF_RESOURCES There are not enough resources to create the child
479 @retval other The child handle was not created
484 Dhcp4ServiceBindingCreateChild (
485 IN EFI_SERVICE_BINDING_PROTOCOL
*This
,
486 IN EFI_HANDLE
*ChildHandle
489 DHCP_SERVICE
*DhcpSb
;
490 DHCP_PROTOCOL
*Instance
;
495 if ((This
== NULL
) || (ChildHandle
== NULL
)) {
496 return EFI_INVALID_PARAMETER
;
499 Instance
= NetAllocatePool (sizeof (*Instance
));
501 if (Instance
== NULL
) {
502 return EFI_OUT_OF_RESOURCES
;
505 DhcpSb
= DHCP_SERVICE_FROM_THIS (This
);
506 DhcpInitProtocol (DhcpSb
, Instance
);
509 // Install DHCP4 onto ChildHandle
511 Status
= gBS
->InstallMultipleProtocolInterfaces (
513 &gEfiDhcp4ProtocolGuid
,
514 &Instance
->Dhcp4Protocol
,
518 if (EFI_ERROR (Status
)) {
519 NetFreePool (Instance
);
523 Instance
->Handle
= *ChildHandle
;
526 // Open the Udp4 protocol BY_CHILD.
528 Status
= gBS
->OpenProtocol (
529 DhcpSb
->UdpIo
->UdpHandle
,
530 &gEfiUdp4ProtocolGuid
,
532 gDhcp4DriverBinding
.DriverBindingHandle
,
534 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
536 if (EFI_ERROR (Status
)) {
537 gBS
->UninstallMultipleProtocolInterfaces (
539 &gEfiDhcp4ProtocolGuid
,
540 &Instance
->Dhcp4Protocol
,
544 NetFreePool (Instance
);
548 OldTpl
= NET_RAISE_TPL (NET_TPL_LOCK
);
550 NetListInsertTail (&DhcpSb
->Children
, &Instance
->Link
);
551 DhcpSb
->NumChildren
++;
553 NET_RESTORE_TPL (OldTpl
);
560 Destroys a child handle with a set of DHCP4 services.
562 @param This Protocol instance pointer.
563 @param ChildHandle Handle of the child to destroy
565 @retval EFI_SUCCES The DHCP4 service is removed from the child handle
566 @retval EFI_UNSUPPORTED The child handle does not support the DHCP4
568 @retval EFI_INVALID_PARAMETER Child handle is not a valid EFI Handle.
569 @retval EFI_ACCESS_DENIED The child handle could not be destroyed because
570 its DHCP4 services are being used.
571 @retval other The child handle was not destroyed
576 Dhcp4ServiceBindingDestroyChild (
577 IN EFI_SERVICE_BINDING_PROTOCOL
*This
,
578 IN EFI_HANDLE ChildHandle
581 DHCP_SERVICE
*DhcpSb
;
582 DHCP_PROTOCOL
*Instance
;
583 EFI_DHCP4_PROTOCOL
*Dhcp
;
587 if ((This
== NULL
) || (ChildHandle
== NULL
)) {
588 return EFI_INVALID_PARAMETER
;
592 // Retrieve the private context data structures
594 Status
= gBS
->OpenProtocol (
596 &gEfiDhcp4ProtocolGuid
,
598 gDhcp4DriverBinding
.DriverBindingHandle
,
600 EFI_OPEN_PROTOCOL_GET_PROTOCOL
603 if (EFI_ERROR (Status
)) {
604 return EFI_UNSUPPORTED
;
607 Instance
= DHCP_INSTANCE_FROM_THIS (Dhcp
);
608 DhcpSb
= DHCP_SERVICE_FROM_THIS (This
);
610 if (Instance
->Service
!= DhcpSb
) {
611 return EFI_INVALID_PARAMETER
;
615 // A child can be destoried more than once. For example,
616 // Dhcp4DriverBindingStop will destory all of its children.
617 // when caller driver is being stopped, it will destory the
618 // dhcp child it opens.
620 if (Instance
->InDestory
) {
624 OldTpl
= NET_RAISE_TPL (NET_TPL_LOCK
);
625 Instance
->InDestory
= TRUE
;
628 // Close the Udp4 protocol.
631 DhcpSb
->UdpIo
->UdpHandle
,
632 &gEfiUdp4ProtocolGuid
,
633 gDhcp4DriverBinding
.DriverBindingHandle
,
638 // Uninstall the DHCP4 protocol first to enable a top down destruction.
640 Status
= gBS
->UninstallProtocolInterface (
642 &gEfiDhcp4ProtocolGuid
,
646 if (EFI_ERROR (Status
)) {
647 Instance
->InDestory
= FALSE
;
649 NET_RESTORE_TPL (OldTpl
);
653 if (DhcpSb
->ActiveChild
== Instance
) {
654 DhcpYieldControl (DhcpSb
);
657 NetListRemoveEntry (&Instance
->Link
);
658 DhcpSb
->NumChildren
--;
660 NET_RESTORE_TPL (OldTpl
);
662 NetFreePool (Instance
);