REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the NetworkPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Maciej Rabeda <maciej.rabeda@linux.intel.com>
		
			
				
	
	
		
			1227 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1227 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   This EFI_DHCP6_PROTOCOL interface implementation.
 | |
| 
 | |
|   Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #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
 | |
| //
 | |
| EFI_IPv6_ADDRESS  mAllDhcpRelayAndServersAddress = {
 | |
|   { 0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2 }
 | |
| };
 | |
| 
 | |
| 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;
 | |
|   EFI_STATUS      MediaStatus;
 | |
| 
 | |
|   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);
 | |
| 
 | |
|   //
 | |
|   // Check Media Status.
 | |
|   //
 | |
|   MediaStatus = EFI_SUCCESS;
 | |
|   NetLibDetectMediaWaitTimeout (Service->Controller, DHCP_CHECK_MEDIA_WAITING_TIME, &MediaStatus);
 | |
|   if (MediaStatus != EFI_SUCCESS) {
 | |
|     Status = EFI_NO_MEDIA;
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
| 
 | |
|   Instance->UdpSts = EFI_ALREADY_STARTED;
 | |
| 
 | |
|   //
 | |
|   // 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);
 | |
| 
 | |
|   //
 | |
|   // No valid REPLY message received yet, cleanup this instance directly.
 | |
|   //
 | |
|   if ((Instance->IaCb.Ia->State == Dhcp6Init) ||
 | |
|       (Instance->IaCb.Ia->State == Dhcp6Selecting) ||
 | |
|       (Instance->IaCb.Ia->State == Dhcp6Requesting)
 | |
|       )
 | |
|   {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Release the current ready Ia.
 | |
|   //
 | |
|   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
 | |
| 
 | |
|   Instance->UdpSts = EFI_ALREADY_STARTED;
 | |
|   Status           = Dhcp6SendReleaseMsg (Instance, Instance->IaCb.Ia);
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Poll udp out of the net tpl if synchronous call.
 | |
|   //
 | |
|   if (Instance->Config->IaInfoEvent == NULL) {
 | |
|     ASSERT (Udp6 != NULL);
 | |
|     while (Instance->UdpSts == EFI_ALREADY_STARTED) {
 | |
|       Udp6->Poll (Udp6);
 | |
|     }
 | |
| 
 | |
|     Status = Instance->UdpSts;
 | |
|   }
 | |
| 
 | |
| ON_EXIT:
 | |
|   //
 | |
|   // 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;
 | |
|   DHCP6_INSTANCE  *Instance;
 | |
|   DHCP6_SERVICE   *Service;
 | |
|   UINTN           Index;
 | |
|   EFI_EVENT       Timer;
 | |
|   EFI_STATUS      TimerStatus;
 | |
|   UINTN           GetMappingTimeOut;
 | |
| 
 | |
|   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;
 | |
| 
 | |
|   Status = Dhcp6StartInfoRequest (
 | |
|              Instance,
 | |
|              SendClientId,
 | |
|              OptionRequest,
 | |
|              OptionCount,
 | |
|              OptionList,
 | |
|              Retransmission,
 | |
|              TimeoutEvent,
 | |
|              ReplyCallback,
 | |
|              CallbackContext
 | |
|              );
 | |
|   if (Status == EFI_NO_MAPPING) {
 | |
|     //
 | |
|     // The link local address is not ready, wait for some time and restart
 | |
|     // the DHCP6 information request process.
 | |
|     //
 | |
|     Status = Dhcp6GetMappingTimeOut (Service->Ip6Cfg, &GetMappingTimeOut);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Start the timer, wait for link local address DAD to finish.
 | |
|     //
 | |
|     Status = gBS->SetTimer (Timer, TimerRelative, GetMappingTimeOut);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       gBS->CloseEvent (Timer);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     do {
 | |
|       TimerStatus = gBS->CheckEvent (Timer);
 | |
|       if (!EFI_ERROR (TimerStatus)) {
 | |
|         Status = Dhcp6StartInfoRequest (
 | |
|                    Instance,
 | |
|                    SendClientId,
 | |
|                    OptionRequest,
 | |
|                    OptionCount,
 | |
|                    OptionList,
 | |
|                    Retransmission,
 | |
|                    TimeoutEvent,
 | |
|                    ReplyCallback,
 | |
|                    CallbackContext
 | |
|                    );
 | |
|       }
 | |
|     } while (TimerStatus == EFI_NOT_READY);
 | |
| 
 | |
|     gBS->CloseEvent (Timer);
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Poll udp out of the net tpl if synchronous 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;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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 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;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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 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:
 | |
| 
 | |
|   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 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:
 | |
| 
 | |
|   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;
 | |
| }
 |