summaryrefslogtreecommitdiff
path: root/NetworkPkg/IpSecDxe/Ikev2/Info.c
diff options
context:
space:
mode:
Diffstat (limited to 'NetworkPkg/IpSecDxe/Ikev2/Info.c')
-rw-r--r--NetworkPkg/IpSecDxe/Ikev2/Info.c401
1 files changed, 401 insertions, 0 deletions
diff --git a/NetworkPkg/IpSecDxe/Ikev2/Info.c b/NetworkPkg/IpSecDxe/Ikev2/Info.c
new file mode 100644
index 0000000000..d297564f11
--- /dev/null
+++ b/NetworkPkg/IpSecDxe/Ikev2/Info.c
@@ -0,0 +1,401 @@
+/** @file
+ The Implementations for Information Exchange.
+
+ 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 "IpSecConfigImpl.h"
+
+/**
+ Generate Information Packet.
+
+ The information Packet may contain one Delete Payload, or Notify Payload, which
+ dependes on the Context's parameters.
+
+ @param[in] SaSession Pointer to IKE SA Session or Child SA Session which is
+ related to the information Exchange.
+ @param[in] Context The Data passed from the caller. If the Context is not NULL
+ it should contain the information for Notification Data.
+
+ @retval Pointer of IKE_PACKET generated.
+
+**/
+IKE_PACKET *
+Ikev2InfoGenerator (
+ IN UINT8 *SaSession,
+ IN VOID *Context
+ )
+{
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ IKE_PACKET *IkePacket;
+ IKE_PAYLOAD *IkePayload;
+ IKEV2_INFO_EXCHANGE_CONTEXT *InfoContext;
+
+ InfoContext = NULL;
+ IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
+ IkePacket = IkePacketAlloc ();
+ ASSERT (IkePacket != NULL);
+
+ //
+ // Fill IkePacket Header.
+ //
+ IkePacket->Header->ExchangeType = IKEV2_EXCHANGE_TYPE_INFO;
+ IkePacket->Header->Version = (UINT8) (2 << 4);
+
+ if (Context != NULL) {
+ InfoContext = (IKEV2_INFO_EXCHANGE_CONTEXT *) Context;
+ }
+
+ //
+ // For Liveness Check
+ //
+ if (InfoContext != NULL &&
+ (InfoContext->InfoType == Ikev2InfoLiveCheck || InfoContext->InfoType == Ikev2InfoNotify)
+ ) {
+ IkePacket->Header->MessageId = InfoContext->MessageId;
+ IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
+ IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
+ IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_NONE;
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
+ //
+ // TODO: add Notify Payload for Notification Information.
+ //
+ return IkePacket;
+ }
+
+ //
+ // For delete SAs
+ //
+ if (IkeSaSession->SessionCommon.IkeSessionType == IkeSessionTypeIkeSa) {
+
+ IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
+ IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
+
+ //
+ // If the information message is response message,the MessageId should
+ // be same as the request MessageId which passed through the Context.
+ //
+ if (InfoContext != NULL) {
+ IkePacket->Header->MessageId = InfoContext->MessageId;
+ } else {
+ IkePacket->Header->MessageId = IkeSaSession->MessageId;
+ Ikev2SaSessionIncreaseMessageId (IkeSaSession);
+ }
+ //
+ // If the state is on deleting generate a Delete Payload for it.
+ //
+ if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting ) {
+ IkePayload = Ikev2GenerateDeletePayload (
+ IkeSaSession,
+ IKEV2_PAYLOAD_TYPE_NONE,
+ 0,
+ 0,
+ NULL
+ );
+ if (IkePayload == NULL) {
+ goto ERROR_EXIT;
+ }
+ //
+ // Fill the next payload in IkePacket's Header.
+ //
+ IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_DELETE;
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);
+ IkePacket->Private = IkeSaSession->SessionCommon.Private;
+ IkePacket->Spi = 0;
+ IkePacket->IsDeleteInfo = TRUE;
+
+ } else if (Context != NULL) {
+ //
+ // TODO: If contest is not NULL Generate a Notify Payload.
+ //
+ } else {
+ //
+ // The input parameter is not correct.
+ //
+ goto ERROR_EXIT;
+ }
+ } else {
+ //
+ // Delete the Child SA Information Exchagne
+ //
+ ChildSaSession = (IKEV2_CHILD_SA_SESSION *) SaSession;
+ IkeSaSession = ChildSaSession->IkeSaSession;
+ IkePacket->Header->InitiatorCookie = ChildSaSession->IkeSaSession->InitiatorCookie;
+ IkePacket->Header->ResponderCookie = ChildSaSession->IkeSaSession->ResponderCookie;
+
+ //
+ // If the information message is response message,the MessageId should
+ // be same as the request MessageId which passed through the Context.
+ //
+ if (InfoContext != NULL && InfoContext->MessageId != 0) {
+ IkePacket->Header->MessageId = InfoContext->MessageId;
+ } else {
+ IkePacket->Header->MessageId = ChildSaSession->IkeSaSession->MessageId;
+ Ikev2SaSessionIncreaseMessageId (IkeSaSession);
+ }
+
+ IkePayload = Ikev2GenerateDeletePayload (
+ ChildSaSession->IkeSaSession,
+ IKEV2_PAYLOAD_TYPE_DELETE,
+ 4,
+ 1,
+ (UINT8 *)&ChildSaSession->LocalPeerSpi
+ );
+ if (IkePayload == NULL) {
+ goto ERROR_EXIT;
+ }
+ //
+ // Fill the Next Payload in IkePacket's Header.
+ //
+ IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_DELETE;
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);
+
+ IkePacket->Private = IkeSaSession->SessionCommon.Private;
+ IkePacket->Spi = ChildSaSession->LocalPeerSpi;
+ IkePacket->IsDeleteInfo = TRUE;
+
+ if (!ChildSaSession->SessionCommon.IsInitiator) {
+ //
+ // If responder, use the MessageId fromt the initiator.
+ //
+ IkePacket->Header->MessageId = ChildSaSession->MessageId;
+ }
+
+ //
+ // Change the IsOnDeleting Flag
+ //
+ ChildSaSession->SessionCommon.IsOnDeleting = TRUE;
+ }
+
+ if (InfoContext == NULL) {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;
+ } else {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
+ }
+ return IkePacket;
+
+ERROR_EXIT:
+ if (IkePacket != NULL) {
+ FreePool (IkePacket);
+ }
+ return NULL;
+
+}
+
+/**
+ Parse the Info Exchange.
+
+ @param[in] SaSession Pointer to IKEV2_SA_SESSION.
+ @param[in] IkePacket Pointer to IkePacket related to the Information Exchange.
+
+ @retval EFI_SUCCESS The operation finised successed.
+
+**/
+EFI_STATUS
+Ikev2InfoParser (
+ IN UINT8 *SaSession,
+ IN IKE_PACKET *IkePacket
+ )
+{
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKE_PAYLOAD *NotifyPayload;
+ IKE_PAYLOAD *DeletePayload;
+ IKE_PAYLOAD *IkePayload;
+ IKEV2_DELETE *Delete;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *ListEntry;
+ UINT8 Index;
+ UINT32 Spi;
+ UINT8 *SpiBuffer;
+ IPSEC_PRIVATE_DATA *Private;
+ UINT8 Value;
+ EFI_STATUS Status;
+ IKE_PACKET *RespondPacket;
+
+ IKEV2_INFO_EXCHANGE_CONTEXT Context;
+
+ IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
+
+ NotifyPayload = NULL;
+ DeletePayload = NULL;
+ Private = NULL;
+ RespondPacket = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // For Liveness Check
+ //
+ if (IkePacket->Header->NextPayload == IKEV2_PAYLOAD_TYPE_NONE &&
+ (IkePacket->PayloadTotalSize == 0)
+ ) {
+ if (IkePacket->Header->Flags == IKE_HEADER_FLAGS_INIT) {
+ //
+ // If it is Liveness check request, reply it.
+ //
+ Context.InfoType = Ikev2InfoLiveCheck;
+ Context.MessageId = IkePacket->Header->MessageId;
+ RespondPacket = Ikev2InfoGenerator ((UINT8 *)IkeSaSession, &Context);
+
+ if (RespondPacket == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ return Status;
+ }
+ Status = Ikev2SendIkePacket (
+ IkeSaSession->SessionCommon.UdpService,
+ (UINT8 *)(&IkeSaSession->SessionCommon),
+ RespondPacket,
+ 0
+ );
+
+ } else {
+ //
+ // Todo: verify the liveness check response packet.
+ //
+ }
+ return Status;
+ }
+
+ //
+ // For SA Delete
+ //
+ NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
+
+ //
+ // Iterate payloads to find the Delete/Notify Payload.
+ //
+ IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
+
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_DELETE) {
+ DeletePayload = IkePayload;
+ Delete = (IKEV2_DELETE *)DeletePayload->PayloadBuf;
+
+ if (Delete->SpiSize == 0) {
+ //
+ // Delete IKE SA.
+ //
+ if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting) {
+ RemoveEntryList (&IkeSaSession->BySessionTable);
+ Ikev2SaSessionFree (IkeSaSession);
+ //
+ // Checking the Private status.
+ //
+ //
+ // when all IKE SAs were disabled by calling "IPsecConfig -disable", the IPsec
+ // status should be changed.
+ //
+ Private = IkeSaSession->SessionCommon.Private;
+ if (Private != NULL && Private->IsIPsecDisabling) {
+ //
+ // After all IKE SAs were deleted, set the IPSEC_STATUS_DISABLED value in
+ // IPsec status variable.
+ //
+ if (IsListEmpty (&Private->Ikev1EstablishedList) &&
+ (IsListEmpty (&Private->Ikev2EstablishedList))
+ ) {
+ Value = IPSEC_STATUS_DISABLED;
+ Status = gRT->SetVariable (
+ IPSECCONFIG_STATUS_NAME,
+ &gEfiIpSecConfigProtocolGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (Value),
+ &Value
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Set the DisabledFlag in Private data.
+ //
+ Private->IpSec.DisabledFlag = TRUE;
+ Private->IsIPsecDisabling = FALSE;
+ }
+ }
+ }
+ } else {
+ IkeSaSession->SessionCommon.State = IkeStateSaDeleting;
+ Context.InfoType = Ikev2InfoDelete;
+ Context.MessageId = IkePacket->Header->MessageId;
+
+ RespondPacket = Ikev2InfoGenerator ((UINT8 *)IkeSaSession, &Context);
+ if (RespondPacket == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ return Status;
+ }
+ Status = Ikev2SendIkePacket (
+ IkeSaSession->SessionCommon.UdpService,
+ (UINT8 *)(&IkeSaSession->SessionCommon),
+ RespondPacket,
+ 0
+ );
+ }
+ } else if (Delete->SpiSize == 4) {
+ //
+ // Move the Child SAs to DeleteList
+ //
+ SpiBuffer = (UINT8 *)(Delete + 1);
+ for (Index = 0; Index < Delete->NumSpis; Index++) {
+ Spi = ReadUnaligned32 ((UINT32 *)SpiBuffer);
+ for (ListEntry = IkeSaSession->ChildSaEstablishSessionList.ForwardLink;
+ ListEntry != &IkeSaSession->ChildSaEstablishSessionList;
+ ) {
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (ListEntry);
+ ListEntry = ListEntry->ForwardLink;
+
+ if (ChildSaSession->RemotePeerSpi == HTONL(Spi)) {
+ if (ChildSaSession->SessionCommon.State != IkeStateSaDeleting) {
+
+ //
+ // Insert the ChildSa Session into Delete List.
+ //
+ InsertTailList (&IkeSaSession->DeleteSaList, &ChildSaSession->ByDelete);
+ ChildSaSession->SessionCommon.State = IkeStateSaDeleting;
+ ChildSaSession->SessionCommon.IsInitiator = FALSE;
+ ChildSaSession->MessageId = IkePacket->Header->MessageId;
+
+ Context.InfoType = Ikev2InfoDelete;
+ Context.MessageId = IkePacket->Header->MessageId;
+
+ RespondPacket = Ikev2InfoGenerator ((UINT8 *)ChildSaSession, &Context);
+ if (RespondPacket == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ return Status;
+ }
+ Status = Ikev2SendIkePacket (
+ ChildSaSession->SessionCommon.UdpService,
+ (UINT8 *)(&ChildSaSession->SessionCommon),
+ RespondPacket,
+ 0
+ );
+ } else {
+ //
+ // Delete the Child SA.
+ //
+ Ikev2ChildSaSilentDelete (IkeSaSession, Spi);
+ RemoveEntryList (&ChildSaSession->ByDelete);
+ }
+ }
+ }
+ SpiBuffer = SpiBuffer + sizeof (Spi);
+ }
+ }
+ }
+ }
+
+ return Status;
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED IKEV2_PACKET_HANDLER mIkev2Info = {
+ Ikev2InfoParser,
+ Ikev2InfoGenerator
+};