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
 | |
| };
 | |
| 
 |