--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/networksecurity/ipsec/ipsec6/src/key_sa.cpp Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,774 @@
+// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// key_sa.cpp - IPv6/IPv4 IPSEC PFKEY interface to SADB
+// CProtocolKey methods that interface with the Security AssociationDatabase (SAD)
+//
+
+
+
+/**
+ @file key_sa.cpp
+*/
+#include "ipaddress.h"
+#include "ipsec.h"
+#include "sadb.h"
+#include "pfkey.h"
+#include "pfkeymsg.h"
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+#include "spdb.h"
+#endif // SYMBIAN_IPSEC_VOIP_SUPPORT
+// There should be some file just defining these numbers and nothing else... -- msa
+const TUint KProtocolInetEsp = 50;
+const TUint KProtocolInetAh = 51;
+const TUint KProtocolInetIpip = 4;
+
+class TAcquireMessage : public TPfkeyMessage
+ /**
+ * An internal, transient representation of the ACQUIRE message.
+ *
+ * The base TPfkeyMessage contains const pointers to SADB structures
+ * defined in pfkeyv2.h. TAcquireMessage extends TPfkeyMessage in such
+ * way that the storage required for these base structures are allocated
+ * internally here(for those extensions that are needed by the ACQUIRE)
+ */
+ {
+ friend class CProtocolKey;
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ TAcquireMessage(const CSecurityAssoc &aSA, const CPropList *aPropList, TUint8 aTunnel, const RTrafficSelectorSet &aTS);
+#else
+ TAcquireMessage(const CSecurityAssoc &aSA, const TSecurityAssocSpec &aSpec, TUint8 aTunnel, const RTrafficSelectorSet &aTS);
+#endif // SYMBIAN_IPSEC_VOIP_SUPPORT
+ T_sadb_msg i_base; //< Base Message Header
+ T_sadb_address i_src_addr; //< Source Address Extension
+ T_sadb_address i_dst_addr; //< Destination Address Extension
+ T_sadb_address i_proxy_addr; //< Proxy Address Extension
+ T_sadb_ident i_src_ident; //< Source Identity Extension
+ T_sadb_ident i_dst_ident; //< Destination Identity Extension
+ T_sadb_ident i_src_endpoint; //< Source Endpoint Extension
+ T_sadb_ident i_dst_endpoint; //< Destination Endpoint Extension
+ T_sadb_sens i_sens; //< Sensitivity Extension
+ T_sadb_ts i_ts; //< Traffic Selector
+ T_sadb_prop i_prop; //< Proposal Extension
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ struct sadb_comb i_comb[MAX_PROPOSALS_PER_SA]; //< Proposed Parameter combination(s) (Only one generated for now)
+#else
+ struct sadb_comb i_comb[1]; //< Proposed Parameter combination(s) (Only one generated for now)
+#endif // SYMBIAN_IPSEC_VOIP_SUPPORT
+ };
+
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+TAcquireMessage::TAcquireMessage(const CSecurityAssoc &aSA, const CPropList *aPropList, TUint8 aTunnel, const RTrafficSelectorSet &aTs)
+#else
+TAcquireMessage::TAcquireMessage(const CSecurityAssoc &aSA, const TSecurityAssocSpec &aSpec, TUint8 aTunnel, const RTrafficSelectorSet &aTs)
+#endif // SYMBIAN_IPSEC_VOIP_SUPPORT
+:
+ i_base((TUint8)SADB_ACQUIRE, aSA.iType, aSA.iSendSeq),
+ i_src_addr(SADB_EXT_ADDRESS_SRC, aSA.iInfo.iProtocol),
+ i_dst_addr(SADB_EXT_ADDRESS_DST, aSA.iInfo.iProtocol),
+ i_proxy_addr(SADB_EXT_ADDRESS_PROXY, aSA.iInfo.iProtocol),
+ i_src_ident(SADB_EXT_IDENTITY_SRC),
+ i_dst_ident(SADB_EXT_IDENTITY_DST),
+ i_src_endpoint(SADB_X_EXT_ENDPOINT_SRC),
+ i_dst_endpoint(SADB_X_EXT_ENDPOINT_DST),
+ i_sens(),
+ i_ts(aTs.Count()),
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ i_prop(aSA.iReplayCheck ? KMaxReplayWindowLength : 0, aPropList->Count())
+#else
+ i_prop(aSA.iReplayCheck ? KMaxReplayWindowLength : 0, 1)
+#endif
+ /**
+ * Constructing a TAcquireMessage.
+ *
+ * Construct from a Larval/egg SA and Specification
+ * (Some information is duplicated in SA and Specification, and could
+ * equally well be accessed from either one; some info, such as lifetimes
+ * is only in the specificiataion (SA lifetimes are at this stage 'undefined',
+ * although the HARD is "borrowed" for expiring the larval SA in case no
+ * key negotiator replies).
+ */
+ {
+ iError = KErrNone;
+ iBase.iMsg = &i_base;
+ iSrcAddr.iExt = &i_src_addr;
+ iSrcAddr.iAddr = aSA.iSrc;
+ iSrcAddr.iPort = aSA.iInfo.iPortSrc;
+ iDstAddr.iExt = &i_dst_addr;
+ iDstAddr.iAddr = aSA.iDst;
+ iDstAddr.iPort = aSA.iInfo.iPortDst;
+ if (!aSA.iInfo.iSrc().IsNone())
+ {
+ iProxyAddr.iExt = &i_proxy_addr;
+ iProxyAddr.iAddr = aSA.iInfo.iSrc;
+ }
+ //
+ //
+ //
+ if (aSA.iInfo.iSrcIdentity)
+ {
+ // Build Source Identity Extension for the PFKEY
+ iSrcIdent.iExt = &i_src_ident;
+ iSrcIdent.iData.Set(aSA.iInfo.iSrcIdentity->Identity());
+ i_src_ident = T_sadb_ident(SADB_EXT_IDENTITY_SRC, iSrcIdent.iData.Length());
+ i_src_ident.sadb_ident_type = aSA.iInfo.iSrcIdentity->Type();
+ }
+ if (aSA.iSrc.IsNamed())
+ {
+ iSrcEndpoint.iExt = &i_src_endpoint;
+ iSrcEndpoint.iData.Set(aSA.iSrc.Name());
+ i_src_endpoint = T_sadb_ident(SADB_X_EXT_ENDPOINT_SRC, iSrcEndpoint.iData.Length());
+ i_src_endpoint.sadb_ident_type = 0;
+ }
+ if (aSA.iInfo.iDstIdentity)
+ {
+ // Build Destination Identity Extension for the PFKEY
+ iDstIdent.iExt = &i_dst_ident;
+ iDstIdent.iData.Set(aSA.iInfo.iDstIdentity->Identity());
+ i_dst_ident = T_sadb_ident(SADB_EXT_IDENTITY_DST, iDstIdent.iData.Length());
+ i_dst_ident.sadb_ident_type = aSA.iInfo.iDstIdentity->Type();
+ }
+ if (aSA.iDst.IsNamed())
+ {
+ iDstEndpoint.iExt = &i_dst_endpoint;
+ iDstEndpoint.iData.Set(aSA.iDst.Name());
+ i_dst_endpoint = T_sadb_ident(SADB_X_EXT_ENDPOINT_DST, iDstEndpoint.iData.Length());
+ i_dst_endpoint.sadb_ident_type = 0;
+ }
+
+ if (i_ts.sadb_x_ts_numsel)
+ {
+ iTs.iExt = &i_ts;
+ iTs.iTS = &aTs;
+ }
+
+ // Sensitivity Extension
+ /* Optional, leave out */
+
+ // Proposal Extension
+ iProposal.iExt = &i_prop;
+ iProposal.iComb = &i_comb[0];
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ iProposal.iNumComb = aPropList->Count();
+ for (TInt propIdx = 0; propIdx < iProposal.iNumComb; propIdx++)
+ {
+ CSecurityProposalSpec *proposal = aPropList->At(propIdx);
+ i_comb[propIdx].sadb_comb_auth = proposal->iAalg;
+ i_comb[propIdx].sadb_comb_encrypt = proposal->iEalg;
+ // *_flags type mismatch originates from rfc2367 (PFKEY),
+ // silence warning by typecast!
+ i_comb[propIdx].sadb_comb_flags = (uint16_t)(aSA.iFlags | (aTunnel ? SADB_SAFLAGS_TUNNEL : 0));
+ if (i_comb[propIdx].sadb_comb_auth)
+ {
+ i_comb[propIdx].sadb_comb_auth_minbits = proposal->iMinAuthBits;
+ i_comb[propIdx].sadb_comb_auth_maxbits = proposal->iMaxAuthBits;
+ }
+ if (i_comb[propIdx].sadb_comb_encrypt)
+ {
+ i_comb[propIdx].sadb_comb_encrypt_minbits = proposal->iMinEncryptBits;
+ i_comb[propIdx].sadb_comb_encrypt_maxbits = proposal->iMaxEncryptBits;
+ }
+ i_comb[propIdx].sadb_comb_soft_allocations = proposal->iSoft.sadb_lifetime_allocations;
+ i_comb[propIdx].sadb_comb_hard_allocations = proposal->iHard.sadb_lifetime_allocations;
+ i_comb[propIdx].sadb_comb_soft_bytes = proposal->iSoft.sadb_lifetime_bytes;
+ i_comb[propIdx].sadb_comb_hard_bytes = proposal->iHard.sadb_lifetime_bytes;
+ i_comb[propIdx].sadb_comb_soft_addtime = proposal->iSoft.sadb_lifetime_addtime;
+ i_comb[propIdx].sadb_comb_hard_addtime = proposal->iHard.sadb_lifetime_addtime;
+ i_comb[propIdx].sadb_comb_soft_usetime = proposal->iSoft.sadb_lifetime_usetime;
+ i_comb[propIdx].sadb_comb_hard_usetime = proposal->iHard.sadb_lifetime_usetime;
+ }
+#else
+ iProposal.iNumComb = 1;
+ i_comb[0].sadb_comb_auth = aSpec.iAalg;
+ i_comb[0].sadb_comb_encrypt = aSpec.iEalg;
+ // *_flags type mismatch originates from rfc2367 (PFKEY),
+ // silence warning by typecast!
+ i_comb[0].sadb_comb_flags = (uint16_t)(aSA.iFlags | (aTunnel ? SADB_SAFLAGS_TUNNEL : 0));
+ if (i_comb[0].sadb_comb_auth)
+ {
+ i_comb[0].sadb_comb_auth_minbits = aSpec.iMinAuthBits;
+ i_comb[0].sadb_comb_auth_maxbits = aSpec.iMaxAuthBits;
+ }
+ if (i_comb[0].sadb_comb_encrypt)
+ {
+ i_comb[0].sadb_comb_encrypt_minbits = aSpec.iMinEncryptBits;
+ i_comb[0].sadb_comb_encrypt_maxbits = aSpec.iMaxEncryptBits;
+ }
+ i_comb[0].sadb_comb_soft_allocations = aSpec.iSoft.sadb_lifetime_allocations;
+ i_comb[0].sadb_comb_hard_allocations = aSpec.iHard.sadb_lifetime_allocations;
+ i_comb[0].sadb_comb_soft_bytes = aSpec.iSoft.sadb_lifetime_bytes;
+ i_comb[0].sadb_comb_hard_bytes = aSpec.iHard.sadb_lifetime_bytes;
+ i_comb[0].sadb_comb_soft_addtime = aSpec.iSoft.sadb_lifetime_addtime;
+ i_comb[0].sadb_comb_hard_addtime = aSpec.iHard.sadb_lifetime_addtime;
+ i_comb[0].sadb_comb_soft_usetime = aSpec.iSoft.sadb_lifetime_usetime;
+ i_comb[0].sadb_comb_hard_usetime = aSpec.iHard.sadb_lifetime_usetime;
+#endif
+ }
+
+
+class TExpireMessage : public TPfkeyMessage
+ /**
+ * An internal, transient representation of the EXPIRE message
+ *
+ * The base TPfkeyMessage contains const pointers to SADB structures
+ * defined in pfkeyv2.h. TExpireMessage extends TPfkeyMessage in such
+ * way that the storage required for these base structures are allocated
+ * internally here(for those extensions that are needed by the EXPIRE)
+ */
+ {
+public:
+ TExpireMessage(const CSecurityAssoc &aSA,
+ const T_sadb_lifetime &aExpired,
+ TUint32 aSeq);
+private:
+ T_sadb_msg i_base; //< Base Message Header
+ T_sadb_sa i_sa;
+ T_sadb_address i_src_addr; //< Source Address Extension
+ T_sadb_address i_dst_addr; //< Destination Address Extension
+ T_sadb_lifetime i_current; //< Current Life times
+ };
+
+TExpireMessage::TExpireMessage
+ (
+ const CSecurityAssoc &aSA,
+ const T_sadb_lifetime &aExpired,
+ TUint32 aSeq
+ )
+:
+ i_base(SADB_EXPIRE, aSA.iType, aSeq),
+ i_sa(aSA.iSPI, aSA.iReplayCheck ? KMaxReplayWindowLength : 0,
+ aSA.iState, aSA.iAalg, aSA.iEalg, aSA.iFlags),
+ i_src_addr(SADB_EXT_ADDRESS_SRC, aSA.iInfo.iProtocol),
+ i_dst_addr(SADB_EXT_ADDRESS_DST, aSA.iInfo.iProtocol),
+ i_current(aSA.iCurrent)
+ /**
+ * Constructing a TExpireMessage from a SA and expired lifetime
+ */
+ {
+ iError = KErrNone;
+ iBase.iMsg = &i_base;
+ iSa.iExt = &i_sa;
+ iSrcAddr.iExt = &i_src_addr;
+ iSrcAddr.iAddr = aSA.iSrc;
+ iSrcAddr.iPort = aSA.iInfo.iPortSrc;
+ iDstAddr.iExt = &i_dst_addr;
+ iDstAddr.iAddr = aSA.iDst;
+ iDstAddr.iPort = aSA.iInfo.iPortDst;
+ iCurrent.iExt = &i_current;
+ if (aExpired.sadb_lifetime_exttype == SADB_EXT_LIFETIME_HARD)
+ iHard.iExt = &aExpired;
+ else if (aExpired.sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT)
+ iSoft.iExt = &aExpired;
+ }
+
+
+CSecurityAssoc *CProtocolKey::Lookup(TUint8 aType, TUint32 aSPI, const TIpAddress &aDst, TInt &aHash) const
+ /**
+ * Find a specific (Association Type, Destination Address, SPI) security association.
+ *
+ * @param aType the Association Type (AH or ESP)
+ * @param aSPI the SPI number
+ * @param aDst the destination address (maybe NONE)
+ * @retval aHash the hash value (index to iHash) corresponding
+ * to the triplet. This is always returned regardless
+ * of the search result (NULL or not)
+ * @returns
+ * @li non NULL, pointer to CSecurityAssociation, if found
+ * @li NULL, if the requested association does not exist
+ */
+ {
+ CSecurityAssoc *sa;
+ aHash = Hash(aDst, aType);
+ sa = iHash[aHash];
+ while (sa)
+ {
+ if (sa->iType == aType &&
+ sa->iDst() == aDst &&
+ sa->iSPI == aSPI)
+ break;
+ sa = sa->iNext;
+ }
+ return sa;
+ }
+
+CSecurityAssoc *CProtocolKey::Lookup(TUint8 aType, TUint32 aSPI, const TIpAddress &aDst) const
+ /**
+ * @see MAssociationManager::Lookup
+ */
+ {
+ TInt ignore;
+
+ TIpAddress dst = aDst;
+ for (TInt done = 0;; done = 1)
+ {
+ CSecurityAssoc *const sa = Lookup(aType, aSPI, dst, ignore);
+ if (sa)
+ {
+ if (sa->iState == SADB_SASTATE_MATURE || sa->iState == SADB_SASTATE_DYING)
+ return sa;
+ }
+ if (done)
+ break;
+ //
+ // No incoming SA found using explicit destination address. Check for
+ // SA with dst=ANY (= any address of the current node).
+ //
+ dst.SetAddressNone();
+ }
+ return NULL;
+ }
+
+void CProtocolKey::Delete(CSecurityAssoc *aSa)
+ /**
+ * @see MAssociationManager::Delete
+ */
+ {
+ if (aSa) // Allow calling with NULL pointer (do nothing)
+ {
+ CSecurityAssoc *p, **pp;
+
+ for (pp = &iHash[Hash(aSa->iDst().Address(), aSa->iType)];
+ (p = *pp) != NULL;
+ pp = &p->iNext)
+ if (p == aSa)
+ {
+ *pp = p->iNext; // Removes aSa from the list
+ // Note: SA is logically deleted from SAD, but the instance
+ // may still persist for a while, if this Delete got called by
+ // some method still having a handle to the SA instance. Then,
+ // actual destruction is delayed until control returns to that
+ // point (if caller protected the reference by Open/Close).
+ (void)aSa->Close();
+ return;
+ }
+ Panic(EIpsecPanic_DeleteSA);
+ }
+ }
+
+void CProtocolKey::Expired(const CSecurityAssoc &aSa, TInt aType, const TLifetime &aLifetime)
+ /**
+ * @see MAssociationManager::Delete
+ */
+ {
+ T_sadb_lifetime lifetime((TUint8)aType, aLifetime, aSa.iCurrent);
+ TExpireMessage expired(aSa, lifetime, ++iSequenceNumber);
+ DeliverRegistered(expired);
+ }
+
+TInt CProtocolKey::Verify
+ /**
+ * @see MAssociationManager::Verify
+ */
+ (
+ const CSecurityAssoc *aSa,
+ const TSecurityAssocSpec &aSpec,
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ const CPropList *aPropList,
+#endif
+ const RIpAddress &aSrc,
+ const RIpAddress &aDst,
+ const RPolicySelectorInfo &aInfo
+ )
+ {
+ // The PFP processing: the specific value in RAssociationInfo needs
+ // to be replaced by a special "don't care" value that is searched for.
+ // Map remote/local into src/dst for incoming pacaket:
+ // association src <- "packet info remote"
+ // association dst <- "packet info local"
+ RAssociationInfo info;
+ if (aSpec.iMatchProxy || aSpec.iMatchRemote)
+ info.iSrc = aInfo.iRemote;
+ if (aSpec.iMatchLocal)
+ info.iDst = aInfo.iLocal;
+ info.iPortSrc = aSpec.iMatchRemotePort ? aInfo.iPortRemote : 0;
+ info.iPortDst = aSpec.iMatchLocalPort ? aInfo.iPortLocal : 0;
+ info.iProtocol = aSpec.iMatchProtocol ? aInfo.iProtocol : 0;
+ // Identities from spec: src <- remote, dst = local
+ // Reference counting for TAssociationInfo is not
+ // required, as it only has temporary duration.
+ info.iDstIdentity = aSpec.iIdentityLocal;
+ info.iSrcIdentity = aSpec.iIdentityRemote;
+
+ // The TS processing needs the actual values from the packet
+ RTrafficSelector ts;
+ ts.iSrc = aInfo.iRemote;
+ ts.iDst = aInfo.iLocal;
+ ts.iPortSrc = aInfo.iPortRemote;
+ ts.iPortDst = aInfo.iPortLocal;
+ ts.iProtocol = aInfo.iProtocol;
+
+ RIpAddress src = aSrc;
+ if (!aSpec.iMatchSrc)
+ {
+ if (!aDst().IsMulticast())
+ {
+ RIpAddress none;
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ return aSa->MatchSpec(aSpec,aPropList, src, none, info, ts);
+#else
+ return aSa->MatchSpec(aSpec, src, none, info, ts);
+#endif // SYMBIAN_IPSEC_VOIP_SUPPORT
+ }
+ src.Close();
+ }
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ return aSa->MatchSpec(aSpec, aPropList, src, aDst, info, ts);
+#else
+ return aSa->MatchSpec(aSpec, src, aDst, info, ts);
+#endif // SYMBIAN_IPSEC_VOIP_SUPPORT
+ }
+
+static void AddressMask2Range(const TIpAddress &aAddr, const TIpAddress &aMask, TIpAddress &aMin, TIpAddress &aMax)
+ /**
+ * Convert address mask into address range.
+ */
+ {
+ for (TInt i = 0; i < 4; ++i)
+ {
+ aMin.u.iAddr32[i] = aAddr.u.iAddr32[i] & aMask.u.iAddr32[i];
+ aMax.u.iAddr32[i] = aAddr.u.iAddr32[i] | ~aMask.u.iAddr32[i];
+ }
+ // Scope should be either 0 or same on both min and max (range does not
+ // make sense with scope id's (somewhat icky...)
+ aMax.iScope = aMin.iScope = aAddr.iScope & aMask.iScope;
+ }
+
+TInt CProtocolKey::Acquire
+ /**
+ * @see MAssociationManager::Acquire
+ */
+ (
+ CSecurityAssoc * &aSA,
+ const TSecurityAssocSpec &aSpec,
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ const CPropList *aPropList,
+#endif // SYMBIAN_IPSEC_VOIP_SUPPORT
+ const CTransportSelector *aTS,
+ const RIpAddress &aSrc,
+ const RIpAddress &aDst,
+ const RPolicySelectorInfo &aInfo,
+ TBool aTunnel
+ )
+ {
+ aSA = NULL; // By default, assume no SA
+
+ const TInt i = Hash(aDst().Address(), aSpec.iType);
+
+
+ // The PFP processing: the specific value in RAssociationInfo needs
+ // to be replaced by a special "don't care" value that is searched for.
+ RAssociationInfo info;
+ if (aSpec.iMatchProxy || aSpec.iMatchLocal)
+ info.iSrc = aInfo.iLocal;
+ if (aSpec.iMatchRemote)
+ info.iDst = aInfo.iRemote;
+ info.iPortSrc = aSpec.iMatchLocalPort ? aInfo.iPortLocal : 0;
+ info.iPortDst = aSpec.iMatchRemotePort ? aInfo.iPortRemote : 0;
+ info.iProtocol = aSpec.iMatchProtocol ? aInfo.iProtocol : 0;
+ // Identities from Spec: dst <- remote, src <- local
+ // Reference counting for TAssociationInfo is not
+ // required, as it only has temporary duration.
+ info.iDstIdentity = aSpec.iIdentityRemote;
+ info.iSrcIdentity = aSpec.iIdentityLocal;
+
+ // The TS processing needs the actual values from the packet
+ RTrafficSelector pkt;
+ pkt.iSrc = aInfo.iLocal;
+ pkt.iDst = aInfo.iRemote;
+ pkt.iPortSrc = aInfo.iPortLocal;
+ pkt.iPortDst = aInfo.iPortRemote;
+ pkt.iProtocol = aInfo.iProtocol;
+
+ RIpAddress src;
+ if (aSpec.iMatchSrc)
+ src = aSrc;
+
+ // Try to find a matching SA
+ CSecurityAssoc *sa = iHash[i];
+ for (sa = iHash[i]; sa; sa = sa->iNext)
+ {
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ if (sa->MatchSpec(aSpec, aPropList, src, aDst, info, pkt) == KErrNone)
+#else
+ if (sa->MatchSpec(aSpec, src, aDst, info, pkt) == KErrNone)
+#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
+ {
+ // An SA exists. If state is MATURE or DYING (= soft lifetime
+ // expired), allow a use of it. If not MATURE or DYING, the
+ // state *MUST* be LARVAL (at least in current implementation,
+ // and could actually use this in the test below, but it would
+ // make reading harder, and a potential trap for future changes)
+ //
+ aSA = sa;
+ if (sa->iState == SADB_SASTATE_MATURE ||
+ sa->iState == SADB_SASTATE_DYING)
+ return KErrNone;
+ else
+ return KRequestPending;
+ }
+ }
+
+ // Cannot find a matching SA, need to get it from the some
+ // key management daemon
+
+ //
+ // Create a larval "egg" SA (with zero SPI)
+ // (This egg will match future Acquires for the same connection
+ // in above loop. Larval eggs are the "acquire request queue" in
+ // in this implementation.
+ aSA = sa = new CSecurityAssoc(aSpec, src, aDst, info);
+ if (sa)
+ {
+ // *NOTE*
+ // This adds new SA to the *FRONT* of the iHash[i]. This is a *FEATURE*. When
+ // an ACQUIRE is looking for a matching SA, the list is scanned from beginning
+ // (see above) and it is better that the search always picks the most recent
+ // (newest) SA for *OUTBOUND* traffic. (useful when other side has lost SAs
+ // without telling this side, and negotiates new similar ones)
+ sa->iNext = iHash[i];
+ iHash[i] = sa;
+ //
+ // Borrow the field iSendSeq for storing the sequence number of the
+ // ACQUIRE message, and build the message from SA
+ //
+ sa->iSendSeq = ++iSequenceNumber;
+
+ // Build the Traffic Selector from the policy selector
+ RTrafficSelectorSet ts;
+ TInt success = 0;
+ // *NOTE* Need to use an empty "dummy" in appending to RArray,
+ // because Append does not execute assign or copy constructor
+ // of RTrafficSelector (for RIpAddress members!).
+ RTrafficSelector dummy;
+ // 1st, append the (low,high) selector, which
+ // represents the packet information
+ success |= ts.Append(dummy);
+ success |= ts.Append(dummy);
+ if (success == 0)
+ {
+ ts[0] = pkt;
+ ts[1] = pkt;
+ }
+ // 2nd, generate a (low,high) pair from each policy selector
+ while (aTS && success == 0)
+ {
+ const TInt i = ts.Count();
+ success |= ts.Append(dummy);
+ success |= ts.Append(dummy);
+ RTrafficSelector &min = ts[i];
+ RTrafficSelector &max = ts[i+1];
+
+ // *NOTE* Translation of masks to ranges works perfectly only with masks
+ // of form ~(2**N - 1). For other masks, the range selector passes more
+ // than the original mask selector.
+ if (aSpec.iMatchProtocol)
+ {
+ min.iProtocol = pkt.iProtocol;
+ max.iProtocol = pkt.iProtocol;
+ }
+ else
+ {
+ min.iProtocol = aTS->iData.iProtocol & aTS->iMask.iProtocol;
+ max.iProtocol = aTS->iData.iProtocol | ~aTS->iMask.iProtocol;
+ }
+ if (aSpec.iMatchLocalPort)
+ {
+ min.iPortSrc = pkt.iPortSrc;
+ max.iPortSrc = pkt.iPortSrc;
+ }
+ else
+ {
+ min.iPortSrc = aTS->iData.iPortLocal & aTS->iMask.iPortLocal;
+ max.iPortSrc = aTS->iData.iPortLocal | ~aTS->iMask.iPortLocal;
+ }
+ if (aSpec.iMatchRemotePort)
+ {
+ min.iPortDst = pkt.iPortDst;
+ max.iPortDst = pkt.iPortDst;
+ }
+ else
+ {
+ min.iPortDst = aTS->iData.iPortRemote & aTS->iMask.iPortRemote;
+ max.iPortDst = aTS->iData.iPortRemote | ~aTS->iMask.iPortRemote;
+ }
+
+ TIpAddress addr_min;
+ TIpAddress addr_max;
+ if (aSpec.iMatchProxy || aSpec.iMatchLocal)
+ {
+ min.iSrc = pkt.iSrc;
+ max.iSrc = pkt.iSrc;
+ }
+ else
+ {
+ AddressMask2Range(aTS->iData.iLocal(), aTS->iMask.iLocal(), addr_min, addr_max);
+ // Conversion of TIPAddress to IPV4 format in case src address is in IPV4 format
+ if(ts[0].iSrc().IsV4Mapped())
+ {
+ const union {TUint8 a[4]; TUint32 b;} v4Prefix = { {0, 0, 0xff, 0xff} };
+ addr_min.u.iAddr32 [0] = addr_max.u.iAddr32 [0] = v4Prefix.a[0];
+ addr_min.u.iAddr32 [1] = addr_max.u.iAddr32 [1] = v4Prefix.a[1];
+ addr_min.u.iAddr32 [2] = addr_max.u.iAddr32 [2] = v4Prefix.b;
+ }
+
+ min.iSrc.Open(iEndPointCollection, addr_min);
+ max.iSrc.Open(iEndPointCollection, addr_max);
+ }
+ if (aSpec.iMatchRemote)
+ {
+ min.iDst = pkt.iDst;
+ max.iDst = pkt.iDst;
+ }
+ else
+ {
+ AddressMask2Range(aTS->iData.iRemote(), aTS->iMask.iRemote(), addr_min, addr_max);
+ // Conversion of TIPAddress to IPV4 format in case destn address is in IPV4 format
+ if(ts[0].iDst().IsV4Mapped())
+ {
+ const union {TUint8 a[4]; TUint32 b;} v4Prefix = { {0, 0, 0xff, 0xff} };
+ addr_min.u.iAddr32 [0] = addr_max.u.iAddr32 [0] = v4Prefix.a[0];
+ addr_min.u.iAddr32 [1] = addr_max.u.iAddr32 [1] = v4Prefix.a[1];
+ addr_min.u.iAddr32 [2] = addr_max.u.iAddr32 [2] = v4Prefix.b;
+ }
+
+ min.iDst.Open(iEndPointCollection, addr_min);
+ max.iDst.Open(iEndPointCollection, addr_max);
+ }
+ aTS = aTS->iOr;
+ }
+#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
+ TAcquireMessage msg = TAcquireMessage(*sa, aPropList, aTunnel, ts);
+#else
+ TAcquireMessage msg = TAcquireMessage(*sa, aSpec, aTunnel, ts);
+#endif
+ DeliverRegistered(msg);
+ // Need to set some default lifetime to the egg SA
+ if (sa->TimerInit(*this) == KErrNone)
+ return KRequestPending;
+ }
+ aSA = NULL;
+ return KErrNotFound;
+ }
+
+TInt CProtocolKey::Overhead(const CSecurityAssoc *const aSa, const TIpAddress &aTunnel) const
+ /**
+ * Return the header overhead.
+ *
+ * Return additional required header space for the transformation specified by
+ * the parameters.
+ *
+ * @param aSa The Security Associtaion (or NULL)
+ * @param aTunnel The tunnel end point addresss (or unspecifed)
+ */
+ {
+ TInt overhead = 0;
+ if (!aTunnel.IsNone())
+ overhead += iEngineIPIP.Overhead(aTunnel);
+ if (aSa)
+ {
+ if (aSa->iType == SADB_SATYPE_AH)
+ overhead += iEngineAH.Overhead(*aSa);
+ else if (aSa->iType == SADB_SATYPE_ESP)
+ {
+ overhead += iEngineESP.Overhead(*aSa);
+ overhead += iEngineNATT.Overhead();
+ }
+ }
+ return overhead;
+ }
+
+int CProtocolKey::ApplyL
+ /**
+ * @see MAssociationManager::ApplyL (outgoing)
+ */
+ (
+ CSecurityAssoc *aSa,
+ RMBufSendPacket &aPacket,
+ RMBufSendInfo &aInfo,
+ const TIpAddress &aTunnel
+ )
+ {
+ if (!aTunnel.IsNone())
+ {
+ iEngineIPIP.ApplyL(aTunnel, aPacket, aInfo);
+ }
+
+ if (aSa == NULL)
+ return KErrNone;
+ else if (aSa->iType == SADB_SATYPE_AH)
+ return iEngineAH.ApplyL(*aSa, aPacket, aInfo);
+ else if (aSa->iType == SADB_SATYPE_ESP) {
+ TInt result = iEngineESP.ApplyL(*aSa, aPacket, aInfo, iRMBufAllocator);
+ if ( result != KErrNone )
+ return result;
+ else
+ return iEngineNATT.ApplyL(aSa->NatTraversal(), aPacket, aInfo); /* For NAT Traversal */
+ }
+ else
+ return KErrGeneral; // Ooooops?
+ }
+
+TInt CProtocolKey::ApplyL
+ /**
+ * @see MAssociationManager::ApplyL (incoming)
+ */
+ (
+ CSecurityAssoc * &aSa,
+ RMBufRecvPacket &aPacket,
+ RMBufRecvInfo &aInfo,
+ TInt aProtocol,
+ TIpAddress &aTunnel
+ )
+ {
+ //
+ // if UDP check if NAT traversal capsulation and remove it
+ //
+ if (aProtocol == STATIC_CAST(TInt, KProtocolInetUdp))
+ {
+ aProtocol = iEngineNATT.ApplyL(aSa, aPacket, aInfo);
+ // There is now diffrence if the incoming UDP packet has been an
+ // UDP capsulated ESP packet or not. In both cases the control
+ // is returned packet to CProtocolSecpol::ApplyL (sc_prt6.cpp)
+ // If the packet was an UDP capsulated ESP packet the UDP header has
+ // been removed from packet and pure ESP packet is returned.
+ // If packet was an ordinary UDP packet it is returned without
+ // any modifications.
+ aSa = NULL;
+ return aProtocol;
+ }
+ //
+ // IPSEC unwrap, if any
+ //
+ if (aProtocol == STATIC_CAST(TInt, KProtocolInetAh))
+ aProtocol = iEngineAH.ApplyL(aSa, aPacket, aInfo);
+ else if (aProtocol == STATIC_CAST(TInt, KProtocolInetEsp))
+ aProtocol = iEngineESP.ApplyL(aSa, aPacket, aInfo, iRMBufAllocator);
+ else
+ aSa = NULL;
+ //
+ // Tunnel unwrap, if any
+ //
+ if (
+ aProtocol == STATIC_CAST(TInt, KProtocolInetIpip) // IPv4 header uncovered
+ || aProtocol == STATIC_CAST(TInt, KProtocolInet6Ipip) // IPv6 header uncovered
+ )
+ {
+ aInfo.iProtocol = aProtocol;
+ aProtocol = iEngineIPIP.ApplyL(aTunnel, aPacket, aInfo);
+ }
+ else
+ {
+ aTunnel.SetAddressNone();
+ }
+ return aProtocol;
+ }