git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11219 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			804 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			804 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  The general interfaces of the IKEv2.
 | 
						|
 | 
						|
  Copyright (c) 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 "Utility.h"
 | 
						|
#include "IpSecDebug.h"
 | 
						|
#include "IkeService.h"
 | 
						|
#include "IpSecConfigImpl.h"
 | 
						|
 | 
						|
/**
 | 
						|
  General interface to intialize a IKEv2 negotiation.
 | 
						|
 | 
						|
  @param[in]  UdpService      Point to Udp Servcie used for the IKE packet sending.
 | 
						|
  @param[in]  SpdEntry        Point to SPD entry related to this IKE negotiation.
 | 
						|
  @param[in]  PadEntry        Point to PAD entry related to this IKE negotiation.
 | 
						|
  @param[in]  RemoteIp        Point to IP Address which the remote peer to negnotiate.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The operation is successful.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The required system resource can't be allocated.
 | 
						|
  @retval EFI_INVALID_PARAMETER If UdpService or RemoteIp is NULL.
 | 
						|
  @return Others                The operation is failed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ikev2NegotiateSa (
 | 
						|
  IN IKE_UDP_SERVICE         *UdpService,
 | 
						|
  IN IPSEC_SPD_ENTRY         *SpdEntry,
 | 
						|
  IN IPSEC_PAD_ENTRY         *PadEntry,
 | 
						|
  IN EFI_IP_ADDRESS          *RemoteIp
 | 
						|
  )
 | 
						|
{
 | 
						|
  IPSEC_PRIVATE_DATA        *Private;
 | 
						|
  IKEV2_SA_SESSION          *IkeSaSession;
 | 
						|
  IKEV2_SESSION_COMMON      *SessionCommon;
 | 
						|
  IKEV2_PACKET_HANDLER      Handler;
 | 
						|
  IKE_PACKET                *IkePacket;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  
 | 
						|
  if (UdpService == NULL || RemoteIp == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  IkePacket = NULL;
 | 
						|
  Private   = (UdpService->IpVersion == IP_VERSION_4) ?
 | 
						|
               IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) :
 | 
						|
               IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);
 | 
						|
 | 
						|
  //
 | 
						|
  // Lookup the remote ip address in the processing IKE SA session list.
 | 
						|
  //
 | 
						|
  IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2SessionList, RemoteIp);
 | 
						|
  if (IkeSaSession != NULL) {
 | 
						|
    //
 | 
						|
    // Drop the packet if already in process.
 | 
						|
    //
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Create a new IkeSaSession and initiate the common parameters.
 | 
						|
  //
 | 
						|
  IkeSaSession = Ikev2SaSessionAlloc (Private, UdpService);
 | 
						|
  if (IkeSaSession == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Set the specific parameters and state(IKE_STATE_INIT).
 | 
						|
  //
 | 
						|
  IkeSaSession->Spd            = SpdEntry;
 | 
						|
  IkeSaSession->Pad            = PadEntry;  
 | 
						|
  SessionCommon                = &IkeSaSession->SessionCommon;
 | 
						|
  SessionCommon->IsInitiator   = TRUE;
 | 
						|
  SessionCommon->State         = IkeStateInit;
 | 
						|
  //
 | 
						|
  // TODO: Get the prefer DH Group from the IPsec Configuration, after the IPsecconfig application update
 | 
						|
  // to support it.
 | 
						|
  //
 | 
						|
  SessionCommon->PreferDhGroup = IKEV2_TRANSFORM_ID_DH_1024MODP;
 | 
						|
  
 | 
						|
  CopyMem (
 | 
						|
    &SessionCommon->RemotePeerIp,
 | 
						|
    RemoteIp,
 | 
						|
    sizeof (EFI_IP_ADDRESS)
 | 
						|
    );
 | 
						|
  
 | 
						|
  CopyMem (
 | 
						|
    &SessionCommon->LocalPeerIp,
 | 
						|
    &UdpService->DefaultAddress,
 | 
						|
    sizeof (EFI_IP_ADDRESS)
 | 
						|
    );
 | 
						|
 | 
						|
  IKEV2_DUMP_STATE (SessionCommon->State, IkeStateInit);
 | 
						|
 | 
						|
  //
 | 
						|
  // Initiate the SAD data of the IkeSaSession.
 | 
						|
  //
 | 
						|
  IkeSaSession->SaData = Ikev2InitializeSaData (SessionCommon);
 | 
						|
  if (IkeSaSession->SaData == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Generate an IKE request packet and send it out.
 | 
						|
  //
 | 
						|
  Handler   = mIkev2Initial[IkeSaSession->Pad->Data->AuthMethod][SessionCommon->State];
 | 
						|
  IkePacket = Handler.Generator ((UINT8 *) IkeSaSession, NULL);
 | 
						|
  if (IkePacket == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Ikev2SendIkePacket (UdpService, (UINT8 *) SessionCommon, IkePacket, 0);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Insert the current IkeSaSession into the processing IKE SA list.
 | 
						|
  //
 | 
						|
  Ikev2SaSessionInsert (&Private->Ikev2SessionList, IkeSaSession, RemoteIp);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
ON_ERROR:
 | 
						|
 | 
						|
  if (IkePacket != NULL) {
 | 
						|
    IkePacketFree (IkePacket);
 | 
						|
  }
 | 
						|
  Ikev2SaSessionFree (IkeSaSession);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  It is general interface to negotiate the Child SA.
 | 
						|
 | 
						|
  There are three situations which will invoke this function. First, create a CHILD 
 | 
						|
  SA if the input Context is NULL. Second, rekeying the existing IKE SA if the Context 
 | 
						|
  is a IKEv2_SA_SESSION. Third, rekeying the existing CHILD SA if the context is a 
 | 
						|
  IKEv2_CHILD_SA_SESSION.
 | 
						|
 | 
						|
  @param[in] IkeSaSession  Pointer to IKEv2_SA_SESSION related to this operation.
 | 
						|
  @param[in] SpdEntry      Pointer to IPSEC_SPD_ENTRY related to this operation.
 | 
						|
  @param[in] Context       The data pass from the caller.
 | 
						|
  
 | 
						|
  @retval EFI_SUCCESS          The operation is successful.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated.
 | 
						|
  @retval EFI_UNSUPPORTED      The condition is not support yet.
 | 
						|
  @return Others               The operation is failed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ikev2NegotiateChildSa (
 | 
						|
  IN UINT8           *IkeSaSession,
 | 
						|
  IN IPSEC_SPD_ENTRY *SpdEntry,
 | 
						|
  IN UINT8           *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  IKEV2_SA_SESSION          *SaSession;
 | 
						|
  IKEV2_CHILD_SA_SESSION    *ChildSaSession;
 | 
						|
  IKEV2_SESSION_COMMON      *ChildSaCommon;
 | 
						|
  IKE_PACKET                *IkePacket;
 | 
						|
  IKE_UDP_SERVICE           *UdpService;
 | 
						|
 | 
						|
  SaSession  = (IKEV2_SA_SESSION*) IkeSaSession;
 | 
						|
  UdpService = SaSession->SessionCommon.UdpService;
 | 
						|
  IkePacket  = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // 1. Create another child SA session if context is null.
 | 
						|
  // 2. Rekeying the IKE SA session if the context is IKE SA session.
 | 
						|
  // 3. Rekeying the child SA session if the context is child SA session.
 | 
						|
  //
 | 
						|
  if (Context == NULL) {
 | 
						|
    //
 | 
						|
    // Create a new ChildSaSession and initiate the common parameters.
 | 
						|
    //
 | 
						|
    ChildSaSession = Ikev2ChildSaSessionAlloc (UdpService, SaSession);
 | 
						|
 | 
						|
    if (ChildSaSession == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Set the specific parameters and state as IKE_STATE_CREATE_CHILD.
 | 
						|
    //
 | 
						|
    ChildSaSession->Spd         = SpdEntry;
 | 
						|
    ChildSaCommon               = &ChildSaSession->SessionCommon;
 | 
						|
    ChildSaCommon->IsInitiator  = TRUE;
 | 
						|
    ChildSaCommon->State        = IkeStateCreateChild;
 | 
						|
 | 
						|
    IKEV2_DUMP_STATE (ChildSaCommon->State, IkeStateCreateChild);
 | 
						|
 | 
						|
    if (SpdEntry->Selector->NextLayerProtocol != EFI_IPSEC_ANY_PROTOCOL) {
 | 
						|
      ChildSaSession->ProtoId = SpdEntry->Selector->NextLayerProtocol;
 | 
						|
    }
 | 
						|
 | 
						|
    if (SpdEntry->Selector->LocalPort != EFI_IPSEC_ANY_PORT) {
 | 
						|
      ChildSaSession->LocalPort = SpdEntry->Selector->LocalPort;
 | 
						|
    }
 | 
						|
 | 
						|
    if (SpdEntry->Selector->RemotePort != EFI_IPSEC_ANY_PORT) {
 | 
						|
      ChildSaSession->RemotePort = SpdEntry->Selector->RemotePort;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Initiate the SAD data parameters of the ChildSaSession.
 | 
						|
    //
 | 
						|
    ChildSaSession->SaData = Ikev2InitializeSaData (ChildSaCommon);
 | 
						|
    if (ChildSaSession->SaData == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto ON_ERROR;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Generate an IKE request packet and send it out.
 | 
						|
    //
 | 
						|
    IkePacket = mIkev2CreateChild.Generator ((UINT8 *) ChildSaSession, NULL);
 | 
						|
 | 
						|
    if (IkePacket == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto ON_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = Ikev2SendIkePacket (UdpService, (UINT8 *) ChildSaCommon, IkePacket, 0);
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto ON_ERROR;
 | 
						|
    }
 | 
						|
    
 | 
						|
    //
 | 
						|
    // Insert the ChildSaSession into processing child SA list.
 | 
						|
    //
 | 
						|
    Ikev2ChildSaSessionInsert (&SaSession->ChildSaSessionList, ChildSaSession);
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // TODO: Rekeying IkeSaSession or ChildSaSession, NOT support yet.
 | 
						|
    //
 | 
						|
    // Rekey IkeSa, set IkeSaSession->State and pass over IkeSaSession
 | 
						|
    // Rekey ChildSa, set ChildSaSession->State and pass over ChildSaSession
 | 
						|
    //
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
ON_ERROR:
 | 
						|
 | 
						|
  if (ChildSaSession->SaData != NULL) {
 | 
						|
    FreePool (ChildSaSession->SaData);
 | 
						|
  }
 | 
						|
 | 
						|
  if (ChildSaSession->SessionCommon.TimeoutEvent != NULL) {
 | 
						|
    gBS->CloseEvent (ChildSaSession->SessionCommon.TimeoutEvent);
 | 
						|
  }
 | 
						|
 | 
						|
  if (IkePacket != NULL) {
 | 
						|
    IkePacketFree (IkePacket);
 | 
						|
  }
 | 
						|
 | 
						|
  Ikev2ChildSaSessionFree (ChildSaSession);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  It is general interface to start the Information Exchange.
 | 
						|
 | 
						|
  There are three situations which will invoke this function. First, deliver a Delete Information
 | 
						|
  to delete the IKE SA if the input Context is NULL and the state of related IkeSaSeesion's is on 
 | 
						|
  deleting.Second, deliver a Notify Information without the contents if the input Context is NULL. 
 | 
						|
  Third, deliver a Notify Information if the input Context is not NULL.
 | 
						|
 | 
						|
  @param[in] IkeSaSession  Pointer to IKEv2_SA_SESSION related to this operation.
 | 
						|
  @param[in] Context       Data passed by caller.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          The operation is successful.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated.
 | 
						|
  @retval EFI_UNSUPPORTED      The condition is not support yet.
 | 
						|
  @return Otherwise            The operation is failed.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ikev2NegotiateInfo (
 | 
						|
  IN UINT8           *IkeSaSession,
 | 
						|
  IN UINT8           *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  IKEV2_SA_SESSION          *Ikev2SaSession;
 | 
						|
  IKEV2_CHILD_SA_SESSION    *ChildSaSession;
 | 
						|
  IKEV2_SESSION_COMMON      *SaCommon;
 | 
						|
  IKE_PACKET                *IkePacket;
 | 
						|
  IKE_UDP_SERVICE           *UdpService;
 | 
						|
  LIST_ENTRY                *Entry;
 | 
						|
  LIST_ENTRY                *NextEntry;
 | 
						|
 | 
						|
  Ikev2SaSession = (IKEV2_SA_SESSION *) IkeSaSession;
 | 
						|
  UdpService     = Ikev2SaSession->SessionCommon.UdpService;
 | 
						|
  SaCommon       = &Ikev2SaSession->SessionCommon;
 | 
						|
  IkePacket      = NULL;
 | 
						|
  Status         = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  // Delete the IKE SA.
 | 
						|
  //
 | 
						|
  if (Ikev2SaSession->SessionCommon.State == IkeStateSaDeleting && Context == NULL) {
 | 
						|
 | 
						|
    //
 | 
						|
    // The IKE SA Session should be initiator if it triggers the deleting.
 | 
						|
    //
 | 
						|
    Ikev2SaSession->SessionCommon.IsInitiator = TRUE;
 | 
						|
 | 
						|
    //
 | 
						|
    // Generate Information Packet which contains the Delete Payload.
 | 
						|
    //
 | 
						|
    IkePacket = mIkev2Info.Generator ((UINT8 *) Ikev2SaSession, NULL);
 | 
						|
    if (IkePacket == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto ON_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Send out the Packet
 | 
						|
    //
 | 
						|
    Status = Ikev2SendIkePacket (UdpService, (UINT8 *) SaCommon, IkePacket, 0);
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto ON_ERROR;
 | 
						|
    }
 | 
						|
  } else if (!IsListEmpty (&Ikev2SaSession->DeleteSaList)) {
 | 
						|
    //
 | 
						|
    // Iterate all Deleting Child SAs.
 | 
						|
    //
 | 
						|
    NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Ikev2SaSession->DeleteSaList) {
 | 
						|
      ChildSaSession                      = IKEV2_CHILD_SA_SESSION_BY_DEL_SA (Entry);
 | 
						|
      ChildSaSession->SessionCommon.State = IkeStateSaDeleting;
 | 
						|
 | 
						|
      //
 | 
						|
      // Generate Information Packet which contains the Child SA Delete Payload.
 | 
						|
      //
 | 
						|
      IkePacket = mIkev2Info.Generator ((UINT8 *) ChildSaSession, NULL);
 | 
						|
      if (IkePacket == NULL) {
 | 
						|
        Status = EFI_OUT_OF_RESOURCES;
 | 
						|
        goto ON_ERROR;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Send out the Packet
 | 
						|
      //
 | 
						|
      Status = Ikev2SendIkePacket (UdpService, (UINT8 *) &ChildSaSession->SessionCommon, IkePacket, 0);
 | 
						|
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        goto ON_ERROR;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }  else if (Context == NULL) {
 | 
						|
    //
 | 
						|
    // TODO: Deliver null notification message.
 | 
						|
    //
 | 
						|
  }  else if (Context != NULL) {
 | 
						|
    //
 | 
						|
    // TODO: Send out the Information Exchange which contains the Notify Payload.
 | 
						|
    //
 | 
						|
  }
 | 
						|
ON_ERROR:
 | 
						|
  if (IkePacket != NULL) {
 | 
						|
    IkePacketFree (IkePacket);
 | 
						|
  }
 | 
						|
  return Status;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The general interface when received a IKEv2 packet for the IKE SA establishing.
 | 
						|
 | 
						|
  This function first find the related IKE SA Session according to the IKE packet's 
 | 
						|
  remote IP. Then call the corresponding function to handle this IKE packet according
 | 
						|
  to the related IKE SA Session's State. 
 | 
						|
 | 
						|
  @param[in] UdpService    Pointer of related UDP Service.
 | 
						|
  @param[in] IkePacket     Data passed by caller.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
Ikev2HandleSa (
 | 
						|
  IN IKE_UDP_SERVICE     *UdpService,
 | 
						|
  IN IKE_PACKET          *IkePacket
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  IKEV2_SA_SESSION        *IkeSaSession;
 | 
						|
  IKEV2_CHILD_SA_SESSION  *ChildSaSession;
 | 
						|
  IKEV2_SESSION_COMMON    *IkeSaCommon;
 | 
						|
  IKEV2_SESSION_COMMON    *ChildSaCommon;
 | 
						|
  IKEV2_PACKET_HANDLER    Handler;
 | 
						|
  IKE_PACKET              *Reply;
 | 
						|
  IPSEC_PAD_ENTRY         *PadEntry;
 | 
						|
  IPSEC_PRIVATE_DATA      *Private;
 | 
						|
  BOOLEAN                 IsNewSession;
 | 
						|
 | 
						|
  Private = (UdpService->IpVersion == IP_VERSION_4) ? 
 | 
						|
             IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) :
 | 
						|
             IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);
 | 
						|
 | 
						|
  ChildSaSession = NULL;
 | 
						|
  ChildSaCommon  = NULL;
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Lookup the remote ip address in the processing IKE SA session list.
 | 
						|
  //
 | 
						|
  IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2SessionList, &IkePacket->RemotePeerIp);
 | 
						|
  IsNewSession = FALSE;
 | 
						|
 | 
						|
  if (IkeSaSession == NULL) {
 | 
						|
    //
 | 
						|
    // Lookup the remote ip address in the pad.
 | 
						|
    //
 | 
						|
    PadEntry = IpSecLookupPadEntry (UdpService->IpVersion, &IkePacket->RemotePeerIp);
 | 
						|
    if (PadEntry == NULL) {
 | 
						|
      //
 | 
						|
      // Drop the packet if no pad entry matched, this is the request from RFC 4301.
 | 
						|
      //
 | 
						|
      return ;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Create a new IkeSaSession and initiate the common parameters.
 | 
						|
    //
 | 
						|
    IkeSaSession             = Ikev2SaSessionAlloc (Private, UdpService);
 | 
						|
    if (IkeSaSession == NULL) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    IkeSaSession->Pad        = PadEntry;
 | 
						|
    IkeSaCommon              = &IkeSaSession->SessionCommon;
 | 
						|
    IkeSaCommon->IsInitiator = FALSE;
 | 
						|
    IkeSaCommon->State       = IkeStateInit;
 | 
						|
 | 
						|
    IKEV2_DUMP_STATE (IkeSaCommon->State, IkeStateInit);
 | 
						|
 | 
						|
    CopyMem (
 | 
						|
      &IkeSaCommon->RemotePeerIp,
 | 
						|
      &IkePacket->RemotePeerIp,
 | 
						|
      sizeof (EFI_IP_ADDRESS)
 | 
						|
      );
 | 
						|
 | 
						|
    CopyMem (
 | 
						|
      &IkeSaCommon->LocalPeerIp,
 | 
						|
      &UdpService->DefaultAddress,
 | 
						|
      sizeof (EFI_IP_ADDRESS)
 | 
						|
      );
 | 
						|
    
 | 
						|
    IsNewSession = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Validate the IKE packet header.
 | 
						|
  //
 | 
						|
  Status = Ikev2ValidateHeader (IkeSaSession, IkePacket->Header);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // Drop the packet if invalid IKE header.
 | 
						|
    //
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Decode all the payloads in the IKE packet.
 | 
						|
  //
 | 
						|
  IkeSaCommon = &IkeSaSession->SessionCommon;
 | 
						|
  Status      = Ikev2DecodePacket (IkeSaCommon, IkePacket, IkeSessionTypeIkeSa);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Try to reate the first ChildSa Session of that IkeSaSession.
 | 
						|
  // If the IkeSaSession is responder, here will create the first ChildSaSession.
 | 
						|
  //
 | 
						|
  if (IkeSaCommon->State == IkeStateAuth && IsListEmpty(&IkeSaSession->ChildSaSessionList)) {
 | 
						|
    //
 | 
						|
    // Generate a piggyback child SA in IKE_STATE_AUTH state.
 | 
						|
    //
 | 
						|
    ASSERT (IsListEmpty (&IkeSaSession->ChildSaSessionList) &&
 | 
						|
            IsListEmpty (&IkeSaSession->ChildSaEstablishSessionList));
 | 
						|
 | 
						|
    ChildSaSession = Ikev2ChildSaSessionCreate (IkeSaSession, UdpService);
 | 
						|
    ChildSaCommon  = &ChildSaSession->SessionCommon;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Parse the IKE request packet according to the auth method and current state.
 | 
						|
  //
 | 
						|
  Handler = mIkev2Initial[IkeSaSession->Pad->Data->AuthMethod][IkeSaCommon->State];
 | 
						|
  Status  = Handler.Parser ((UINT8 *)IkeSaSession, IkePacket);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Try to reate the first ChildSa Session of that IkeSaSession.
 | 
						|
  // If the IkeSaSession is initiator, here will create the first ChildSaSession.
 | 
						|
  //
 | 
						|
  if (IkeSaCommon->State == IkeStateAuth && IsListEmpty(&IkeSaSession->ChildSaSessionList)) {
 | 
						|
    //
 | 
						|
    // Generate a piggyback child SA in IKE_STATE_AUTH state.
 | 
						|
    //
 | 
						|
    ASSERT (IsListEmpty (&IkeSaSession->ChildSaSessionList) && 
 | 
						|
            IsListEmpty (&IkeSaSession->ChildSaEstablishSessionList));
 | 
						|
    
 | 
						|
    ChildSaSession = Ikev2ChildSaSessionCreate (IkeSaSession, UdpService);
 | 
						|
    ChildSaCommon  = &ChildSaSession->SessionCommon;
 | 
						|
 | 
						|
    //
 | 
						|
    // Initialize the SA data for Child SA.
 | 
						|
    //    
 | 
						|
    ChildSaSession->SaData = Ikev2InitializeSaData (ChildSaCommon);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Generate the IKE response packet and send it out if not established.
 | 
						|
  //
 | 
						|
  if (IkeSaCommon->State != IkeStateIkeSaEstablished) {
 | 
						|
    Handler = mIkev2Initial[IkeSaSession->Pad->Data->AuthMethod][IkeSaCommon->State];
 | 
						|
    Reply   = Handler.Generator ((UINT8 *) IkeSaSession, NULL);
 | 
						|
    if (Reply == NULL) {
 | 
						|
      goto ON_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = Ikev2SendIkePacket (UdpService, (UINT8 *) IkeSaCommon, Reply, 0);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto ON_ERROR;
 | 
						|
    }
 | 
						|
    if (!IkeSaCommon->IsInitiator) {
 | 
						|
      IkeSaCommon->State ++;
 | 
						|
      IKEV2_DUMP_STATE (IkeSaCommon->State - 1, IkeSaCommon->State);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Insert the new IkeSaSession into the Private processing IkeSaSession List.
 | 
						|
  //
 | 
						|
  if (IsNewSession) {
 | 
						|
    Ikev2SaSessionInsert (&Private->Ikev2SessionList, IkeSaSession, &IkePacket->RemotePeerIp);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Register the IkeSaSession and remove it from processing list.
 | 
						|
  //
 | 
						|
  if (IkeSaCommon->State == IkeStateIkeSaEstablished) {
 | 
						|
 | 
						|
    //
 | 
						|
    // Remove the Established IKE SA Session from the IKE SA Session Negotiating list
 | 
						|
    // and insert it into IKE SA Session Established list.
 | 
						|
    //
 | 
						|
    Ikev2SaSessionRemove (&Private->Ikev2SessionList, &IkePacket->RemotePeerIp);
 | 
						|
    Ikev2SaSessionReg (IkeSaSession, Private);
 | 
						|
 | 
						|
    //
 | 
						|
    // Remove the Established Child SA Session from the IkeSaSession->ChildSaSessionList
 | 
						|
    // ,insert it into IkeSaSession->ChildSaEstablishSessionList and save this Child SA 
 | 
						|
    // into SAD.
 | 
						|
    //
 | 
						|
    ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (IkeSaSession->ChildSaSessionList.BackLink);
 | 
						|
    Ikev2ChildSaSessionRemove (
 | 
						|
      &IkeSaSession->ChildSaSessionList,
 | 
						|
      ChildSaSession->LocalPeerSpi,
 | 
						|
      IKEV2_ESTABLISHING_CHILDSA_LIST
 | 
						|
      );
 | 
						|
    Ikev2ChildSaSessionReg (ChildSaSession, Private);
 | 
						|
  }
 | 
						|
 | 
						|
  return ;
 | 
						|
 | 
						|
ON_ERROR:
 | 
						|
  if (ChildSaSession != NULL) {
 | 
						|
    //
 | 
						|
    // Remove the ChildSa from the list (Established list or Negotiating list).
 | 
						|
    //
 | 
						|
    RemoveEntryList (&ChildSaSession->ByIkeSa);
 | 
						|
    Ikev2ChildSaSessionFree (ChildSaSession);
 | 
						|
  }
 | 
						|
 | 
						|
  if (IsNewSession && IkeSaSession != NULL) {
 | 
						|
    //
 | 
						|
    // Remove the IkeSa from the list (Established list or Negotiating list).
 | 
						|
    //
 | 
						|
    if ((&IkeSaSession->BySessionTable)->ForwardLink != NULL &&
 | 
						|
        !IsListEmpty (&IkeSaSession->BySessionTable
 | 
						|
       )){
 | 
						|
      RemoveEntryList (&IkeSaSession->BySessionTable);
 | 
						|
    }
 | 
						|
    Ikev2SaSessionFree (IkeSaSession);
 | 
						|
  }
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  The general interface when received a IKEv2 packet for the IKE Child SA establishing 
 | 
						|
  or IKE SA/CHILD SA rekeying.
 | 
						|
 | 
						|
  This function first find the related IKE SA Session according to the IKE packet's 
 | 
						|
  remote IP. Then call the corresponding function to handle this IKE packet according
 | 
						|
  to the related IKE Child Session's State. 
 | 
						|
 | 
						|
  @param[in] UdpService    Pointer of related UDP Service.
 | 
						|
  @param[in] IkePacket     Data passed by caller.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
Ikev2HandleChildSa (
 | 
						|
  IN IKE_UDP_SERVICE  *UdpService,
 | 
						|
  IN IKE_PACKET       *IkePacket
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
  IKEV2_SA_SESSION                 *IkeSaSession;
 | 
						|
  IKEV2_CREATE_CHILD_REQUEST_TYPE  RequestType;
 | 
						|
  IKE_PACKET                       *Reply;
 | 
						|
  IPSEC_PRIVATE_DATA               *Private;
 | 
						|
  
 | 
						|
  Private = (UdpService->IpVersion == IP_VERSION_4) ? 
 | 
						|
             IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) :
 | 
						|
             IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);
 | 
						|
 | 
						|
  Reply   = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Lookup the remote ip address in the processing IKE SA session list.
 | 
						|
  //
 | 
						|
  IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2EstablishedList, &IkePacket->RemotePeerIp);
 | 
						|
 | 
						|
  if (IkeSaSession == NULL) {
 | 
						|
    //
 | 
						|
    // Drop the packet if no IKE SA associated.
 | 
						|
    //
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Validate the IKE packet header.
 | 
						|
  //
 | 
						|
  if (!Ikev2ValidateHeader (IkeSaSession, IkePacket->Header)) {
 | 
						|
    //
 | 
						|
    // Drop the packet if invalid IKE header.
 | 
						|
    //
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Decode all the payloads in the IKE packet.
 | 
						|
  //
 | 
						|
  Status = Ikev2DecodePacket (&IkeSaSession->SessionCommon, IkePacket, IkeSessionTypeIkeSa);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the request type: CreateChildSa/RekeyChildSa/RekeyIkeSa.
 | 
						|
  //  
 | 
						|
  RequestType = Ikev2ChildExchangeRequestType (IkePacket);
 | 
						|
 | 
						|
  switch (RequestType) {
 | 
						|
  case IkeRequestTypeCreateChildSa:
 | 
						|
  case IkeRequestTypeRekeyChildSa: 
 | 
						|
  case IkeRequestTypeRekeyIkeSa: 
 | 
						|
    //
 | 
						|
    // Parse the IKE request packet. Not support CREATE_CHILD_SA exchange yet, so
 | 
						|
    // only EFI_UNSUPPORTED will be returned and that will trigger a reply with a 
 | 
						|
    // Notify payload of type NO_ADDITIONAL_SAS.
 | 
						|
    //
 | 
						|
    Status = mIkev2CreateChild.Parser ((UINT8 *) IkeSaSession, IkePacket);
 | 
						|
    if (EFI_ERROR (Status)) {     
 | 
						|
      goto ON_REPLY;
 | 
						|
    }
 | 
						|
 | 
						|
  default:
 | 
						|
    //
 | 
						|
    // No support.
 | 
						|
    //
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
  
 | 
						|
ON_REPLY:
 | 
						|
  //
 | 
						|
  // Generate the reply packet if needed and send it out.
 | 
						|
  //
 | 
						|
  if (IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) {
 | 
						|
    Reply = mIkev2CreateChild.Generator ((UINT8 *) IkeSaSession, &IkePacket->Header->MessageId);
 | 
						|
    if (Reply != NULL) {
 | 
						|
      Status = Ikev2SendIkePacket (UdpService, (UINT8 *) &(IkeSaSession->SessionCommon), Reply, 0);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        //
 | 
						|
        //  Delete Reply payload.
 | 
						|
        //
 | 
						|
        if (Reply != NULL) {
 | 
						|
          IkePacketFree (Reply);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }  
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  It is general interface to handle IKEv2 information Exchange.
 | 
						|
  
 | 
						|
  @param[in] UdpService  Point to IKE UPD Service related to this information exchange.  
 | 
						|
  @param[in] IkePacket   The IKE packet to be parsed.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
Ikev2HandleInfo (
 | 
						|
  IN IKE_UDP_SERVICE  *UdpService,
 | 
						|
  IN IKE_PACKET       *IkePacket
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  IKEV2_SESSION_COMMON    *SessionCommon;
 | 
						|
  IKEV2_SA_SESSION        *IkeSaSession;
 | 
						|
  IPSEC_PRIVATE_DATA      *Private;
 | 
						|
 | 
						|
  Private = (UdpService->IpVersion == IP_VERSION_4) ? 
 | 
						|
             IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) : 
 | 
						|
             IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);
 | 
						|
 | 
						|
  //
 | 
						|
  // Lookup the remote ip address in the processing IKE SA session list.
 | 
						|
  //
 | 
						|
  IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2EstablishedList, &IkePacket->RemotePeerIp);
 | 
						|
  
 | 
						|
  if (IkeSaSession == NULL) {
 | 
						|
    //
 | 
						|
    // Drop the packet if no IKE SA associated.
 | 
						|
    //
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Validate the IKE packet header.
 | 
						|
  //
 | 
						|
  if (!Ikev2ValidateHeader (IkeSaSession, IkePacket->Header)) {
 | 
						|
  
 | 
						|
    //
 | 
						|
    // Drop the packet if invalid IKE header.
 | 
						|
    //
 | 
						|
    return;
 | 
						|
  }  
 | 
						|
 | 
						|
  SessionCommon = &IkeSaSession->SessionCommon;
 | 
						|
 | 
						|
  //
 | 
						|
  // Decode all the payloads in the IKE packet.
 | 
						|
  //
 | 
						|
  Status = Ikev2DecodePacket (SessionCommon, IkePacket, IkeSessionTypeIkeSa);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = mIkev2Info.Parser ((UINT8 *)IkeSaSession, IkePacket);
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // Drop the packet if fail to parse.
 | 
						|
    //
 | 
						|
    return;
 | 
						|
  }    
 | 
						|
}
 | 
						|
 | 
						|
IKE_EXCHANGE_INTERFACE  mIkev1Exchange = {
 | 
						|
  1,
 | 
						|
  NULL, //Ikev1NegotiateSa
 | 
						|
  NULL, //Ikev1NegotiateChildSa
 | 
						|
  NULL,
 | 
						|
  NULL, //Ikev1HandleSa,
 | 
						|
  NULL, //Ikev1HandleChildSa
 | 
						|
  NULL, //Ikev1HandleInfo
 | 
						|
};
 | 
						|
 | 
						|
IKE_EXCHANGE_INTERFACE  mIkev2Exchange = {
 | 
						|
  2,
 | 
						|
  Ikev2NegotiateSa,
 | 
						|
  Ikev2NegotiateChildSa,
 | 
						|
  Ikev2NegotiateInfo,
 | 
						|
  Ikev2HandleSa,
 | 
						|
  Ikev2HandleChildSa,
 | 
						|
  Ikev2HandleInfo
 | 
						|
};
 | 
						|
 |