NetworkPkg: Move Network library and drivers from MdeModulePkg to NetworkPkg

Signed-off-by: Liming Gao <liming.gao@intel.com>
Cc: Siyuan Fu <siyuan.fu@intel.com>
Cc: Jiaxin Wu <jiaxin.wu@intel.com>
Reviewed-by: Jiaxin Wu <jiaxin.wu@intel.com>
Reviewed-by: Siyuan Fu <siyuan.fu@intel.com>
This commit is contained in:
Liming Gao
2019-05-15 20:02:18 +08:00
parent c0fd7f734e
commit 4542f8b813
147 changed files with 24 additions and 24 deletions

View File

@@ -0,0 +1,431 @@
/** @file
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Dhcp4Impl.h"
//
// EFI Component Name Functions
//
/**
Retrieves a Unicode string that is the user readable name of the driver.
This function retrieves the user readable name of a driver in the form of a
Unicode string. If the driver specified by This has a user readable name in
the language specified by Language, then a pointer to the driver name is
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
by This does not support the language specified by Language,
then EFI_UNSUPPORTED is returned.
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param[in] Language A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified
in RFC 4646 or ISO 639-2 language code format.
@param[out] DriverName A pointer to the Unicode string to return.
This Unicode string is the name of the
driver specified by This in the language
specified by Language.
@retval EFI_SUCCESS The Unicode string for the Driver specified by
This and the language specified by Language was
returned in DriverName.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER DriverName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
DhcpComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
);
/**
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by a driver.
This function retrieves the user readable name of the controller specified by
ControllerHandle and ChildHandle in the form of a Unicode string. If the
driver specified by This has a user readable name in the language specified by
Language, then a pointer to the controller name is returned in ControllerName,
and EFI_SUCCESS is returned. If the driver specified by This is not currently
managing the controller specified by ControllerHandle and ChildHandle,
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
support the language specified by Language, then EFI_UNSUPPORTED is returned.
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param[in] ControllerHandle The handle of a controller that the driver
specified by This is managing. This handle
specifies the controller whose name is to be
returned.
@param[in] ChildHandle The handle of the child controller to retrieve
the name of. This is an optional parameter that
may be NULL. It will be NULL for device
drivers. It will also be NULL for a bus drivers
that wish to retrieve the name of the bus
controller. It will not be NULL for a bus
driver that wishes to retrieve the name of a
child controller.
@param[in] Language A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified in
RFC 4646 or ISO 639-2 language code format.
@param[out] ControllerName A pointer to the Unicode string to return.
This Unicode string is the name of the
controller specified by ControllerHandle and
ChildHandle in the language specified by
Language from the point of view of the driver
specified by This.
@retval EFI_SUCCESS The Unicode string for the user readable name in
the language specified by Language for the
driver specified by This was returned in
DriverName.
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
EFI_HANDLE.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
DhcpComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
);
//
// EFI Component Name Protocol
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gDhcp4ComponentName = {
DhcpComponentNameGetDriverName,
DhcpComponentNameGetControllerName,
"eng"
};
//
// EFI Component Name 2 Protocol
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gDhcp4ComponentName2 = {
(EFI_COMPONENT_NAME2_GET_DRIVER_NAME) DhcpComponentNameGetDriverName,
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) DhcpComponentNameGetControllerName,
"en"
};
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mDhcpDriverNameTable[] = {
{
"eng;en",
L"DHCP Protocol Driver"
},
{
NULL,
NULL
}
};
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gDhcpControllerNameTable = NULL;
CHAR16 *mDhcp4ControllerName[] = {
L"DHCPv4 (State=0, Stopped)",
L"DHCPv4 (State=1, Init)",
L"DHCPv4 (State=2, Selecting)",
L"DHCPv4 (State=3, Requesting)",
L"DHCPv4 (State=4, Bound)",
L"DHCPv4 (State=5, Renewing)",
L"DHCPv4 (State=6, Rebinding)",
L"DHCPv4 (State=7, InitReboot)",
L"DHCPv4 (State=8, Rebooting)"
};
/**
Retrieves a Unicode string that is the user readable name of the driver.
This function retrieves the user readable name of a driver in the form of a
Unicode string. If the driver specified by This has a user readable name in
the language specified by Language, then a pointer to the driver name is
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
by This does not support the language specified by Language,
then EFI_UNSUPPORTED is returned.
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param[in] Language A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified
in RFC 4646 or ISO 639-2 language code format.
@param[out] DriverName A pointer to the Unicode string to return.
This Unicode string is the name of the
driver specified by This in the language
specified by Language.
@retval EFI_SUCCESS The Unicode string for the Driver specified by
This and the language specified by Language was
returned in DriverName.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER DriverName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
DhcpComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
{
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
mDhcpDriverNameTable,
DriverName,
(BOOLEAN)(This == &gDhcp4ComponentName)
);
}
/**
Update the component name for the Dhcp4 child handle.
@param Dhcp4[in] A pointer to the EFI_DHCP4_PROTOCOL.
@retval EFI_SUCCESS Update the ControllerNameTable of this instance successfully.
@retval EFI_INVALID_PARAMETER The input parameter is invalid.
@retval EFI_DEVICE_ERROR DHCP is in unknown state.
**/
EFI_STATUS
UpdateName (
IN EFI_DHCP4_PROTOCOL *Dhcp4
)
{
EFI_STATUS Status;
EFI_DHCP4_MODE_DATA Dhcp4ModeData;
if (Dhcp4 == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Format the child name into the string buffer.
//
Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4ModeData);
if (EFI_ERROR (Status)) {
return Status;
}
if (gDhcpControllerNameTable != NULL) {
FreeUnicodeStringTable (gDhcpControllerNameTable);
gDhcpControllerNameTable = NULL;
}
if (Dhcp4ModeData.State > Dhcp4Rebooting) {
return EFI_DEVICE_ERROR;
}
Status = AddUnicodeString2 (
"eng",
gDhcp4ComponentName.SupportedLanguages,
&gDhcpControllerNameTable,
mDhcp4ControllerName[Dhcp4ModeData.State],
TRUE
);
if (EFI_ERROR (Status)) {
return Status;
}
return AddUnicodeString2 (
"en",
gDhcp4ComponentName2.SupportedLanguages,
&gDhcpControllerNameTable,
mDhcp4ControllerName[Dhcp4ModeData.State],
FALSE
);
}
/**
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by a driver.
This function retrieves the user readable name of the controller specified by
ControllerHandle and ChildHandle in the form of a Unicode string. If the
driver specified by This has a user readable name in the language specified by
Language, then a pointer to the controller name is returned in ControllerName,
and EFI_SUCCESS is returned. If the driver specified by This is not currently
managing the controller specified by ControllerHandle and ChildHandle,
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
support the language specified by Language, then EFI_UNSUPPORTED is returned.
@param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param[in] ControllerHandle The handle of a controller that the driver
specified by This is managing. This handle
specifies the controller whose name is to be
returned.
@param[in] ChildHandle The handle of the child controller to retrieve
the name of. This is an optional parameter that
may be NULL. It will be NULL for device
drivers. It will also be NULL for a bus drivers
that wish to retrieve the name of the bus
controller. It will not be NULL for a bus
driver that wishes to retrieve the name of a
child controller.
@param[in] Language A pointer to a Null-terminated ASCII string
array indicating the language. This is the
language of the driver name that the caller is
requesting, and it must match one of the
languages specified in SupportedLanguages. The
number of languages supported by a driver is up
to the driver writer. Language is specified in
RFC 4646 or ISO 639-2 language code format.
@param[out] ControllerName A pointer to the Unicode string to return.
This Unicode string is the name of the
controller specified by ControllerHandle and
ChildHandle in the language specified by
Language from the point of view of the driver
specified by This.
@retval EFI_SUCCESS The Unicode string for the user readable name in
the language specified by Language for the
driver specified by This was returned in
DriverName.
@retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
@retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
EFI_HANDLE.
@retval EFI_INVALID_PARAMETER Language is NULL.
@retval EFI_INVALID_PARAMETER ControllerName is NULL.
@retval EFI_UNSUPPORTED The driver specified by This is not currently
managing the controller specified by
ControllerHandle and ChildHandle.
@retval EFI_UNSUPPORTED The driver specified by This does not support
the language specified by Language.
**/
EFI_STATUS
EFIAPI
DhcpComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
{
EFI_STATUS Status;
EFI_DHCP4_PROTOCOL *Dhcp4;
//
// Only provide names for child handles.
//
if (ChildHandle == NULL) {
return EFI_UNSUPPORTED;
}
//
// Make sure this driver produced ChildHandle
//
Status = EfiTestChildHandle (
ControllerHandle,
ChildHandle,
&gEfiUdp4ProtocolGuid
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Retrieve an instance of a produced protocol from ChildHandle
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiDhcp4ProtocolGuid,
(VOID **)&Dhcp4,
NULL,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Update the component name for this child handle.
//
Status = UpdateName (Dhcp4);
if (EFI_ERROR (Status)) {
return Status;
}
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
gDhcpControllerNameTable,
ControllerName,
(BOOLEAN)(This == &gDhcp4ComponentName)
);
}

View File

