summaryrefslogtreecommitdiff
path: root/NetworkPkg/IpSecDxe/Ikev2/Exchange.c
diff options
context:
space:
mode:
Diffstat (limited to 'NetworkPkg/IpSecDxe/Ikev2/Exchange.c')
-rw-r--r--NetworkPkg/IpSecDxe/Ikev2/Exchange.c803
1 files changed, 803 insertions, 0 deletions
diff --git a/NetworkPkg/IpSecDxe/Ikev2/Exchange.c b/NetworkPkg/IpSecDxe/Ikev2/Exchange.c
new file mode 100644
index 0000000000..94bdd86d90
--- /dev/null
+++ b/NetworkPkg/IpSecDxe/Ikev2/Exchange.c
@@ -0,0 +1,803 @@
+/** @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
+};
+