summaryrefslogtreecommitdiffstats
path: root/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.c
diff options
context:
space:
mode:
authorhhtian <hhtian@6f19259b-4bc3-4df7-8a09-765794883524>2010-11-01 06:13:54 +0000
committerhhtian <hhtian@6f19259b-4bc3-4df7-8a09-765794883524>2010-11-01 06:13:54 +0000
commita3bcde70e6dc69000f85cc5deee98101d2ae200a (patch)
tree693709a5293f80b320931693b34b2d6983cfcf4b /NetworkPkg/Dhcp6Dxe/Dhcp6Impl.c
parent12873d57666d0beff41959a1fb8f9062016f0983 (diff)
downloadedk2-a3bcde70e6dc69000f85cc5deee98101d2ae200a.tar.gz
edk2-a3bcde70e6dc69000f85cc5deee98101d2ae200a.tar.bz2
edk2-a3bcde70e6dc69000f85cc5deee98101d2ae200a.zip
Add NetworkPkg (P.UDK2010.UP3.Network.P1)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10986 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'NetworkPkg/Dhcp6Dxe/Dhcp6Impl.c')
-rw-r--r--NetworkPkg/Dhcp6Dxe/Dhcp6Impl.c1220
1 files changed, 1220 insertions, 0 deletions
diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.c
new file mode 100644
index 0000000000..3e73976ddb
--- /dev/null
+++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.c
@@ -0,0 +1,1220 @@
+/** @file
+ This EFI_DHCP6_PROTOCOL interface implementation.
+
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Dhcp6Impl.h"
+
+//
+// Well-known multi-cast address defined in section-24.1 of rfc-3315
+//
+// ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2
+// ALL_DHCP_Servers address: FF05::1:3
+//
+EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress = {{0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}};
+EFI_IPv6_ADDRESS mAllDhcpServersAddress = {{0xFF, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 3}};
+
+EFI_DHCP6_PROTOCOL gDhcp6ProtocolTemplate = {
+ EfiDhcp6GetModeData,
+ EfiDhcp6Configure,
+ EfiDhcp6Start,
+ EfiDhcp6InfoRequest,
+ EfiDhcp6RenewRebind,
+ EfiDhcp6Decline,
+ EfiDhcp6Release,
+ EfiDhcp6Stop,
+ EfiDhcp6Parse
+};
+
+/**
+ Starts the DHCPv6 standard S.A.R.R. process.
+
+ The Start() function starts the DHCPv6 standard process. This function can
+ be called only when the state of Dhcp6 instance is in the Dhcp6Init state.
+ If the DHCP process completes successfully, the state of the Dhcp6 instance
+ will be transferred through Dhcp6Selecting and Dhcp6Requesting to the
+ Dhcp6Bound state.
+ Refer to rfc-3315 for precise state transitions during this process. At the
+ time when each event occurs in this process, the callback function that was set
+ by EFI_DHCP6_PROTOCOL.Configure() will be called, and the user can take this
+ opportunity to control the process.
+
+ @param[in] This The pointer to Dhcp6 protocol.
+
+ @retval EFI_SUCCESS The DHCPv6 standard process has started, or it has
+ completed when CompletionEvent is NULL.
+ @retval EFI_ACCESS_DENIED The EFI DHCPv6 Child instance hasn't been configured.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
+ @retval EFI_TIMEOUT The DHCPv6 configuration process failed because no
+ response was received from the server within the
+ specified timeout value.
+ @retval EFI_ABORTED The user aborted the DHCPv6 process.
+ @retval EFI_ALREADY_STARTED Some other Dhcp6 instance already started the DHCPv6
+ standard process.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+ @retval EFI_NO_MEDIA There was a media error.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiDhcp6Start (
+ IN EFI_DHCP6_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ DHCP6_INSTANCE *Instance;
+ DHCP6_SERVICE *Service;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = DHCP6_INSTANCE_FROM_THIS (This);
+ Service = Instance->Service;
+
+ //
+ // The instance hasn't been configured.
+ //
+ if (Instance->Config == NULL) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ ASSERT (Instance->IaCb.Ia != NULL);
+
+ //
+ // The instance has already been started.
+ //
+ if (Instance->IaCb.Ia->State != Dhcp6Init) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ Instance->UdpSts = EFI_ALREADY_STARTED;
+
+ //
+ // Need to clear initial time to make sure that elapsed-time
+ // is set to 0 for first Solicit.
+ //
+ Instance->StartTime = 0;
+
+ //
+ // Send the solicit message to start S.A.R.R process.
+ //
+ Status = Dhcp6SendSolicitMsg (Instance);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Register receive callback for the stateful exchange process.
+ //
+ Status = UdpIoRecvDatagram(
+ Service->UdpIo,
+ Dhcp6ReceivePacket,
+ Service,
+ 0
+ );
+
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ goto ON_ERROR;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ //
+ // Poll udp out of the net tpl if synchronous call.
+ //
+ if (Instance->Config->IaInfoEvent == NULL) {
+
+ while (Instance->UdpSts == EFI_ALREADY_STARTED) {
+ Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);
+ }
+ return Instance->UdpSts;
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Stops the DHCPv6 standard S.A.R.R. process.
+
+ The Stop() function is used to stop the DHCPv6 standard process. After this
+ function is called successfully, the state of Dhcp6 instance is transferred
+ into Dhcp6Init. EFI_DHCP6_PROTOCOL.Configure() needs to be called
+ before DHCPv6 standard process can be started again. This function can be
+ called when the Dhcp6 instance is in any state.
+
+ @param[in] This The pointer to the Dhcp6 protocol.
+
+ @retval EFI_SUCCESS The Dhcp6 instance is now in the Dhcp6Init state.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiDhcp6Stop (
+ IN EFI_DHCP6_PROTOCOL *This
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ EFI_UDP6_PROTOCOL *Udp6;
+ DHCP6_INSTANCE *Instance;
+ DHCP6_SERVICE *Service;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = DHCP6_INSTANCE_FROM_THIS (This);
+ Service = Instance->Service;
+ Udp6 = Service->UdpIo->Protocol.Udp6;
+ Status = EFI_SUCCESS;
+
+ //
+ // The instance hasn't been configured.
+ //
+ if (Instance->Config == NULL) {
+ return Status;
+ }
+
+ ASSERT (Instance->IaCb.Ia != NULL);
+
+ //
+ // The instance has already been stopped.
+ //
+ if (Instance->IaCb.Ia->State == Dhcp6Init ||
+ Instance->IaCb.Ia->State == Dhcp6Selecting ||
+ Instance->IaCb.Ia->State == Dhcp6Requesting
+ ) {
+ return Status;
+ }
+
+ //
+ // Release the current ready Ia.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ Instance->UdpSts = EFI_ALREADY_STARTED;
+ Dhcp6SendReleaseMsg (Instance, Instance->IaCb.Ia);
+
+ gBS->RestoreTPL (OldTpl);
+
+ //
+ // Poll udp out of the net tpl if synchoronus call.
+ //
+ if (Instance->Config->IaInfoEvent == NULL) {
+ ASSERT (Udp6 != NULL);
+ while (Instance->UdpSts == EFI_ALREADY_STARTED) {
+ Udp6->Poll (Udp6);
+ }
+ Status = Instance->UdpSts;
+ }
+
+ //
+ // Clean up the session data for the released Ia.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ Dhcp6CleanupSession (Instance, EFI_SUCCESS);
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Returns the current operating mode data for the Dhcp6 instance.
+
+ The GetModeData() function returns the current operating mode and
+ cached data packet for the Dhcp6 instance.
+
+ @param[in] This The pointer to the Dhcp6 protocol.
+ @param[out] Dhcp6ModeData The pointer to the Dhcp6 mode data.
+ @param[out] Dhcp6ConfigData The pointer to the Dhcp6 configure data.
+
+ @retval EFI_SUCCESS The mode data was returned.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_ACCESS_DENIED The EFI DHCPv6 Protocol instance was not
+ configured.
+**/
+EFI_STATUS
+EFIAPI
+EfiDhcp6GetModeData (
+ IN EFI_DHCP6_PROTOCOL *This,
+ OUT EFI_DHCP6_MODE_DATA *Dhcp6ModeData OPTIONAL,
+ OUT EFI_DHCP6_CONFIG_DATA *Dhcp6ConfigData OPTIONAL
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_DHCP6_IA *Ia;
+ DHCP6_INSTANCE *Instance;
+ DHCP6_SERVICE *Service;
+ UINT32 IaSize;
+ UINT32 IdSize;
+
+ if (This == NULL || (Dhcp6ModeData == NULL && Dhcp6ConfigData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = DHCP6_INSTANCE_FROM_THIS (This);
+ Service = Instance->Service;
+
+ if (Instance->Config == NULL && Dhcp6ConfigData != NULL) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ ASSERT (Service->ClientId != NULL);
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // User needs a copy of instance config data.
+ //
+ if (Dhcp6ConfigData != NULL) {
+ ZeroMem (Dhcp6ConfigData, sizeof(EFI_DHCP6_CONFIG_DATA));
+ //
+ // Duplicate config data, including all reference buffers.
+ //
+ if (EFI_ERROR (Dhcp6CopyConfigData (Dhcp6ConfigData, Instance->Config))) {
+ goto ON_ERROR;
+ }
+ }
+
+ //
+ // User need a copy of instance mode data.
+ //
+ if (Dhcp6ModeData != NULL) {
+ ZeroMem (Dhcp6ModeData, sizeof (EFI_DHCP6_MODE_DATA));
+ //
+ // Duplicate a copy of EFI_DHCP6_DUID for client Id.
+ //
+ IdSize = Service->ClientId->Length + sizeof (Service->ClientId->Length);
+
+ Dhcp6ModeData->ClientId = AllocateZeroPool (IdSize);
+ if (Dhcp6ModeData->ClientId == NULL) {
+ goto ON_ERROR;
+ }
+
+ CopyMem (
+ Dhcp6ModeData->ClientId,
+ Service->ClientId,
+ IdSize
+ );
+
+ Ia = Instance->IaCb.Ia;
+ if (Ia != NULL) {
+ //
+ // Duplicate a copy of EFI_DHCP6_IA for configured Ia.
+ //
+ IaSize = sizeof (EFI_DHCP6_IA) + (Ia->IaAddressCount -1) * sizeof (EFI_DHCP6_IA_ADDRESS);
+
+ Dhcp6ModeData->Ia = AllocateZeroPool (IaSize);
+ if (Dhcp6ModeData->Ia == NULL) {
+ goto ON_ERROR;
+ }
+
+ CopyMem (
+ Dhcp6ModeData->Ia,
+ Ia,
+ IaSize
+ );
+
+ //
+ // Duplicate a copy of reply packet if has.
+ //
+ if (Ia->ReplyPacket != NULL) {
+ Dhcp6ModeData->Ia->ReplyPacket = AllocateZeroPool (Ia->ReplyPacket->Size);
+ if (Dhcp6ModeData->Ia->ReplyPacket == NULL) {
+ goto ON_ERROR;
+ }
+ CopyMem (
+ Dhcp6ModeData->Ia->ReplyPacket,
+ Ia->ReplyPacket,
+ Ia->ReplyPacket->Size
+ );
+ }
+ }
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ if (Dhcp6ConfigData != NULL) {
+ Dhcp6CleanupConfigData (Dhcp6ConfigData);
+ }
+ if (Dhcp6ModeData != NULL) {
+ Dhcp6CleanupModeData (Dhcp6ModeData);
+ }
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_OUT_OF_RESOURCES;
+}
+
+
+/**
+ Initializes, changes, or resets the operational settings for the Dhcp6 instance.
+
+ The Configure() function is used to initialize or clean up the configuration
+ data of the Dhcp6 instance:
+ - When Dhcp6CfgData is not NULL and Configure() is called successfully, the
+ configuration data will be initialized in the Dhcp6 instance, and the state
+ of the configured IA will be transferred into Dhcp6Init.
+ - When Dhcp6CfgData is NULL and Configure() is called successfully, the
+ configuration data will be cleaned up and no IA will be associated with
+ the Dhcp6 instance.
+ To update the configuration data for an Dhcp6 instance, the original data
+ must be cleaned up before setting the new configuration data.
+
+ @param[in] This The pointer to the Dhcp6 protocol
+ @param[in] Dhcp6CfgData The pointer to the EFI_DHCP6_CONFIG_DATA.
+
+ @retval EFI_SUCCESS The Dhcp6 is configured successfully with the
+ Dhcp6Init state, or cleaned up the original
+ configuration setting.
+ @retval EFI_ACCESS_DENIED The Dhcp6 instance was already configured.
+ The Dhcp6 instance has already started the
+ DHCPv6 S.A.R.R when Dhcp6CfgData is NULL.
+ @retval EFI_INVALID_PARAMETER Some of the parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiDhcp6Configure (
+ IN EFI_DHCP6_PROTOCOL *This,
+ IN EFI_DHCP6_CONFIG_DATA *Dhcp6CfgData OPTIONAL
+ )
+{
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ LIST_ENTRY *Entry;
+ DHCP6_INSTANCE *Other;
+ DHCP6_INSTANCE *Instance;
+ DHCP6_SERVICE *Service;
+ UINTN Index;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = DHCP6_INSTANCE_FROM_THIS (This);
+ Service = Instance->Service;
+
+ //
+ // Check the parameter of configure data.
+ //
+ if (Dhcp6CfgData != NULL) {
+ if (Dhcp6CfgData->OptionCount > 0 && Dhcp6CfgData->OptionList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Dhcp6CfgData->OptionList != NULL) {
+ for (Index = 0; Index < Dhcp6CfgData->OptionCount; Index++) {
+ if (Dhcp6CfgData->OptionList[Index]->OpCode == Dhcp6OptClientId ||
+ Dhcp6CfgData->OptionList[Index]->OpCode == Dhcp6OptRapidCommit ||
+ Dhcp6CfgData->OptionList[Index]->OpCode == Dhcp6OptReconfigureAccept ||
+ Dhcp6CfgData->OptionList[Index]->OpCode == Dhcp6OptIana ||
+ Dhcp6CfgData->OptionList[Index]->OpCode == Dhcp6OptIata
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if (Dhcp6CfgData->IaDescriptor.Type != EFI_DHCP6_IA_TYPE_NA &&
+ Dhcp6CfgData->IaDescriptor.Type != EFI_DHCP6_IA_TYPE_TA
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Dhcp6CfgData->IaInfoEvent == NULL && Dhcp6CfgData->SolicitRetransmission == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Dhcp6CfgData->SolicitRetransmission != NULL &&
+ Dhcp6CfgData->SolicitRetransmission->Mrc == 0 &&
+ Dhcp6CfgData->SolicitRetransmission->Mrd == 0
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Make sure the (IaId, IaType) is unique over all the instances.
+ //
+ NET_LIST_FOR_EACH (Entry, &Service->Child) {
+ Other = NET_LIST_USER_STRUCT (Entry, DHCP6_INSTANCE, Link);
+ if (Other->IaCb.Ia != NULL &&
+ Other->IaCb.Ia->Descriptor.Type == Dhcp6CfgData->IaDescriptor.Type &&
+ Other->IaCb.Ia->Descriptor.IaId == Dhcp6CfgData->IaDescriptor.IaId
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ if (Dhcp6CfgData != NULL) {
+ //
+ // It's not allowed to configure one instance twice without configure null.
+ //
+ if (Instance->Config != NULL) {
+ gBS->RestoreTPL (OldTpl);
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Duplicate config data including all reference buffers.
+ //
+ Instance->Config = AllocateZeroPool (sizeof (EFI_DHCP6_CONFIG_DATA));
+ if (Instance->Config == NULL) {
+ gBS->RestoreTPL (OldTpl);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Dhcp6CopyConfigData (Instance->Config, Dhcp6CfgData);
+ if (EFI_ERROR(Status)) {
+ FreePool (Instance->Config);
+ gBS->RestoreTPL (OldTpl);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Initialize the Ia descriptor from the config data, and leave the other
+ // fields of the Ia as default value 0.
+ //
+ Instance->IaCb.Ia = AllocateZeroPool (sizeof(EFI_DHCP6_IA));
+ if (Instance->IaCb.Ia == NULL) {
+ Dhcp6CleanupConfigData (Instance->Config);
+ FreePool (Instance->Config);
+ gBS->RestoreTPL (OldTpl);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (
+ &Instance->IaCb.Ia->Descriptor,
+ &Dhcp6CfgData->IaDescriptor,
+ sizeof(EFI_DHCP6_IA_DESCRIPTOR)
+ );
+
+ } else {
+
+ if (Instance->Config == NULL) {
+ ASSERT (Instance->IaCb.Ia == NULL);
+ gBS->RestoreTPL (OldTpl);
+ return EFI_SUCCESS;
+ }
+
+ //
+ // It's not allowed to configure a started instance as null.
+ //
+ if (Instance->IaCb.Ia->State != Dhcp6Init) {
+ gBS->RestoreTPL (OldTpl);
+ return EFI_ACCESS_DENIED;
+ }
+
+ Dhcp6CleanupConfigData (Instance->Config);
+ FreePool (Instance->Config);
+ Instance->Config = NULL;
+
+ FreePool (Instance->IaCb.Ia);
+ Instance->IaCb.Ia = NULL;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Request configuration information without the assignment of any
+ Ia addresses of the client.
+
+ The InfoRequest() function is used to request configuration information
+ without the assignment of any IPv6 address of the client. The client sends
+ out an Information Request packet to obtain the required configuration
+ information, and DHCPv6 server responds with a Reply packet containing
+ the information for the client. The received Reply packet will be passed
+ to the user by ReplyCallback function. If the user returns EFI_NOT_READY from
+ ReplyCallback, the Dhcp6 instance will continue to receive other Reply
+ packets unless timeout according to the Retransmission parameter.
+ Otherwise, the Information Request exchange process will be finished
+ successfully if user returns EFI_SUCCESS from ReplyCallback.
+
+ @param[in] This The pointer to the Dhcp6 protocol.
+ @param[in] SendClientId If TRUE, the DHCPv6 protocol instance will build Client
+ Identifier option and include it into Information Request
+ packet. Otherwise, Client Identifier option will not be included.
+ @param[in] OptionRequest The pointer to the buffer of option request options.
+ @param[in] OptionCount The option number in the OptionList.
+ @param[in] OptionList The list of appended options.
+ @param[in] Retransmission The pointer to the retransmission of the message.
+ @param[in] TimeoutEvent The event of timeout.
+ @param[in] ReplyCallback The callback function when the reply was received.
+ @param[in] CallbackContext The pointer to the parameter passed to the callback.
+
+ @retval EFI_SUCCESS The DHCPv6 information request exchange process
+ completed when TimeoutEvent is NULL. Information
+ Request packet has been sent to DHCPv6 server when
+ TimeoutEvent is not NULL.
+ @retval EFI_NO_RESPONSE The DHCPv6 information request exchange process failed
+ because of no response, or not all requested-options
+ are responded by DHCPv6 servers when Timeout happened.
+ @retval EFI_ABORTED The DHCPv6 information request exchange process was aborted
+ by user.
+ @retval EFI_INVALID_PARAMETER Some parameter is NULL.
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiDhcp6InfoRequest (
+ IN EFI_DHCP6_PROTOCOL *This,
+ IN BOOLEAN SendClientId,
+ IN EFI_DHCP6_PACKET_OPTION *OptionRequest,
+ IN UINT32 OptionCount,
+ IN EFI_DHCP6_PACKET_OPTION *OptionList[] OPTIONAL,
+ IN EFI_DHCP6_RETRANSMISSION *Retransmission,
+ IN EFI_EVENT TimeoutEvent OPTIONAL,
+ IN EFI_DHCP6_INFO_CALLBACK ReplyCallback,
+ IN VOID *CallbackContext OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ DHCP6_INSTANCE *Instance;
+ DHCP6_SERVICE *Service;
+ DHCP6_INF_CB *InfCb;
+ UINTN Index;
+
+ if (This == NULL || OptionRequest == NULL || Retransmission == NULL || ReplyCallback == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Retransmission != NULL && Retransmission->Mrc == 0 && Retransmission->Mrd == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (OptionCount > 0 && OptionList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (OptionList != NULL) {
+ for (Index = 0; Index < OptionCount; Index++) {
+ if (OptionList[Index]->OpCode == Dhcp6OptClientId || OptionList[Index]->OpCode == Dhcp6OptRequestOption) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ Instance = DHCP6_INSTANCE_FROM_THIS (This);
+ Service = Instance->Service;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ Instance->UdpSts = EFI_ALREADY_STARTED;
+
+ //
+ // Create and initialize the control block for the info-request.
+ //
+ InfCb = AllocateZeroPool (sizeof(DHCP6_INF_CB));
+
+ if (InfCb == NULL) {
+ gBS->RestoreTPL (OldTpl);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InfCb->ReplyCallback = ReplyCallback;
+ InfCb->CallbackContext = CallbackContext;
+ InfCb->TimeoutEvent = TimeoutEvent;
+
+ InsertTailList (&Instance->InfList, &InfCb->Link);
+
+ //
+ // Send the info-request message to start exchange process.
+ //
+ Status = Dhcp6SendInfoRequestMsg (
+ Instance,
+ InfCb,
+ SendClientId,
+ OptionRequest,
+ OptionCount,
+ OptionList,
+ Retransmission
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Register receive callback for the stateless exchange process.
+ //
+ Status = UdpIoRecvDatagram(
+ Service->UdpIo,
+ Dhcp6ReceivePacket,
+ Service,
+ 0
+ );
+
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ goto ON_ERROR;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ //
+ // Poll udp out of the net tpl if synchoronus call.
+ //
+ if (TimeoutEvent == NULL) {
+
+ while (Instance->UdpSts == EFI_ALREADY_STARTED) {
+ Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);
+ }
+ return Instance->UdpSts;
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ RemoveEntryList (&InfCb->Link);
+ FreePool (InfCb);
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Manually extend the valid and preferred lifetimes for the IPv6 addresses
+ of the configured IA and update other configuration parameters by sending a
+ Renew or Rebind packet.
+
+ The RenewRebind() function is used to manually extend the valid and preferred
+ lifetimes for the IPv6 addresses of the configured IA, and update other
+ configuration parameters by sending Renew or Rebind packet.
+ - When RebindRequest is FALSE and the state of the configured IA is Dhcp6Bound,
+ it sends Renew packet to the previously DHCPv6 server and transfer the
+ state of the configured IA to Dhcp6Renewing. If valid Reply packet received,
+ the state transfers to Dhcp6Bound and the valid and preferred timer restarts.
+ If fails, the state transfers to Dhcp6Bound, but the timer continues.
+ - When RebindRequest is TRUE and the state of the configured IA is Dhcp6Bound,
+ it will send a Rebind packet. If valid Reply packet is received, the state transfers
+ to Dhcp6Bound and the valid and preferred timer restarts. If it fails, the state
+ transfers to Dhcp6Init, and the IA can't be used.
+
+ @param[in] This The pointer to the Dhcp6 protocol.
+ @param[in] RebindRequest If TRUE, Rebind packet will be sent and enter Dhcp6Rebinding state.
+ Otherwise, Renew packet will be sent and enter Dhcp6Renewing state.
+
+ @retval EFI_SUCCESS The DHCPv6 renew/rebind exchange process has
+ completed and at least one IPv6 address of the
+ configured IA has been bound again when
+ EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL.
+ The EFI DHCPv6 Protocol instance has sent Renew
+ or Rebind packet when
+ EFI_DHCP6_CONFIG_DATA.IaInfoEvent is not NULL.
+ @retval EFI_ACCESS_DENIED The Dhcp6 instance hasn't been configured, or the
+ state of the configured IA is not in Dhcp6Bound.
+ @retval EFI_ALREADY_STARTED The state of the configured IA has already entered
+ Dhcp6Renewing when RebindRequest is FALSE.
+ The state of the configured IA has already entered
+ Dhcp6Rebinding when RebindRequest is TRUE.
+ @retval EFI_ABORTED The DHCPv6 renew/rebind exchange process aborted
+ by the user.
+ @retval EFI_NO_RESPONSE The DHCPv6 renew/rebind exchange process failed
+ because of no response.
+ @retval EFI_NO_MAPPING No IPv6 address has been bound to the configured
+ IA after the DHCPv6 renew/rebind exchange process.
+ @retval EFI_INVALID_PARAMETER Some parameter is NULL.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiDhcp6RenewRebind (
+ IN EFI_DHCP6_PROTOCOL *This,
+ IN BOOLEAN RebindRequest
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ DHCP6_INSTANCE *Instance;
+ DHCP6_SERVICE *Service;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = DHCP6_INSTANCE_FROM_THIS (This);
+ Service = Instance->Service;
+
+ //
+ // The instance hasn't been configured.
+ //
+ if (Instance->Config == NULL) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ ASSERT (Instance->IaCb.Ia != NULL);
+
+ //
+ // The instance has already entered renewing or rebinding state.
+ //
+ if ((Instance->IaCb.Ia->State == Dhcp6Rebinding && RebindRequest) ||
+ (Instance->IaCb.Ia->State == Dhcp6Renewing && !RebindRequest)
+ ) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (Instance->IaCb.Ia->State != Dhcp6Bound) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ Instance->UdpSts = EFI_ALREADY_STARTED;
+
+ //
+ // Send renew/rebind message to start exchange process.
+ //
+ Status = Dhcp6SendRenewRebindMsg (Instance, RebindRequest);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Register receive callback for the stateful exchange process.
+ //
+ Status = UdpIoRecvDatagram(
+ Service->UdpIo,
+ Dhcp6ReceivePacket,
+ Service,
+ 0
+ );
+
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ goto ON_ERROR;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ //
+ // Poll udp out of the net tpl if synchoronus call.
+ //
+ if (Instance->Config->IaInfoEvent == NULL) {
+
+ while (Instance->UdpSts == EFI_ALREADY_STARTED) {
+ Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);
+ }
+ return Instance->UdpSts;
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+
+/**
+ Inform that one or more addresses assigned by a server are already
+ in use by another node.
+
+ The Decline() function is used to manually decline the assignment of
+ IPv6 addresses, which have been already used by another node. If all
+ IPv6 addresses of the configured IA are declined through this function,
+ the state of the IA will switch through Dhcp6Declining to Dhcp6Init.
+ Otherwise, the state of the IA will restore to Dhcp6Bound after the
+ declining process. The Decline() can only be called when the IA is in
+ Dhcp6Bound state. If the EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL,
+ this function is a blocking operation. It will return after the
+ declining process finishes, or aborted by user.
+
+ @param[in] This The pointer to EFI_DHCP6_PROTOCOL.
+ @param[in] AddressCount The number of declining addresses.
+ @param[in] Addresses The pointer to the buffer stored the declining
+ addresses.
+
+ @retval EFI_SUCCESS The DHCPv6 decline exchange process completed
+ when EFI_DHCP6_CONFIG_DATA.IaInfoEvent was NULL.
+ The Dhcp6 instance sent Decline packet when
+ EFI_DHCP6_CONFIG_DATA.IaInfoEvent was not NULL.
+ @retval EFI_ACCESS_DENIED The Dhcp6 instance hasn't been configured, or the
+ state of the configured IA is not in Dhcp6Bound.
+ @retval EFI_ABORTED The DHCPv6 decline exchange process aborted by user.
+ @retval EFI_NOT_FOUND Any specified IPv6 address is not correlated with
+ the configured IA for this instance.
+ @retval EFI_INVALID_PARAMETER Some parameter is NULL.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiDhcp6Decline (
+ IN EFI_DHCP6_PROTOCOL *This,
+ IN UINT32 AddressCount,
+ IN EFI_IPv6_ADDRESS *Addresses
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ EFI_DHCP6_IA *DecIa;
+ DHCP6_INSTANCE *Instance;
+ DHCP6_SERVICE *Service;
+
+ if (This == NULL || AddressCount == 0 || Addresses == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = DHCP6_INSTANCE_FROM_THIS (This);
+ Service = Instance->Service;
+
+ //
+ // The instance hasn't been configured.
+ //
+ if (Instance->Config == NULL) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ ASSERT (Instance->IaCb.Ia != NULL);
+
+ if (Instance->IaCb.Ia->State != Dhcp6Bound) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Check whether all the declined addresses belongs to the configured Ia.
+ //
+ Status = Dhcp6CheckAddress (Instance->IaCb.Ia, AddressCount, Addresses);
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ Instance->UdpSts = EFI_ALREADY_STARTED;
+
+ //
+ // Deprive of all the declined addresses from the configured Ia, and create a
+ // DeclineIa used to create decline message.
+ //
+ DecIa = Dhcp6DepriveAddress (Instance->IaCb.Ia, AddressCount, Addresses);
+
+ if (DecIa == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_ERROR;
+ }
+
+ //
+ // Send the decline message to start exchange process.
+ //
+ Status = Dhcp6SendDeclineMsg (Instance, DecIa);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Register receive callback for the stateful exchange process.
+ //
+ Status = UdpIoRecvDatagram(
+ Service->UdpIo,
+ Dhcp6ReceivePacket,
+ Service,
+ 0
+ );
+
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ goto ON_ERROR;
+ }
+
+ FreePool (DecIa);
+ gBS->RestoreTPL (OldTpl);
+
+ //
+ // Poll udp out of the net tpl if synchoronus call.
+ //
+ if (Instance->Config->IaInfoEvent == NULL) {
+
+ while (Instance->UdpSts == EFI_ALREADY_STARTED) {
+ Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);
+ }
+ return Instance->UdpSts;
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ if (DecIa != NULL) {
+ FreePool (DecIa);
+ }
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Release one or more addresses associated with the configured Ia
+ for current instance.
+
+ The Release() function is used to manually release one or more
+ IPv6 addresses. If AddressCount is zero, it will release all IPv6
+ addresses of the configured IA. If all IPv6 addresses of the IA are
+ released through this function, the state of the IA will switch
+ through Dhcp6Releasing to Dhcp6Init, otherwise, the state of the
+ IA will restore to Dhcp6Bound after the releasing process.
+ The Release() can only be called when the IA is in Dhcp6Bound state.
+ If the EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL, the function is
+ a blocking operation. It will return after the releasing process
+ finishes, or is aborted by user.
+
+ @param[in] This The pointer to the Dhcp6 protocol.
+ @param[in] AddressCount The number of releasing addresses.
+ @param[in] Addresses The pointer to the buffer stored the releasing
+ addresses.
+
+ @retval EFI_SUCCESS The DHCPv6 release exchange process
+ completed when EFI_DHCP6_CONFIG_DATA.IaInfoEvent
+ was NULL. The Dhcp6 instance was sent Release
+ packet when EFI_DHCP6_CONFIG_DATA.IaInfoEvent
+ was not NULL.
+ @retval EFI_ACCESS_DENIED The Dhcp6 instance hasn't been configured, or the
+ state of the configured IA is not in Dhcp6Bound.
+ @retval EFI_ABORTED The DHCPv6 release exchange process aborted by user.
+ @retval EFI_NOT_FOUND Any specified IPv6 address is not correlated with
+ the configured IA for this instance.
+ @retval EFI_INVALID_PARAMETER Some parameter is NULL.
+ @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiDhcp6Release (
+ IN EFI_DHCP6_PROTOCOL *This,
+ IN UINT32 AddressCount,
+ IN EFI_IPv6_ADDRESS *Addresses
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ EFI_DHCP6_IA *RelIa;
+ DHCP6_INSTANCE *Instance;
+ DHCP6_SERVICE *Service;
+
+ if (This == NULL || (AddressCount != 0 && Addresses == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = DHCP6_INSTANCE_FROM_THIS (This);
+ Service = Instance->Service;
+
+ //
+ // The instance hasn't been configured.
+ //
+ if (Instance->Config == NULL) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ ASSERT (Instance->IaCb.Ia != NULL);
+
+ if (Instance->IaCb.Ia->State != Dhcp6Bound) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Check whether all the released addresses belongs to the configured Ia.
+ //
+ Status = Dhcp6CheckAddress (Instance->IaCb.Ia, AddressCount, Addresses);
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ Instance->UdpSts = EFI_ALREADY_STARTED;
+
+ //
+ // Deprive of all the released addresses from the configured Ia, and create a
+ // ReleaseIa used to create release message.
+ //
+ RelIa = Dhcp6DepriveAddress (Instance->IaCb.Ia, AddressCount, Addresses);
+
+ if (RelIa == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_ERROR;
+ }
+
+ //
+ // Send the release message to start exchange process.
+ //
+ Status = Dhcp6SendReleaseMsg (Instance, RelIa);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Register receive callback for the stateful exchange process.
+ //
+ Status = UdpIoRecvDatagram(
+ Service->UdpIo,
+ Dhcp6ReceivePacket,
+ Service,
+ 0
+ );
+
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ goto ON_ERROR;
+ }
+
+ FreePool (RelIa);
+ gBS->RestoreTPL (OldTpl);
+
+ //
+ // Poll udp out of the net tpl if synchoronus call.
+ //
+ if (Instance->Config->IaInfoEvent == NULL) {
+ while (Instance->UdpSts == EFI_ALREADY_STARTED) {
+ Service->UdpIo->Protocol.Udp6->Poll (Service->UdpIo->Protocol.Udp6);
+ }
+ return Instance->UdpSts;
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ if (RelIa != NULL) {
+ FreePool (RelIa);
+ }
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Parse the option data in the Dhcp6 packet.
+
+ The Parse() function is used to retrieve the option list in the DHCPv6 packet.
+
+ @param[in] This The pointer to the Dhcp6 protocol.
+ @param[in] Packet The pointer to the Dhcp6 packet.
+ @param[in, out] OptionCount The number of option in the packet.
+ @param[out] PacketOptionList The array of pointers to each option in the packet.
+
+ @retval EFI_SUCCESS The packet was successfully parsed.
+ @retval EFI_INVALID_PARAMETER Some parameter is NULL.
+ @retval EFI_BUFFER_TOO_SMALL *OptionCount is smaller than the number of options
+ that were found in the Packet.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiDhcp6Parse (
+ IN EFI_DHCP6_PROTOCOL *This,
+ IN EFI_DHCP6_PACKET *Packet,
+ IN OUT UINT32 *OptionCount,
+ OUT EFI_DHCP6_PACKET_OPTION *PacketOptionList[] OPTIONAL
+ )
+{
+ UINT32 OptCnt;
+ UINT32 OptLen;
+ UINT16 DataLen;
+ UINT8 *Start;
+ UINT8 *End;
+
+ if (This == NULL || Packet == NULL || OptionCount == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*OptionCount != 0 && PacketOptionList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Packet->Length > Packet->Size || Packet->Length < sizeof (EFI_DHCP6_HEADER)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The format of Dhcp6 option:
+ //
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | option-code | option-len (option data) |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | option-data |
+ // | (option-len octets) |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+
+ OptCnt = 0;
+ OptLen = Packet->Length - sizeof (EFI_DHCP6_HEADER);
+ Start = Packet->Dhcp6.Option;
+ End = Start + OptLen;
+
+ //
+ // Calculate the number of option in the packet.
+ //
+ while (Start < End) {
+ DataLen = ((EFI_DHCP6_PACKET_OPTION *) Start)->OpLen;
+ Start += (NTOHS (DataLen) + 4);
+ OptCnt++;
+ }
+
+ //
+ // It will return buffer too small if pass-in option count is smaller than the
+ // actual count of options in the packet.
+ //
+ if (OptCnt > *OptionCount) {
+ *OptionCount = OptCnt;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ ZeroMem (
+ PacketOptionList,
+ (*OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *))
+ );
+
+ OptCnt = 0;
+ Start = Packet->Dhcp6.Option;
+
+ while (Start < End) {
+
+ PacketOptionList[OptCnt] = (EFI_DHCP6_PACKET_OPTION *) Start;
+ DataLen = ((EFI_DHCP6_PACKET_OPTION *) Start)->OpLen;
+ Start += (NTOHS (DataLen) + 4);
+ OptCnt++;
+ }
+
+ return EFI_SUCCESS;
+}
+