@@ -0,0 +1,732 @@
/** @file
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Dhcp4Impl.h"
#include "Dhcp4Driver.h"
EFI_DRIVER_BINDING_PROTOCOL gDhcp4DriverBinding = {
Dhcp4DriverBindingSupported,
Dhcp4DriverBindingStart,
Dhcp4DriverBindingStop,
0xa,
NULL,
NULL
};
EFI_SERVICE_BINDING_PROTOCOL mDhcp4ServiceBindingTemplate = {
Dhcp4ServiceBindingCreateChild,
Dhcp4ServiceBindingDestroyChild
};
/**
This is the declaration of an EFI image entry point. This entry point is
the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
both device drivers and bus drivers.
Entry point of the DHCP driver to install various protocols.
@param[in] ImageHandle The firmware allocated handle for the UEFI image.
@param[in] SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The operation completed successfully.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
**/
EFI_STATUS
EFIAPI
Dhcp4DriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
return EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
SystemTable,
&gDhcp4DriverBinding,
ImageHandle,
&gDhcp4ComponentName,
&gDhcp4ComponentName2
);
}
/**
Test to see if this driver supports ControllerHandle. This service
is called by the EFI boot service ConnectController(). In
order to make drivers as small as possible, there are a few calling
restrictions for this service. ConnectController() must
follow these calling restrictions. If any other agent wishes to call
Supported() it must also follow these calling restrictions.
@param[in] This Protocol instance pointer.
@param[in] ControllerHandle Handle of device to test
@param[in] RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCESS This driver supports this device
@retval EFI_ALREADY_STARTED This driver is already running on this device
@retval other This driver does not support this device
**/
EFI_STATUS
EFIAPI
Dhcp4DriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
EFI_STATUS Status;
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiUdp4ServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
return Status;
}
/**
Configure the default UDP child to receive all the DHCP traffics
on this network interface.
@param[in] UdpIo The UDP IO to configure
@param[in] Context The context to the function
@retval EFI_SUCCESS The UDP IO is successfully configured.
@retval Others Failed to configure the UDP child.
**/
EFI_STATUS
EFIAPI
DhcpConfigUdpIo (
IN UDP_IO *UdpIo,
IN VOID *Context
)
{
EFI_UDP4_CONFIG_DATA UdpConfigData;
UdpConfigData.AcceptBroadcast = TRUE;
UdpConfigData.AcceptPromiscuous = FALSE;
UdpConfigData.AcceptAnyPort = FALSE;
UdpConfigData.AllowDuplicatePort = TRUE;
UdpConfigData.TypeOfService = 0;
UdpConfigData.TimeToLive = 64;
UdpConfigData.DoNotFragment = FALSE;
UdpConfigData.ReceiveTimeout = 0;
UdpConfigData.TransmitTimeout = 0;
UdpConfigData.UseDefaultAddress = FALSE;
UdpConfigData.StationPort = DHCP_CLIENT_PORT;
UdpConfigData.RemotePort = DHCP_SERVER_PORT;
ZeroMem (&UdpConfigData.StationAddress, sizeof (EFI_IPv4_ADDRESS));
ZeroMem (&UdpConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
ZeroMem (&UdpConfigData.RemoteAddress, sizeof (EFI_IPv4_ADDRESS));
return UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, &UdpConfigData);;
}
/**
Destroy the DHCP service. The Dhcp4 service may be partly initialized,
or partly destroyed. If a resource is destroyed, it is marked as so in
case the destroy failed and being called again later.
@param[in] DhcpSb The DHCP service instance to destroy.
@retval EFI_SUCCESS Always return success.
**/
EFI_STATUS
Dhcp4CloseService (
IN DHCP_SERVICE *DhcpSb
)
{
DhcpCleanLease (DhcpSb);
if (DhcpSb->UdpIo != NULL) {
UdpIoFreeIo (DhcpSb->UdpIo);
DhcpSb->UdpIo = NULL;
}
if (DhcpSb->Timer != NULL) {
gBS->SetTimer (DhcpSb->Timer, TimerCancel, 0);
gBS->CloseEvent (DhcpSb->Timer);
DhcpSb->Timer = NULL;
}
return EFI_SUCCESS;
}
/**
Create a new DHCP service binding instance for the controller.
@param[in] Controller The controller to install DHCP service binding
protocol onto
@param[in] ImageHandle The driver's image handle
@param[out] Service The variable to receive the created DHCP service
instance.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource .
@retval EFI_SUCCESS The DHCP service instance is created.
@retval other Other error occurs.
**/
EFI_STATUS
Dhcp4CreateService (
IN EFI_HANDLE Controller,
IN EFI_HANDLE ImageHandle,
OUT DHCP_SERVICE **Service
)
{
DHCP_SERVICE *DhcpSb;
EFI_STATUS Status;
*Service = NULL;
DhcpSb = AllocateZeroPool (sizeof (DHCP_SERVICE));
if (DhcpSb == NULL) {
return EFI_OUT_OF_RESOURCES;
}
DhcpSb->Signature = DHCP_SERVICE_SIGNATURE;
DhcpSb->ServiceState = DHCP_UNCONFIGED;
DhcpSb->Controller = Controller;
DhcpSb->Image = ImageHandle;
InitializeListHead (&DhcpSb->Children);
DhcpSb->DhcpState = Dhcp4Stopped;
DhcpSb->Xid = NET_RANDOM (NetRandomInitSeed ());
CopyMem (
&DhcpSb->ServiceBinding,
&mDhcp4ServiceBindingTemplate,
sizeof (EFI_SERVICE_BINDING_PROTOCOL)
);
//
// Create various resources, UdpIo, Timer, and get Mac address
//
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL | EVT_TIMER,
TPL_CALLBACK,
DhcpOnTimerTick,
DhcpSb,
&DhcpSb->Timer
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
DhcpSb->UdpIo = UdpIoCreateIo (
Controller,
ImageHandle,
DhcpConfigUdpIo,
UDP_IO_UDP4_VERSION,
NULL
);
if (DhcpSb->UdpIo == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_ERROR;
}
DhcpSb->HwLen = (UINT8) DhcpSb->UdpIo->SnpMode.HwAddressSize;
DhcpSb->HwType = DhcpSb->UdpIo->SnpMode.IfType;
CopyMem (&DhcpSb->Mac, &DhcpSb->UdpIo->SnpMode.CurrentAddress, sizeof (DhcpSb->Mac));
*Service = DhcpSb;
return EFI_SUCCESS;
ON_ERROR:
Dhcp4CloseService (DhcpSb);
FreePool (DhcpSb);
return Status;
}
/**
Start this driver on ControllerHandle. This service is called by the
EFI boot service ConnectController(). In order to make
drivers as small as possible, there are a few calling restrictions for
this service. ConnectController() must follow these
calling restrictions. If any other agent wishes to call Start() it
must also follow these calling restrictions.
@param[in] This Protocol instance pointer.
@param[in] ControllerHandle Handle of device to bind driver to
@param[in] RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCESS This driver is added to ControllerHandle
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
@retval other This driver does not support this device
**/
EFI_STATUS
EFIAPI
Dhcp4DriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
DHCP_SERVICE *DhcpSb;
EFI_STATUS Status;
//
// First: test for the DHCP4 Protocol
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiDhcp4ServiceBindingProtocolGuid,
NULL,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (Status == EFI_SUCCESS) {
return EFI_ALREADY_STARTED;
}
Status = Dhcp4CreateService (ControllerHandle, This->DriverBindingHandle, &DhcpSb);
if (EFI_ERROR (Status)) {
return Status;
}
ASSERT (DhcpSb != NULL);
//
// Start the receiving
//
Status = UdpIoRecvDatagram (DhcpSb->UdpIo, DhcpInput, DhcpSb, 0);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
Status = gBS->SetTimer (DhcpSb->Timer, TimerPeriodic, TICKS_PER_SECOND);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
//
// Install the Dhcp4ServiceBinding Protocol onto ControlerHandle
//
Status = gBS->InstallMultipleProtocolInterfaces (
&ControllerHandle,
&gEfiDhcp4ServiceBindingProtocolGuid,
&DhcpSb->ServiceBinding,
NULL
);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
return Status;
ON_ERROR:
Dhcp4CloseService (DhcpSb);
FreePool (DhcpSb);
return Status;
}
/**
Callback function which provided by user to remove one node in NetDestroyLinkList process.
@param[in] Entry The entry to be removed.
@param[in] Context Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
@retval EFI_SUCCESS The entry has been removed successfully.
@retval Others Fail to remove the entry.
**/
EFI_STATUS
EFIAPI
Dhcp4DestroyChildEntry (
IN LIST_ENTRY *Entry,
IN VOID *Context
)
{
DHCP_PROTOCOL *Instance;
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
if (Entry == NULL || Context == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = NET_LIST_USER_STRUCT_S (Entry, DHCP_PROTOCOL, Link, DHCP_PROTOCOL_SIGNATURE);
ServiceBinding = (EFI_SERVICE_BINDING_PROTOCOL *) Context;
return ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);
}
/**
Stop this driver on ControllerHandle. This service is called by the
EFI boot service DisconnectController(). In order to
make drivers as small as possible, there are a few calling
restrictions for this service. DisconnectController()
must follow these calling restrictions. If any other agent wishes
to call Stop() it must also follow these calling restrictions.
@param[in] This Protocol instance pointer.
@param[in] ControllerHandle Handle of device to stop driver on
@param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
children is zero stop the entire bus driver.
@param[in] ChildHandleBuffer List of Child Handles to Stop.
@retval EFI_SUCCESS This driver is removed ControllerHandle
@retval other This driver was not removed from this device
**/
EFI_STATUS
EFIAPI
Dhcp4DriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
DHCP_SERVICE *DhcpSb;
EFI_HANDLE NicHandle;
EFI_STATUS Status;
LIST_ENTRY *List;
UINTN ListLength;
//
// DHCP driver opens UDP child, So, the ControllerHandle is the
// UDP child handle. locate the Nic handle first.
//
NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiUdp4ProtocolGuid);
if (NicHandle == NULL) {
return EFI_SUCCESS;
}
Status = gBS->OpenProtocol (
NicHandle,
&gEfiDhcp4ServiceBindingProtocolGuid,
(VOID **) &ServiceBinding,
This->DriverBindingHandle,
NicHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
DhcpSb = DHCP_SERVICE_FROM_THIS (ServiceBinding);
if (!IsListEmpty (&DhcpSb->Children)) {
//
// Destroy all the children instances before destory the service.
//
List = &DhcpSb->Children;
Status = NetDestroyLinkList (
List,
Dhcp4DestroyChildEntry,
ServiceBinding,
&ListLength
);
if (EFI_ERROR (Status) || ListLength != 0) {
Status = EFI_DEVICE_ERROR;
}
}
if (NumberOfChildren == 0 && !IsListEmpty (&DhcpSb->Children)) {
Status = EFI_DEVICE_ERROR;
}
if (NumberOfChildren == 0 && IsListEmpty (&DhcpSb->Children)) {
//
// Destroy the service itself if no child instance left.
//
DhcpSb->ServiceState = DHCP_DESTROY;
gBS->UninstallProtocolInterface (
NicHandle,
&gEfiDhcp4ServiceBindingProtocolGuid,
ServiceBinding
);
Dhcp4CloseService (DhcpSb);
if (gDhcpControllerNameTable != NULL) {
FreeUnicodeStringTable (gDhcpControllerNameTable);
gDhcpControllerNameTable = NULL;
}
FreePool (DhcpSb);
Status = EFI_SUCCESS;
}
return Status;
}
/**
Initialize a new DHCP instance.
@param DhcpSb The dhcp service instance
@param Instance The dhcp instance to initialize
**/
VOID
DhcpInitProtocol (
IN DHCP_SERVICE *DhcpSb,
IN OUT DHCP_PROTOCOL *Instance
)
{
Instance->Signature = DHCP_PROTOCOL_SIGNATURE;
CopyMem (&Instance->Dhcp4Protocol, &mDhcp4ProtocolTemplate, sizeof (Instance->Dhcp4Protocol));
InitializeListHead (&Instance->Link);
Instance->Handle = NULL;
Instance->Service = DhcpSb;
Instance->InDestroy = FALSE;
Instance->CompletionEvent = NULL;
Instance->RenewRebindEvent = NULL;
Instance->Token = NULL;
Instance->UdpIo = NULL;
Instance->ElaspedTime = 0;
NetbufQueInit (&Instance->ResponseQueue);
}
/**
Creates a child handle and installs a protocol.
The CreateChild() function installs a protocol on ChildHandle.
If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
@param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
@param ChildHandle Pointer to the handle of the child to create. If it is NULL,
then a new handle is created. If it is a pointer to an existing UEFI handle,
then the protocol is added to the existing UEFI handle.
@retval EFI_SUCCES The protocol was added to ChildHandle.
@retval EFI_INVALID_PARAMETER ChildHandle is NULL.
@retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
the child
@retval other The child handle was not created
**/
EFI_STATUS
EFIAPI
Dhcp4ServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE *ChildHandle
)
{
DHCP_SERVICE *DhcpSb;
DHCP_PROTOCOL *Instance;
EFI_STATUS Status;
EFI_TPL OldTpl;
VOID *Udp4;
if ((This == NULL) || (ChildHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
Instance = AllocatePool (sizeof (*Instance));
if (Instance == NULL) {
return EFI_OUT_OF_RESOURCES;
}
DhcpSb = DHCP_SERVICE_FROM_THIS (This);
DhcpInitProtocol (DhcpSb, Instance);
//
// Install DHCP4 onto ChildHandle
//
Status = gBS->InstallMultipleProtocolInterfaces (
ChildHandle,
&gEfiDhcp4ProtocolGuid,
&Instance->Dhcp4Protocol,
NULL
);
if (EFI_ERROR (Status)) {
FreePool (Instance);
return Status;
}
Instance->Handle = *ChildHandle;
//
// Open the Udp4 protocol BY_CHILD.
//
Status = gBS->OpenProtocol (
DhcpSb->UdpIo->UdpHandle,
&gEfiUdp4ProtocolGuid,
(VOID **) &Udp4,
gDhcp4DriverBinding.DriverBindingHandle,
Instance->Handle,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
);
if (EFI_ERROR (Status)) {
gBS->UninstallMultipleProtocolInterfaces (
Instance->Handle,
&gEfiDhcp4ProtocolGuid,
&Instance->Dhcp4Protocol,
NULL
);
FreePool (Instance);
return Status;
}
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
InsertTailList (&DhcpSb->Children, &Instance->Link);
DhcpSb->NumChildren++;
gBS->RestoreTPL (OldTpl);
return EFI_SUCCESS;
}
/**
Destroys a child handle with a protocol installed on it.
The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
that was installed by CreateChild() from ChildHandle. If the removed protocol is the
last protocol on ChildHandle, then ChildHandle is destroyed.
@param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
@param ChildHandle Handle of the child to destroy
@retval EFI_SUCCES The protocol was removed from ChildHandle.
@retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
@retval EFI_INVALID_PARAMETER Child handle is NULL.
@retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
because its services are being used.
@retval other The child handle was not destroyed
**/
EFI_STATUS
EFIAPI
Dhcp4ServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
)
{
DHCP_SERVICE *DhcpSb;
DHCP_PROTOCOL *Instance;
EFI_DHCP4_PROTOCOL *Dhcp;
EFI_TPL OldTpl;
EFI_STATUS Status;
if ((This == NULL) || (ChildHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// Retrieve the private context data structures
//
Status = gBS->OpenProtocol (
ChildHandle,
&gEfiDhcp4ProtocolGuid,
(VOID **) &Dhcp,
gDhcp4DriverBinding.DriverBindingHandle,
ChildHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
Instance = DHCP_INSTANCE_FROM_THIS (Dhcp);
DhcpSb = DHCP_SERVICE_FROM_THIS (This);
if (Instance->Service != DhcpSb) {
return EFI_INVALID_PARAMETER;
}
//
// A child can be destroyed more than once. For example,
// Dhcp4DriverBindingStop will destroy all of its children.
// when caller driver is being stopped, it will destroy the
// dhcp child it opens.
//
if (Instance->InDestroy) {
return EFI_SUCCESS;
}
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
Instance->InDestroy = TRUE;
//
// Close the Udp4 protocol.
//
gBS->CloseProtocol (
DhcpSb->UdpIo->UdpHandle,
&gEfiUdp4ProtocolGuid,
gDhcp4DriverBinding.DriverBindingHandle,
ChildHandle
);
//
// Uninstall the DHCP4 protocol first to enable a top down destruction.
//
gBS->RestoreTPL (OldTpl);
Status = gBS->UninstallProtocolInterface (
ChildHandle,
&gEfiDhcp4ProtocolGuid,
Dhcp
);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
if (EFI_ERROR (Status)) {
Instance->InDestroy = FALSE;
gBS->RestoreTPL (OldTpl);
return Status;
}
if (DhcpSb->ActiveChild == Instance) {
DhcpYieldControl (DhcpSb);
}
RemoveEntryList (&Instance->Link);
DhcpSb->NumChildren--;
if (Instance->UdpIo != NULL) {
UdpIoCleanIo (Instance->UdpIo);
gBS->CloseProtocol (
Instance->UdpIo->UdpHandle,
&gEfiUdp4ProtocolGuid,
Instance->Service->Image,
Instance->Handle
);
UdpIoFreeIo (Instance->UdpIo);
Instance->UdpIo = NULL;
Instance->Token = NULL;
}
gBS->RestoreTPL (OldTpl);
FreePool (Instance);
return EFI_SUCCESS;
}

View File

@@ -0,0 +1,146 @@
/** @file
Header for the DHCP4 driver.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __EFI_DHCP4_DRIVER_H__
#define __EFI_DHCP4_DRIVER_H__
extern EFI_COMPONENT_NAME_PROTOCOL gDhcp4ComponentName;
extern EFI_COMPONENT_NAME2_PROTOCOL gDhcp4ComponentName2;
extern EFI_UNICODE_STRING_TABLE *gDhcpControllerNameTable;
/**
Test to see if this driver supports ControllerHandle. This service
is called by the EFI boot service ConnectController(). In
order to make drivers as small as possible, there are a few calling
restrictions for this service. ConnectController() must
follow these calling restrictions. If any other agent wishes to call
Supported() it must also follow these calling restrictions.
@param[in] This Protocol instance pointer.
@param[in] ControllerHandle Handle of device to test
@param[in] RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCESS This driver supports this device
@retval EFI_ALREADY_STARTED This driver is already running on this device
@retval other This driver does not support this device
**/
EFI_STATUS
EFIAPI
Dhcp4DriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
/**
Start this driver on ControllerHandle. This service is called by the
EFI boot service ConnectController(). In order to make
drivers as small as possible, there are a few calling restrictions for
this service. ConnectController() must follow these
calling restrictions. If any other agent wishes to call Start() it
must also follow these calling restrictions.
@param[in] This Protocol instance pointer.
@param[in] ControllerHandle Handle of device to bind driver to
@param[in] RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCESS This driver is added to ControllerHandle
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
@retval other This driver does not support this device
**/
EFI_STATUS
EFIAPI
Dhcp4DriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
);
/**
Stop this driver on ControllerHandle. This service is called by the
EFI boot service DisconnectController(). In order to
make drivers as small as possible, there are a few calling
restrictions for this service. DisconnectController()
must follow these calling restrictions. If any other agent wishes
to call Stop() it must also follow these calling restrictions.
@param[in] This Protocol instance pointer.
@param[in] ControllerHandle Handle of device to stop driver on
@param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
children is zero stop the entire bus driver.
@param[in] ChildHandleBuffer List of Child Handles to Stop.
@retval EFI_SUCCESS This driver is removed ControllerHandle
@retval other This driver was not removed from this device
**/
EFI_STATUS
EFIAPI
Dhcp4DriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
);
/**
Creates a child handle and installs a protocol.
The CreateChild() function installs a protocol on ChildHandle.
If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
@param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
@param ChildHandle Pointer to the handle of the child to create. If it is NULL,
then a new handle is created. If it is a pointer to an existing UEFI handle,
then the protocol is added to the existing UEFI handle.
@retval EFI_SUCCES The protocol was added to ChildHandle.
@retval EFI_INVALID_PARAMETER ChildHandle is NULL.
@retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
the child
@retval other The child handle was not created
**/
EFI_STATUS
EFIAPI
Dhcp4ServiceBindingCreateChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE *ChildHandle
);
/**
Destroys a child handle with a protocol installed on it.
The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
that was installed by CreateChild() from ChildHandle. If the removed protocol is the
last protocol on ChildHandle, then ChildHandle is destroyed.
@param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
@param ChildHandle Handle of the child to destroy
@retval EFI_SUCCES The protocol was removed from ChildHandle.
@retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
@retval EFI_INVALID_PARAMETER Child handle is NULL.
@retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
because its services are being used.
@retval other The child handle was not destroyed
**/
EFI_STATUS
EFIAPI
Dhcp4ServiceBindingDestroyChild (
IN EFI_SERVICE_BINDING_PROTOCOL *This,
IN EFI_HANDLE ChildHandle
);
#endif

View File

@@ -0,0 +1,66 @@
## @file
# This module produces EFI DHCPv4 Protocol and EFI DHCPv4 Service Binding Protocol.
#
# This module produces EFI DHCPv4 Protocol upon EFI UDPv4 Protocol, to provide the
# capability to collect configuration information for the EFI IPv4 Protocol drivers
# and to provide DHCPv4 server and PXE boot server discovery services.
#
# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = Dhcp4Dxe
MODULE_UNI_FILE = Dhcp4Dxe.uni
FILE_GUID = 94734718-0BBC-47fb-96A5-EE7A5AE6A2AD
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = Dhcp4DriverEntryPoint
UNLOAD_IMAGE = NetLibDefaultUnload
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 EBC
#
# DRIVER_BINDING = gDhcp4DriverBinding
# COMPONENT_NAME = gDhcp4ComponentName
# COMPONENT_NAME2 = gDhcp4ComponentName2
#
[Sources]
Dhcp4Impl.c
Dhcp4Io.c
Dhcp4Io.h
ComponentName.c
Dhcp4Driver.h
Dhcp4Driver.c
Dhcp4Option.c
Dhcp4Option.h
Dhcp4Impl.h
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
BaseLib
UefiLib
UefiBootServicesTableLib
UefiDriverEntryPoint
DebugLib
NetLib
UdpIoLib
[Protocols]
gEfiDhcp4ServiceBindingProtocolGuid ## BY_START
gEfiUdp4ServiceBindingProtocolGuid ## TO_START
gEfiDhcp4ProtocolGuid ## BY_START
gEfiUdp4ProtocolGuid ## TO_START
[UserExtensions.TianoCore."ExtraFiles"]
Dhcp4DxeExtra.uni

View File

@@ -0,0 +1,18 @@
// /** @file
// This module produces EFI DHCPv4 Protocol and EFI DHCPv4 Service Binding Protocol.
//
// This module produces EFI DHCPv4 Protocol upon EFI UDPv4 Protocol, to provide the
// capability to collect configuration information for the EFI IPv4 Protocol drivers
// and to provide DHCPv4 server and PXE boot server discovery services.
//
// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
// **/
#string STR_MODULE_ABSTRACT #language en-US "EFI DHCPv4 Driver"
#string STR_MODULE_DESCRIPTION #language en-US "This module produces EFI DHCPv4 Protocol using the EFI UDPv4 Protocol, providing the capability to collect configuration information for the EFI IPv4 Protocol drivers and providing DHCPv4 server and PXE boot server discovery services."

View File

@@ -0,0 +1,14 @@
// /** @file
// Dhcp4Dxe Localized Strings and Content
//
// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
// **/
#string STR_PROPERTIES_MODULE_NAME
#language en-US
"DHCP v4 DXE Driver"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,206 @@
/** @file
EFI DHCP protocol implementation.
RFCs supported are:
RFC 2131: Dynamic Host Configuration Protocol
RFC 2132: DHCP Options and BOOTP Vendor Extensions
RFC 1534: Interoperation Between DHCP and BOOTP
RFC 3396: Encoding Long Options in DHCP.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __EFI_DHCP4_IMPL_H__
#define __EFI_DHCP4_IMPL_H__
#include <Uefi.h>
#include <Protocol/Dhcp4.h>
#include <Protocol/Udp4.h>
#include <IndustryStandard/Dhcp.h>
#include <Library/DebugLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/NetLib.h>
typedef struct _DHCP_SERVICE DHCP_SERVICE;
typedef struct _DHCP_PROTOCOL DHCP_PROTOCOL;
#include "Dhcp4Option.h"
#include "Dhcp4Io.h"
#define DHCP_SERVICE_SIGNATURE SIGNATURE_32 ('D', 'H', 'C', 'P')
#define DHCP_PROTOCOL_SIGNATURE SIGNATURE_32 ('d', 'h', 'c', 'p')
#define DHCP_CHECK_MEDIA_WAITING_TIME EFI_TIMER_PERIOD_SECONDS(20)
//
// The state of the DHCP service. It starts as UNCONFIGED. If
// and active child configures the service successfully, it
// goes to CONFIGED. If the active child configures NULL, it
// goes back to UNCONFIGED. It becomes DESTROY if it is (partly)
// destroyed.
//
#define DHCP_UNCONFIGED 0
#define DHCP_CONFIGED 1
#define DHCP_DESTROY 2
struct _DHCP_PROTOCOL {
UINT32 Signature;
EFI_DHCP4_PROTOCOL Dhcp4Protocol;
LIST_ENTRY Link;
EFI_HANDLE Handle;
DHCP_SERVICE *Service;
BOOLEAN InDestroy;
EFI_EVENT CompletionEvent;
EFI_EVENT RenewRebindEvent;
EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token;
UDP_IO *UdpIo; // The UDP IO used for TransmitReceive.
UINT32 Timeout;
UINT16 ElaspedTime;
NET_BUF_QUEUE ResponseQueue;
};
//
// DHCP driver is specical in that it is a singleton. Although it
// has a service binding, there can be only one active child.
//
struct _DHCP_SERVICE {
UINT32 Signature;
EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
INTN ServiceState; // CONFIGED, UNCONFIGED, and DESTROY
EFI_HANDLE Controller;
EFI_HANDLE Image;
LIST_ENTRY Children;
UINTN NumChildren;
INTN DhcpState;
EFI_STATUS IoStatus; // the result of last user operation
UINT32 Xid;
IP4_ADDR ClientAddr; // lease IP or configured client address
IP4_ADDR Netmask;
IP4_ADDR ServerAddr;
EFI_DHCP4_PACKET *LastOffer; // The last received offer
EFI_DHCP4_PACKET *Selected;
DHCP_PARAMETER *Para;
UINT32 Lease;
UINT32 T1;
UINT32 T2;
INTN ExtraRefresh; // This refresh is reqested by user
UDP_IO *UdpIo; // Udp child receiving all DHCP message
UDP_IO *LeaseIoPort; // Udp child with lease IP
EFI_DHCP4_PACKET *LastPacket; // The last sent packet for retransmission
EFI_MAC_ADDRESS Mac;
UINT8 HwType;
UINT8 HwLen;
UINT8 ClientAddressSendOut[16];
DHCP_PROTOCOL *ActiveChild;
EFI_DHCP4_CONFIG_DATA ActiveConfig;
UINT32 UserOptionLen;
//
// Timer event and various timer
//
EFI_EVENT Timer;
UINT32 PacketToLive; // Retransmission timer for our packets
UINT32 LastTimeout; // Record the init value of PacketToLive every time
INTN CurRetry;
INTN MaxRetries;
UINT32 LeaseLife;
};
typedef struct {
EFI_DHCP4_PACKET_OPTION **Option;
UINT32 OptionCount;
UINT32 Index;
} DHCP_PARSE_CONTEXT;
#define DHCP_INSTANCE_FROM_THIS(Proto) \
CR ((Proto), DHCP_PROTOCOL, Dhcp4Protocol, DHCP_PROTOCOL_SIGNATURE)
#define DHCP_SERVICE_FROM_THIS(Sb) \
CR ((Sb), DHCP_SERVICE, ServiceBinding, DHCP_SERVICE_SIGNATURE)
extern EFI_DHCP4_PROTOCOL mDhcp4ProtocolTemplate;
/**
Give up the control of the DHCP service to let other child
resume. Don't change the service's DHCP state and the Client
address and option list configure as required by RFC2131.
@param DhcpSb The DHCP service instance.
**/
VOID
DhcpYieldControl (
IN DHCP_SERVICE *DhcpSb
);
/**
Complete a Dhcp4 transaction and signal the upper layer.
@param Instance Dhcp4 instance.
**/
VOID
PxeDhcpDone (
IN DHCP_PROTOCOL *Instance
);
/**
Free the resource related to the configure parameters.
DHCP driver will make a copy of the user's configure
such as the time out value.
@param Config The DHCP configure data
**/
VOID
DhcpCleanConfigure (
IN OUT EFI_DHCP4_CONFIG_DATA *Config
);
/**
Callback of Dhcp packet. Does nothing.
@param Arg The context.
**/
VOID
EFIAPI
DhcpDummyExtFree (
IN VOID *Arg
);
/**
Set the elapsed time based on the given instance and the pointer to the
elapsed time option.
@param[in] Elapsed The pointer to the position to append.
@param[in] Instance The pointer to the Dhcp4 instance.
**/
VOID
SetElapsedTime (
IN UINT16 *Elapsed,
IN DHCP_PROTOCOL *Instance
);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,189 @@
/** @file
The DHCP4 protocol implementation.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __EFI_DHCP4_IO_H__
#define __EFI_DHCP4_IO_H__
#include <Uefi.h>
#include <Protocol/ServiceBinding.h>
#include <Library/NetLib.h>
#include <Library/UdpIoLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#define DHCP_WAIT_OFFER 3 // Time to wait the offers
#define DHCP_DEFAULT_LEASE 7 * 24 * 60 * 60 // Seven days as default.
#define DHCP_SERVER_PORT 67
#define DHCP_CLIENT_PORT 68
//
// BOOTP header "op" field
//
#define BOOTP_REQUEST 1
#define BOOTP_REPLY 2
//
// DHCP message types
//
#define DHCP_MSG_DISCOVER 1
#define DHCP_MSG_OFFER 2
#define DHCP_MSG_REQUEST 3
#define DHCP_MSG_DECLINE 4
#define DHCP_MSG_ACK 5
#define DHCP_MSG_NAK 6
#define DHCP_MSG_RELEASE 7
#define DHCP_MSG_INFORM 8
//
// DHCP notify user type
//
#define DHCP_NOTIFY_COMPLETION 1
#define DHCP_NOTIFY_RENEWREBIND 2
#define DHCP_NOTIFY_ALL 3
#define DHCP_IS_BOOTP(Parameter) (((Parameter) == NULL) || ((Parameter)->DhcpType == 0))
#define DHCP_CONNECTED(State) \
(((State) == Dhcp4Bound) || ((State) == (Dhcp4Renewing)) || ((State) == Dhcp4Rebinding))
/**
Set the DHCP state. If CallUser is true, it will try to notify
the user before change the state by DhcpNotifyUser. It returns
EFI_ABORTED if the user return EFI_ABORTED, otherwise, it returns
EFI_SUCCESS. If CallUser is FALSE, it isn't necessary to test
the return value of this function.
@param DhcpSb The DHCP service instance
@param State The new DHCP state to change to
@param CallUser Whether we need to call user
@retval EFI_SUCCESS The state is changed
@retval EFI_ABORTED The user asks to abort the DHCP process.
**/
EFI_STATUS
DhcpSetState (
IN OUT DHCP_SERVICE *DhcpSb,
IN INTN State,
IN BOOLEAN CallUser
);
/**
Build and transmit a DHCP message according to the current states.
This function implement the Table 5. of RFC 2131. Always transits
the state (as defined in Figure 5. of the same RFC) before sending
a DHCP message. The table is adjusted accordingly.
@param[in] DhcpSb The DHCP service instance
@param[in] Seed The seed packet which the new packet is based on
@param[in] Para The DHCP parameter of the Seed packet
@param[in] Type The message type to send
@param[in] Msg The human readable message to include in the packet
sent.
@retval EFI_OUT_OF_RESOURCES Failed to allocate resources for the packet
@retval EFI_ACCESS_DENIED Failed to transmit the packet through UDP
@retval EFI_SUCCESS The message is sent
@retval other Other error occurs
**/
EFI_STATUS
DhcpSendMessage (
IN DHCP_SERVICE *DhcpSb,
IN EFI_DHCP4_PACKET *Seed,
IN DHCP_PARAMETER *Para,
IN UINT8 Type,
IN UINT8 *Msg
);
/**
Each DHCP service has three timer. Two of them are count down timer.
One for the packet retransmission. The other is to collect the offers.
The third timer increaments the lease life which is compared to T1, T2,
and lease to determine the time to renew and rebind the lease.
DhcpOnTimerTick will be called once every second.
@param[in] Event The timer event
@param[in] Context The context, which is the DHCP service instance.
**/
VOID
EFIAPI
DhcpOnTimerTick (
IN EFI_EVENT Event,
IN VOID *Context
);
/**
Handle the received DHCP packets. This function drives the DHCP
state machine.
@param UdpPacket The UDP packets received.
@param EndPoint The local/remote UDP access point
@param IoStatus The status of the UDP receive
@param Context The opaque parameter to the function.
**/
VOID
EFIAPI
DhcpInput (
NET_BUF *UdpPacket,
UDP_END_POINT *EndPoint,
EFI_STATUS IoStatus,
VOID *Context
);
/**
Send an initial DISCOVER or REQUEST message according to the
DHCP service's current state.
@param[in] DhcpSb The DHCP service instance
@retval EFI_SUCCESS The request has been sent
@retval other Some error occurs when sending the request.
**/
EFI_STATUS
DhcpInitRequest (
IN DHCP_SERVICE *DhcpSb
);
/**
Clean up the DHCP related states, IoStatus isn't reset.
@param DhcpSb The DHCP instance service.
**/
VOID
DhcpCleanLease (
IN DHCP_SERVICE *DhcpSb
);
/**
Release the net buffer when packet is sent.
@param UdpPacket The UDP packets received.
@param EndPoint The local/remote UDP access point
@param IoStatus The status of the UDP receive
@param Context The opaque parameter to the function.
**/
VOID
EFIAPI
DhcpOnPacketSent (
NET_BUF *Packet,
UDP_END_POINT *EndPoint,
EFI_STATUS IoStatus,
VOID *Context
);
#endif

View File

@@ -0,0 +1,890 @@
/** @file
Function to validate, parse, process the DHCP options.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Dhcp4Impl.h"
///
/// A list of the format of DHCP Options sorted by option tag
/// to validate a dhcp message. Refere the comments of the
/// DHCP_OPTION_FORMAT structure.
///
DHCP_OPTION_FORMAT DhcpOptionFormats[] = {
{DHCP4_TAG_NETMASK, DHCP_OPTION_IP, 1, 1 , TRUE},
{DHCP4_TAG_TIME_OFFSET, DHCP_OPTION_INT32, 1, 1 , FALSE},
{DHCP4_TAG_ROUTER, DHCP_OPTION_IP, 1, -1 , TRUE},
{DHCP4_TAG_TIME_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_NAME_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_DNS_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_LOG_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_COOKIE_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_LPR_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_IMPRESS_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_RL_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_HOSTNAME, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP4_TAG_BOOTFILE_LEN, DHCP_OPTION_INT16, 1, 1 , FALSE},
{DHCP4_TAG_DUMP, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP4_TAG_DOMAINNAME, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP4_TAG_SWAP_SERVER, DHCP_OPTION_IP, 1, 1 , FALSE},
{DHCP4_TAG_ROOTPATH, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP4_TAG_EXTEND_PATH, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP4_TAG_IPFORWARD, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP4_TAG_NONLOCAL_SRR, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP4_TAG_POLICY_SRR, DHCP_OPTION_IPPAIR, 1, -1 , FALSE},
{DHCP4_TAG_EMTU, DHCP_OPTION_INT16, 1, 1 , FALSE},
{DHCP4_TAG_TTL, DHCP_OPTION_INT8, 1, 1 , FALSE},
{DHCP4_TAG_PATHMTU_AGE, DHCP_OPTION_INT32, 1, 1 , FALSE},
{DHCP4_TAG_PATHMTU_PLATEAU,DHCP_OPTION_INT16, 1, -1 , FALSE},
{DHCP4_TAG_IFMTU, DHCP_OPTION_INT16, 1, 1 , FALSE},
{DHCP4_TAG_SUBNET_LOCAL, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP4_TAG_BROADCAST, DHCP_OPTION_IP, 1, 1 , FALSE},
{DHCP4_TAG_DISCOVER_MASK, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP4_TAG_SUPPLY_MASK, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP4_TAG_DISCOVER_ROUTE, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP4_TAG_ROUTER_SOLICIT, DHCP_OPTION_IP, 1, 1 , FALSE},
{DHCP4_TAG_STATIC_ROUTE, DHCP_OPTION_IPPAIR, 1, -1 , FALSE},
{DHCP4_TAG_TRAILER, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP4_TAG_ARPAGE, DHCP_OPTION_INT32, 1, 1 , FALSE},
{DHCP4_TAG_ETHER_ENCAP, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP4_TAG_TCP_TTL, DHCP_OPTION_INT8, 1, 1 , FALSE},
{DHCP4_TAG_KEEP_INTERVAL, DHCP_OPTION_INT32, 1, 1 , FALSE},
{DHCP4_TAG_KEEP_GARBAGE, DHCP_OPTION_SWITCH, 1, 1 , FALSE},
{DHCP4_TAG_NIS_DOMAIN, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP4_TAG_NIS_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_NTP_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_VENDOR, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP4_TAG_NBNS, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_NBDD, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_NBTYPE, DHCP_OPTION_INT8, 1, 1 , FALSE},
{DHCP4_TAG_NBSCOPE, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP4_TAG_XFONT, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_XDM, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_REQUEST_IP, DHCP_OPTION_IP, 1, 1 , FALSE},
{DHCP4_TAG_LEASE, DHCP_OPTION_INT32, 1, 1 , TRUE},
{DHCP4_TAG_OVERLOAD, DHCP_OPTION_INT8, 1, 1 , TRUE},
{DHCP4_TAG_MSG_TYPE, DHCP_OPTION_INT8, 1, 1 , TRUE},
{DHCP4_TAG_SERVER_ID, DHCP_OPTION_IP, 1, 1 , TRUE},
{DHCP4_TAG_PARA_LIST, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP4_TAG_MESSAGE, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP4_TAG_MAXMSG, DHCP_OPTION_INT16, 1, 1 , FALSE},
{DHCP4_TAG_T1, DHCP_OPTION_INT32, 1, 1 , TRUE},
{DHCP4_TAG_T2, DHCP_OPTION_INT32, 1, 1 , TRUE},
{DHCP4_TAG_VENDOR_CLASS_ID,DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP4_TAG_CLIENT_ID, DHCP_OPTION_INT8, 2, -1 , FALSE},
{DHCP4_TAG_NISPLUS, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP4_TAG_NISPLUS_SERVER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_TFTP, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP4_TAG_BOOTFILE, DHCP_OPTION_INT8, 1, -1 , FALSE},
{DHCP4_TAG_MOBILEIP, DHCP_OPTION_IP, 0, -1 , FALSE},
{DHCP4_TAG_SMTP, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_POP3, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_NNTP, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_WWW, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_FINGER, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_IRC, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_STTALK, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_STDA, DHCP_OPTION_IP, 1, -1 , FALSE},
{DHCP4_TAG_CLASSLESS_ROUTE,DHCP_OPTION_INT8, 5, -1 , FALSE},
};
/**
Binary search the DhcpOptionFormats array to find the format
information about a specific option.
@param[in] Tag The option's tag.
@return The point to the option's format, NULL if not found.
**/
DHCP_OPTION_FORMAT *
DhcpFindOptionFormat (
IN UINT8 Tag
)
{
INTN Left;
INTN Right;
INTN Middle;
Left = 0;
Right = sizeof (DhcpOptionFormats) / sizeof (DHCP_OPTION_FORMAT) - 1;
while (Right >= Left) {
Middle = (Left + Right) / 2;
if (Tag == DhcpOptionFormats[Middle].Tag) {
return &DhcpOptionFormats[Middle];
}
if (Tag < DhcpOptionFormats[Middle].Tag) {
Right = Middle - 1;
} else {
Left = Middle + 1;
}
}
return NULL;
}
/**
Validate whether a single DHCP option is valid according to its format.
@param[in] Format The option's format
@param[in] OptValue The value of the option
@param[in] Len The length of the option value
@retval TRUE The option is valid.
@retval FALSE Otherwise.
**/
BOOLEAN
DhcpOptionIsValid (
IN DHCP_OPTION_FORMAT *Format,
IN UINT8 *OptValue,
IN INTN Len
)
{
INTN Unit;
INTN Occur;
INTN Index;
Unit = 0;
switch (Format->Type) {
case DHCP_OPTION_SWITCH:
case DHCP_OPTION_INT8:
Unit = 1;
break;
case DHCP_OPTION_INT16:
Unit = 2;
break;
case DHCP_OPTION_INT32:
case DHCP_OPTION_IP:
Unit = 4;
break;
case DHCP_OPTION_IPPAIR:
Unit = 8;
break;
}
ASSERT (Unit != 0);
//
// Validate that the option appears in the full units.
//
if ((Len % Unit) != 0) {
return FALSE;
}
//
// Validate the occurance of the option unit is with in [MinOccur, MaxOccur]
//
Occur = Len / Unit;
if (((Format->MinOccur != -1) && (Occur < Format->MinOccur)) ||
((Format->MaxOccur != -1) && (Occur > Format->MaxOccur))
) {
return FALSE;
}
//
// If the option is of type switch, only 0/1 are valid values.
//
if (Format->Type == DHCP_OPTION_SWITCH) {
for (Index = 0; Index < Occur; Index++) {
if ((OptValue[Index] != 0) && (OptValue[Index] != 1)) {
return FALSE;
}
}
}
return TRUE;
}
/**
Extract the client interested options, all the parameters are
converted to host byte order.
@param[in] Tag The DHCP option tag
@param[in] Len The length of the option
@param[in] Data The value of the DHCP option
@param[out] Para The variable to save the interested parameter
@retval EFI_SUCCESS The DHCP option is successfully extracted.
@retval EFI_INVALID_PARAMETER The DHCP option is mal-formated
**/
EFI_STATUS
DhcpGetParameter (
IN UINT8 Tag,
IN INTN Len,
IN UINT8 *Data,
OUT DHCP_PARAMETER *Para
)
{
switch (Tag) {
case DHCP4_TAG_NETMASK:
Para->NetMask = NetGetUint32 (Data);
break;
case DHCP4_TAG_ROUTER:
//
// Return the first router to consumer which is the preferred one
//
Para->Router = NetGetUint32 (Data);
break;
case DHCP4_TAG_LEASE:
Para->Lease = NetGetUint32 (Data);
break;
case DHCP4_TAG_OVERLOAD:
Para->Overload = *Data;
if ((Para->Overload < 1) || (Para->Overload > 3)) {
return EFI_INVALID_PARAMETER;
}
break;
case DHCP4_TAG_MSG_TYPE:
Para->DhcpType = *Data;
if ((Para->DhcpType < 1) || (Para->DhcpType > 9)) {
return EFI_INVALID_PARAMETER;
}
break;
case DHCP4_TAG_SERVER_ID:
Para->ServerId = NetGetUint32 (Data);
break;
case DHCP4_TAG_T1:
Para->T1 = NetGetUint32 (Data);
break;
case DHCP4_TAG_T2:
Para->T2 = NetGetUint32 (Data);
break;
}
return EFI_SUCCESS;
}
/**
Inspect all the options in a single buffer. DHCP options may be contained
in several buffers, such as the BOOTP options filed, boot file or server
name. Each option buffer is required to end with DHCP4_TAG_EOP.
@param[in] Buffer The buffer which contains DHCP options
@param[in] BufLen The length of the buffer
@param[in] Check The callback function for each option found
@param[in] Context The opaque parameter for the Check
@param[out] Overload Variable to save the value of DHCP4_TAG_OVERLOAD
option.
@retval EFI_SUCCESS All the options are valid
@retval EFI_INVALID_PARAMETER The options are mal-formated.
**/
EFI_STATUS
DhcpIterateBufferOptions (
IN UINT8 *Buffer,
IN INTN BufLen,
IN DHCP_CHECK_OPTION Check OPTIONAL,
IN VOID *Context,
OUT UINT8 *Overload OPTIONAL
)
{
INTN Cur;
UINT8 Tag;
UINT8 Len;
Cur = 0;
while (Cur < BufLen) {
Tag = Buffer[Cur];
if (Tag == DHCP4_TAG_PAD) {
Cur++;
continue;
} else if (Tag == DHCP4_TAG_EOP) {
return EFI_SUCCESS;
}
Cur++;
if (Cur == BufLen) {
return EFI_INVALID_PARAMETER;
}
Len = Buffer[Cur++];
if (Cur + Len > BufLen) {
return EFI_INVALID_PARAMETER;
}
if ((Tag == DHCP4_TAG_OVERLOAD) && (Overload != NULL)) {
if (Len != 1) {
return EFI_INVALID_PARAMETER;
}
*Overload = Buffer[Cur];
}
if ((Check != NULL) && EFI_ERROR (Check (Tag, Len, Buffer + Cur, Context))) {
return EFI_INVALID_PARAMETER;
}
Cur += Len;
}
//
// Each option buffer is expected to end with an EOP
//
return EFI_INVALID_PARAMETER;
}
/**
Iterate through a DHCP message to visit each option. First inspect
all the options in the OPTION field. Then if overloaded, inspect
the options in FILENAME and SERVERNAME fields. One option may be
encoded in several places. See RFC 3396 Encoding Long Options in DHCP
@param[in] Packet The DHCP packet to check the options for
@param[in] Check The callback function to be called for each option
found
@param[in] Context The opaque parameter for Check
@retval EFI_SUCCESS The DHCP packet's options are well formated
@retval EFI_INVALID_PARAMETER The DHCP packet's options are not well formated
**/
EFI_STATUS
DhcpIterateOptions (
IN EFI_DHCP4_PACKET *Packet,
IN DHCP_CHECK_OPTION Check OPTIONAL,
IN VOID *Context
)
{
EFI_STATUS Status;
UINT8 Overload;
Overload = 0;
Status = DhcpIterateBufferOptions (
Packet->Dhcp4.Option,
Packet->Length - sizeof (EFI_DHCP4_HEADER) - sizeof (UINT32),
Check,
Context,
&Overload
);
if (EFI_ERROR (Status)) {
return Status;
}
if ((Overload == DHCP_OVERLOAD_FILENAME) || (Overload == DHCP_OVERLOAD_BOTH)) {
Status = DhcpIterateBufferOptions (
(UINT8 *) Packet->Dhcp4.Header.BootFileName,
128,
Check,
Context,
NULL
);
if (EFI_ERROR (Status)) {
return Status;
}
}
if ((Overload == DHCP_OVERLOAD_SVRNAME) || (Overload == DHCP_OVERLOAD_BOTH)) {
Status = DhcpIterateBufferOptions (
(UINT8 *) Packet->Dhcp4.Header.ServerName,
64,
Check,
Context,
NULL
);
if (EFI_ERROR (Status)) {
return Status;
}
}
return EFI_SUCCESS;
}
/**
Call back function to DhcpIterateOptions to compute each option's
length. It just adds the data length of all the occurances of this
Tag. Context is an array of 256 DHCP_OPTION_COUNT.
@param[in] Tag The current option to check
@param[in] Len The length of the option data
@param[in] Data The option data
@param[in] Context The context, which is a array of 256
DHCP_OPTION_COUNT.
@retval EFI_SUCCESS It always returns EFI_SUCCESS.
**/
EFI_STATUS
DhcpGetOptionLen (
IN UINT8 Tag,
IN UINT8 Len,
IN UINT8 *Data,
IN VOID *Context
)
{
DHCP_OPTION_COUNT *OpCount;
OpCount = (DHCP_OPTION_COUNT *) Context;
OpCount[Tag].Offset = (UINT16) (OpCount[Tag].Offset + Len);
return EFI_SUCCESS;
}
/**
Call back function to DhcpIterateOptions to consolidate each option's
data. There are maybe several occurrence of the same option.
@param[in] Tag The option to consolidate its data
@param[in] Len The length of option data
@param[in] Data The data of the option's current occurance
@param[in] Context The context, which is DHCP_OPTION_CONTEXT. This
array is just a wrap to pass THREE parameters.
@retval EFI_SUCCESS It always returns EFI_SUCCESS
**/
EFI_STATUS
DhcpFillOption (
IN UINT8 Tag,
IN UINT8 Len,
IN UINT8 *Data,
IN VOID *Context
)
{
DHCP_OPTION_CONTEXT *OptContext;
DHCP_OPTION_COUNT *OptCount;
DHCP_OPTION *Options;
UINT8 *Buf;
UINT8 Index;
OptContext = (DHCP_OPTION_CONTEXT *) Context;
OptCount = OptContext->OpCount;
Index = OptCount[Tag].Index;
Options = OptContext->Options;
Buf = OptContext->Buf;
if (Options[Index].Data == NULL) {
Options[Index].Tag = Tag;
Options[Index].Data = Buf + OptCount[Tag].Offset;
}
CopyMem (Buf + OptCount[Tag].Offset, Data, Len);
OptCount[Tag].Offset = (UINT16) (OptCount[Tag].Offset + Len);
Options[Index].Len = (UINT16) (Options[Index].Len + Len);
return EFI_SUCCESS;
}
/**
Parse the options of a DHCP packet. It supports RFC 3396: Encoding
Long Options in DHCP. That is, it will combine all the option value
of all the occurances of each option.
A little bit of implemenation:
It adopts the "Key indexed counting" algorithm. First, it allocates
an array of 256 DHCP_OPTION_COUNTs because DHCP option tag is encoded
as a UINT8. It then iterates the DHCP packet to get data length of
each option by calling DhcpIterOptions with DhcpGetOptionLen. Now, it
knows the number of present options and their length. It allocates a
array of DHCP_OPTION and a continuous buffer after the array to put
all the options' data. Each option's data is pointed to by the Data
field in DHCP_OPTION structure. At last, it call DhcpIterateOptions
with DhcpFillOption to fill each option's data to its position in the
buffer.
@param[in] Packet The DHCP packet to parse the options
@param[out] Count The number of valid dhcp options present in the
packet
@param[out] OptionPoint The array that contains the DHCP options. Caller
should free it.
@retval EFI_NOT_FOUND Cannot find any option.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory to parse the packet.
@retval EFI_INVALID_PARAMETER The options are mal-formated
@retval EFI_SUCCESS The options are parsed into OptionPoint
**/
EFI_STATUS
DhcpParseOption (
IN EFI_DHCP4_PACKET *Packet,
OUT INTN *Count,
OUT DHCP_OPTION **OptionPoint
)
{
DHCP_OPTION_CONTEXT Context;
DHCP_OPTION *Options;
DHCP_OPTION_COUNT *OptCount;
EFI_STATUS Status;
UINT16 TotalLen;
INTN OptNum;
INTN Index;
ASSERT ((Count != NULL) && (OptionPoint != NULL));
//
// First compute how many options and how long each option is
// with the "Key indexed counting" algorithms.
//
OptCount = AllocateZeroPool (DHCP_MAX_OPTIONS * sizeof (DHCP_OPTION_COUNT));
if (OptCount == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Status = DhcpIterateOptions (Packet, DhcpGetOptionLen, OptCount);
if (EFI_ERROR (Status)) {
goto ON_EXIT;
}
//
// Before the loop, Offset is the length of the option. After loop,
// OptCount[Index].Offset specifies the offset into the continuous
// option value buffer to put the data.
//
TotalLen = 0;
OptNum = 0;
for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {
if (OptCount[Index].Offset != 0) {
OptCount[Index].Index = (UINT8) OptNum;
TotalLen = (UINT16) (TotalLen + OptCount[Index].Offset);
OptCount[Index].Offset = (UINT16) (TotalLen - OptCount[Index].Offset);
OptNum++;
}
}
*Count = OptNum;
*OptionPoint = NULL;
if (OptNum == 0) {
goto ON_EXIT;
}
//
// Allocate a buffer to hold the DHCP options, and after that, a
// continuous buffer to put all the options' data.
//
Options = AllocateZeroPool ((UINTN) (OptNum * sizeof (DHCP_OPTION)) + TotalLen);
if (Options == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_EXIT;
}
Context.OpCount = OptCount;
Context.Options = Options;
Context.Buf = (UINT8 *) (Options + OptNum);
Status = DhcpIterateOptions (Packet, DhcpFillOption, &Context);
if (EFI_ERROR (Status)) {
FreePool (Options);
goto ON_EXIT;
}
*OptionPoint = Options;
ON_EXIT:
FreePool (OptCount);
return Status;
}
/**
Validate the packet's options. If necessary, allocate
and fill in the interested parameters.
@param[in] Packet The packet to validate the options
@param[out] Para The variable to save the DHCP parameters.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory to validate the packet.
@retval EFI_INVALID_PARAMETER The options are mal-formated
@retval EFI_SUCCESS The options are parsed into OptionPoint
**/
EFI_STATUS
DhcpValidateOptions (
IN EFI_DHCP4_PACKET *Packet,
OUT DHCP_PARAMETER **Para OPTIONAL
)
{
DHCP_PARAMETER Parameter;
DHCP_OPTION_FORMAT *Format;
DHCP_OPTION *AllOption;
DHCP_OPTION *Option;
EFI_STATUS Status;
BOOLEAN Updated;
INTN Count;
INTN Index;
if (Para != NULL) {
*Para = NULL;
}
AllOption = NULL;
Status = DhcpParseOption (Packet, &Count, &AllOption);
if (EFI_ERROR (Status) || (Count == 0)) {
return Status;
}
ASSERT (AllOption != NULL);
Updated = FALSE;
ZeroMem (&Parameter, sizeof (Parameter));
for (Index = 0; Index < Count; Index++) {
Option = &AllOption[Index];
//
// Find the format of the option then validate it.
//
Format = DhcpFindOptionFormat (Option->Tag);
if (Format == NULL) {
continue;
}
if (!DhcpOptionIsValid (Format, Option->Data, Option->Len)) {
Status = EFI_INVALID_PARAMETER;
goto ON_EXIT;
}
//
// Get the client interested parameters
//
if (Format->Alert && (Para != NULL)) {
Updated = TRUE;
Status = DhcpGetParameter (Option->Tag, Option->Len, Option->Data, &Parameter);
if (EFI_ERROR (Status)) {
goto ON_EXIT;
}
}
}
if (Updated && (Para != NULL)) {
*Para = AllocateCopyPool (sizeof (DHCP_PARAMETER), &Parameter);
if (*Para == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto ON_EXIT;
}
}
ON_EXIT:
FreePool (AllOption);
return Status;
}
/**
Append an option to the memory, if the option is longer than
255 bytes, splits it into several options.
@param[out] Buf The buffer to append the option to
@param[in] Tag The option's tag
@param[in] DataLen The length of the option's data
@param[in] Data The option's data
@return The position to append the next option
**/
UINT8 *
DhcpAppendOption (
OUT UINT8 *Buf,
IN UINT8 Tag,
IN UINT16 DataLen,
IN UINT8 *Data
)
{
INTN Index;
INTN Len;
ASSERT (DataLen != 0);
for (Index = 0; Index < (DataLen + 254) / 255; Index++) {
Len = MIN (255, DataLen - Index * 255);
*(Buf++) = Tag;
*(Buf++) = (UINT8) Len;
CopyMem (Buf, Data + Index * 255, (UINTN) Len);
Buf += Len;
}
return Buf;
}
/**
Build a new DHCP packet from a seed packet. Options may be deleted or
appended. The caller should free the NewPacket when finished using it.
@param[in] SeedPacket The seed packet to start with
@param[in] DeleteCount The number of options to delete
@param[in] DeleteList The options to delete from the packet
@param[in] AppendCount The number of options to append
@param[in] AppendList The options to append to the packet
@param[out] NewPacket The new packet, allocated and built by this
function.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory
@retval EFI_INVALID_PARAMETER The options in SeekPacket are mal-formated
@retval EFI_SUCCESS The packet is build.
**/
EFI_STATUS
DhcpBuild (
IN EFI_DHCP4_PACKET *SeedPacket,
IN UINT32 DeleteCount,
IN UINT8 *DeleteList OPTIONAL,
IN UINT32 AppendCount,
IN EFI_DHCP4_PACKET_OPTION *AppendList[] OPTIONAL,
OUT EFI_DHCP4_PACKET **NewPacket
)
{
DHCP_OPTION *Mark;
DHCP_OPTION *SeedOptions;
EFI_DHCP4_PACKET *Packet;
EFI_STATUS Status;
INTN Count;
UINT32 Index;
UINT32 Len;
UINT8 *Buf;
//
// Use an array of DHCP_OPTION to mark the existance
// and position of each valid options.
//
Mark = AllocatePool (sizeof (DHCP_OPTION) * DHCP_MAX_OPTIONS);
if (Mark == NULL) {
return EFI_OUT_OF_RESOURCES;
}
for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {
Mark[Index].Tag = (UINT8) Index;
Mark[Index].Len = 0;
}
//
// Get list of the options from the seed packet, then put
// them to the mark array according to their tags.
//
SeedOptions = NULL;
Status = DhcpParseOption (SeedPacket, &Count, &SeedOptions);
if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
if (SeedOptions != NULL) {
for (Index = 0; Index < (UINT32) Count; Index++) {
Mark[SeedOptions[Index].Tag] = SeedOptions[Index];
}
}
//
// Mark the option's length is zero if it is in the DeleteList.
//
for (Index = 0; Index < DeleteCount; Index++) {
Mark[DeleteList[Index]].Len = 0;
}
//
// Add or replace the option if it is in the append list.
//
for (Index = 0; Index < AppendCount; Index++) {
Mark[AppendList[Index]->OpCode].Len = AppendList[Index]->Length;
Mark[AppendList[Index]->OpCode].Data = AppendList[Index]->Data;
}
//
// compute the new packet length. No need to add 1 byte for
// EOP option since EFI_DHCP4_PACKET includes one extra byte
// for option. It is necessary to split the option if it is
// longer than 255 bytes.
//
Len = sizeof (EFI_DHCP4_PACKET);
for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {
if (Mark[Index].Len != 0) {
Len += ((Mark[Index].Len + 254) / 255) * 2 + Mark[Index].Len;
}
}
Status = EFI_OUT_OF_RESOURCES;
Packet = (EFI_DHCP4_PACKET *) AllocatePool (Len);
if (Packet == NULL) {
goto ON_ERROR;
}
Packet->Size = Len;
Packet->Length = 0;
CopyMem (&Packet->Dhcp4.Header, &SeedPacket->Dhcp4.Header, sizeof (Packet->Dhcp4.Header));
Packet->Dhcp4.Magik = DHCP_OPTION_MAGIC;
Buf = Packet->Dhcp4.Option;
for (Index = 0; Index < DHCP_MAX_OPTIONS; Index++) {
if (Mark[Index].Len != 0) {
Buf = DhcpAppendOption (Buf, Mark[Index].Tag, Mark[Index].Len, Mark[Index].Data);
}
}
*(Buf++) = DHCP4_TAG_EOP;
Packet->Length = sizeof (EFI_DHCP4_HEADER) + sizeof (UINT32)
+ (UINT32) (Buf - Packet->Dhcp4.Option);
*NewPacket = Packet;
Status = EFI_SUCCESS;
ON_ERROR:
if (SeedOptions != NULL) {
FreePool (SeedOptions);
}
FreePool (Mark);
return Status;
}

View File

@@ -0,0 +1,228 @@
/** @file
To validate, parse and process the DHCP options.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef __EFI_DHCP4_OPTION_H__
#define __EFI_DHCP4_OPTION_H__
///
/// DHCP option tags (types)
///
#define DHCP_OPTION_MAGIC 0x63538263 // Network byte order
#define DHCP_MAX_OPTIONS 256
//
// DHCP option types, this is used to validate the DHCP options.
//
#define DHCP_OPTION_SWITCH 1
#define DHCP_OPTION_INT8 2
#define DHCP_OPTION_INT16 3
#define DHCP_OPTION_INT32 4
#define DHCP_OPTION_IP 5
#define DHCP_OPTION_IPPAIR 6
//
// Value of DHCP overload option
//
#define DHCP_OVERLOAD_FILENAME 1
#define DHCP_OVERLOAD_SVRNAME 2
#define DHCP_OVERLOAD_BOTH 3
///
/// The DHCP option structure. This structure extends the EFI_DHCP_OPTION
/// structure to support options longer than 255 bytes, such as classless route.
///
typedef struct {
UINT8 Tag;
UINT16 Len;
UINT8 *Data;
} DHCP_OPTION;
///
/// Structures used to parse the DHCP options with RFC3396 support.
///
typedef struct {
UINT8 Index;
UINT16 Offset;
} DHCP_OPTION_COUNT;
typedef struct {
DHCP_OPTION_COUNT *OpCount;
DHCP_OPTION *Options;
UINT8 *Buf;
} DHCP_OPTION_CONTEXT;
///
/// The options that matters to DHCP driver itself. The user of
/// DHCP clients may be interested in other options, such as
/// classless route, who can parse the DHCP offer to get them.
///
typedef struct {
IP4_ADDR NetMask; // DHCP4_TAG_NETMASK
IP4_ADDR Router; // DHCP4_TAG_ROUTER, only the first router is used
//
// DHCP specific options
//
UINT8 DhcpType; // DHCP4_TAG_MSG_TYPE
UINT8 Overload; // DHCP4_TAG_OVERLOAD
IP4_ADDR ServerId; // DHCP4_TAG_SERVER_ID
UINT32 Lease; // DHCP4_TAG_LEASE
UINT32 T1; // DHCP4_TAG_T1
UINT32 T2; // DHCP4_TAG_T2
} DHCP_PARAMETER;
///
/// Structure used to describe and validate the format of DHCP options.
/// Type is the options' data type, such as DHCP_OPTION_INT8. MinOccur
/// is the minium occurance of this data type. MaxOccur is defined
/// similarly. If MaxOccur is -1, it means that there is no limit on the
/// maximum occurance. Alert tells whether DHCP client should further
/// inspect the option to parse DHCP_PARAMETER.
///
typedef struct {
UINT8 Tag;
INTN Type;
INTN MinOccur;
INTN MaxOccur;
BOOLEAN Alert;
} DHCP_OPTION_FORMAT;
typedef
EFI_STATUS
(*DHCP_CHECK_OPTION) (
IN UINT8 Tag,
IN UINT8 Len,
IN UINT8 *Data,
IN VOID *Context
);
/**
Iterate through a DHCP message to visit each option. First inspect
all the options in the OPTION field. Then if overloaded, inspect
the options in FILENAME and SERVERNAME fields. One option may be
encoded in several places. See RFC 3396 Encoding Long Options in DHCP
@param[in] Packet The DHCP packet to check the options for
@param[in] Check The callback function to be called for each option
found
@param[in] Context The opaque parameter for Check
@retval EFI_SUCCESS The DHCP packet's options are well formated
@retval EFI_INVALID_PARAMETER The DHCP packet's options are not well formated
**/
EFI_STATUS
DhcpIterateOptions (
IN EFI_DHCP4_PACKET *Packet,
IN DHCP_CHECK_OPTION Check OPTIONAL,
IN VOID *Context
);
/**
Validate the packet's options. If necessary, allocate
and fill in the interested parameters.
@param[in] Packet The packet to validate the options
@param[out] Para The variable to save the DHCP parameters.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory to validate the packet.
@retval EFI_INVALID_PARAMETER The options are mal-formated
@retval EFI_SUCCESS The options are parsed into OptionPoint
**/
EFI_STATUS
DhcpValidateOptions (
IN EFI_DHCP4_PACKET *Packet,
OUT DHCP_PARAMETER **Para OPTIONAL
);
/**
Parse the options of a DHCP packet. It supports RFC 3396: Encoding
Long Options in DHCP. That is, it will combine all the option value
of all the occurances of each option.
A little bit of implemenation:
It adopts the "Key indexed counting" algorithm. First, it allocates
an array of 256 DHCP_OPTION_COUNTs because DHCP option tag is encoded
as a UINT8. It then iterates the DHCP packet to get data length of
each option by calling DhcpIterOptions with DhcpGetOptionLen. Now, it
knows the number of present options and their length. It allocates a
array of DHCP_OPTION and a continuous buffer after the array to put
all the options' data. Each option's data is pointed to by the Data
field in DHCP_OPTION structure. At last, it call DhcpIterateOptions
with DhcpFillOption to fill each option's data to its position in the
buffer.
@param[in] Packet The DHCP packet to parse the options
@param[out] Count The number of valid dhcp options present in the
packet
@param[out] OptionPoint The array that contains the DHCP options. Caller
should free it.
@retval EFI_NOT_FOUND Cannot find any option.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory to parse the packet.
@retval EFI_INVALID_PARAMETER The options are mal-formated
@retval EFI_SUCCESS The options are parsed into OptionPoint
**/
EFI_STATUS
DhcpParseOption (
IN EFI_DHCP4_PACKET *Packet,
OUT INTN *Count,
OUT DHCP_OPTION **OptionPoint
);
/**
Append an option to the memory, if the option is longer than
255 bytes, splits it into several options.
@param[out] Buf The buffer to append the option to
@param[in] Tag The option's tag
@param[in] DataLen The length of the option's data
@param[in] Data The option's data
@return The position to append the next option
**/
UINT8 *
DhcpAppendOption (
OUT UINT8 *Buf,
IN UINT8 Tag,
IN UINT16 DataLen,
IN UINT8 *Data
);
/**
Build a new DHCP packet from a seed packet. Options may be deleted or
appended. The caller should free the NewPacket when finished using it.
@param[in] SeedPacket The seed packet to start with
@param[in] DeleteCount The number of options to delete
@param[in] DeleteList The options to delete from the packet
@param[in] AppendCount The number of options to append
@param[in] AppendList The options to append to the packet
@param[out] NewPacket The new packet, allocated and built by this
function.
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory
@retval EFI_INVALID_PARAMETER The options in SeekPacket are mal-formated
@retval EFI_SUCCESS The packet is build.
**/
EFI_STATUS
DhcpBuild (
IN EFI_DHCP4_PACKET *SeedPacket,
IN UINT32 DeleteCount,
IN UINT8 *DeleteList OPTIONAL,
IN UINT32 AppendCount,
IN EFI_DHCP4_PACKET_OPTION *AppendList[] OPTIONAL,
OUT EFI_DHCP4_PACKET **NewPacket
);
#endif