--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/ikeutils/src/pfkeymsg.cpp Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,722 @@
+/*
+* Copyright (c) 1999-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 management daemon PFKEY message module.
+*
+*/
+
+#include <es_sock.h>
+#include <in_sock.h>
+#include <eikenv.h>
+
+#include "pfkeymsg.h"
+
+// ======== MEMBER FUNCTIONS ========
+
+#ifdef _DEBUG
+//
+// Convert to String methods
+//
+// TPfkeyBase::String
+// Convert Base Message Header to printable string
+//
+
+void TPfkeyBase::String(TDes &aStr, const TDesC &aLabel) const
+ {
+
+ if (!iMsg)
+ return;
+
+ aStr.Append(aLabel);
+ aStr.AppendFormat(_L("#%d.%d "),
+ (int)iMsg->sadb_msg_seq,
+ (int)iMsg->sadb_msg_pid);
+ switch (iMsg->sadb_msg_type)
+ {
+ case SADB_GETSPI:
+ aStr.Append(_L("GETSPI"));
+ break;
+ case SADB_UPDATE:
+ aStr.Append(_L("UPDATE"));
+ break;
+ case SADB_ADD:
+ aStr.Append(_L("ADD"));
+ break;
+ case SADB_DELETE:
+ aStr.Append(_L("DELETE"));
+ break;
+ case SADB_GET:
+ aStr.Append(_L("GET"));
+ break;
+ case SADB_ACQUIRE:
+ aStr.Append(_L("ACQUIRE"));
+ break;
+ case SADB_REGISTER:
+ aStr.Append(_L("REGISTER"));
+ break;
+ case SADB_EXPIRE:
+ aStr.Append(_L("EXPIRE"));
+ break;
+ case SADB_FLUSH:
+ aStr.Append(_L("FLUSH"));
+ break;
+ case SADB_DUMP:
+ aStr.Append(_L("DUMP"));
+ break;
+ default:
+ aStr.AppendFormat(_L("UNKNOWN(%d)"),
+ iMsg->sadb_msg_type);
+ break;
+ }
+ if (iMsg->sadb_msg_version != PF_KEY_V2)
+ aStr.AppendFormat(_L("(V%d)"), (int)iMsg->sadb_msg_version);
+
+ if (iMsg->sadb_msg_errno)
+ {
+ aStr.AppendFormat(_L("(Errno%d)"), (int)iMsg->sadb_msg_errno);
+ }
+ else
+ aStr.Append(_L("[ok] "));
+ switch (iMsg->sadb_msg_satype)
+ {
+ case SADB_SATYPE_AH:
+ aStr.Append(_L("AH"));
+ break;
+ case SADB_SATYPE_ESP:
+ aStr.Append(_L("ESP"));
+ break;
+ case SADB_SATYPE_UNSPEC:
+ aStr.Append('*');
+ break;
+ default:
+ aStr.AppendFormat(_L("UNKNOWN=%d"), (int)iMsg->sadb_msg_satype);
+ break;
+ }
+ }
+
+void TPfkeyAssociation::String(TDes &aStr, const TDesC &aLabel) const
+ {
+ if (!iExt)
+ return;
+ aStr.Append(aLabel);
+ if (iExt->sadb_sa_encrypt || iExt->sadb_sa_auth)
+ {
+ aStr.Append('(');
+ if (iExt->sadb_sa_encrypt)
+ TPfkeySupportedEncrypt::Alg2String(aStr, iExt->sadb_sa_encrypt);
+ aStr.Append(',');
+ if (iExt->sadb_sa_auth)
+ TPfkeySupportedAuth::Alg2String(aStr, iExt->sadb_sa_auth);
+ aStr.Append(')');
+ }
+
+ switch (iExt->sadb_sa_state)
+ {
+ case SADB_SASTATE_LARVAL:
+ aStr.Append(_L(" LARVAL"));
+ break;
+ case SADB_SASTATE_MATURE:
+ aStr.Append(_L(" MATURE"));
+ break;
+ case SADB_SASTATE_DYING:
+ aStr.Append(_L(" DYING"));
+ break;
+ case SADB_SASTATE_DEAD:
+ aStr.Append(_L(" DEAD"));
+ break;
+ default:
+ aStr.AppendFormat(_L(" UNKNOWN=%d"), (int)iExt->sadb_sa_state);
+ break;
+ }
+ aStr.AppendFormat(_L(" SPI=%x"), (int)ByteOrder::Swap32(iExt->sadb_sa_spi));
+ if (iExt->sadb_sa_replay)
+ aStr.AppendFormat(_L(" Replay=%d"), (int)iExt->sadb_sa_replay);
+ }
+
+void TPfkeyAddress::String(TDes &aStr, const TDesC &aLabel) const
+ {
+ if (!iExt)
+ return;
+ aStr.Append(aLabel);
+ if (iAddr)
+ {
+ TBuf<39> addr;
+ iAddr->OutputWithScope(addr);
+ aStr.Append(addr);
+ if (iExt->sadb_address_proto)
+ aStr.AppendFormat(_L(" proto=%d"), iExt->sadb_address_proto);
+ if (iAddr->Port())
+ aStr.AppendFormat(_L(" port=%d"), iAddr->Port());
+ }
+ }
+
+void TPfkeyKey::String(TDes &aStr, const TDesC &aLabel) const
+ {
+ if (iExt)
+ aStr.Append(aLabel);
+ }
+
+void TPfkeyLifetime::String(TDes &aStr, const TDesC &aLabel) const
+ {
+ if (!iExt)
+ return;
+ aStr.Append(aLabel);
+ aStr.Append((TChar)'(');
+ aStr.AppendNum(iExt->sadb_lifetime_allocations);
+ aStr.Append((TChar)',');
+ aStr.AppendNum(iExt->sadb_lifetime_bytes);
+ aStr.Append((TChar)',');
+ aStr.AppendNum(iExt->sadb_lifetime_addtime);
+ aStr.Append((TChar)',');
+ aStr.AppendNum(iExt->sadb_lifetime_usetime);
+ aStr.Append((TChar)')');
+ }
+
+void TPfkeySupported::String(TDes &aStr, const TDesC &aLabel) const
+ {
+ if (!iExt)
+ return;
+ aStr.Append(aLabel);
+ for (int i = 0; i < iNumAlg; ++i)
+ {
+ AlgString(aStr, iAlg[i].sadb_alg_id);
+ if (iAlg[i].sadb_alg_minbits == iAlg[i].sadb_alg_maxbits)
+ aStr.AppendFormat
+ (_L("(IV=%d,key=%d)"),
+ (int)iAlg[i].sadb_alg_ivlen,
+ (int)iAlg[i].sadb_alg_maxbits);
+ else
+ aStr.AppendFormat
+ (_L("(IV=%d,%d<=key<=%d)"),
+ (int)iAlg[i].sadb_alg_ivlen,
+ (int)iAlg[i].sadb_alg_minbits,
+ (int)iAlg[i].sadb_alg_maxbits);
+ }
+ }
+
+void TPfkeyIdentity::String(TDes &aStr, const TDesC &aLabel) const
+{
+
+#ifdef _UNICODE
+ if (iExt)
+ {
+ aStr.Append(aLabel);
+ if (iData.Length() == 0)
+ return;
+ HBufC *unibuf = HBufC::New(iData.Length());
+ if (!unibuf)
+ return;
+ unibuf->Des().Copy(iData);
+ aStr.Append(unibuf->Des());
+ delete unibuf;
+ }
+#else
+ if (iExt)
+ {
+ aStr.Append(aLabel);
+ aStr.Append(iData);
+ }
+#endif
+}
+
+void TPfkeySensitivity::String(TDes &aStr, const TDesC &aLabel) const
+ {
+ if (iExt)
+ {
+ aStr.Append(aLabel);
+ }
+ }
+
+void TPfkeyProposal::String(TDes &aStr, const TDesC &aLabel) const
+ {
+ if (!iExt)
+ return;
+ aStr.Append(aLabel);
+ if (iExt->sadb_prop_replay)
+ aStr.AppendFormat(_L("replay=%d"), (int)iExt->sadb_prop_replay);
+ for (int i = 0; i < iNumComb; i++)
+ {
+ aStr.AppendFormat(_L(" %d:("), i+1);
+ if (iComb[i].sadb_comb_flags & SADB_SAFLAGS_PFS)
+ aStr.Append(_L("PFS "));
+ if (iComb[i].sadb_comb_encrypt)
+ {
+ TPfkeySupportedEncrypt::Alg2String(aStr, iComb[i].sadb_comb_encrypt);
+ aStr.AppendFormat(_L("[%d..%d]"),
+ iComb[i].sadb_comb_encrypt_minbits,
+ iComb[i].sadb_comb_encrypt_maxbits);
+ }
+ if (iComb[i].sadb_comb_auth)
+ {
+ aStr.Append(',');
+ TPfkeySupportedAuth::Alg2String(aStr, iComb[i].sadb_comb_auth);
+ aStr.AppendFormat(_L("[%d..%d]"),
+ iComb[i].sadb_comb_auth_minbits,
+ iComb[i].sadb_comb_auth_maxbits);
+ }
+ if (iComb[i].sadb_comb_soft_allocations ||
+ iComb[i].sadb_comb_soft_bytes != 0 ||
+ iComb[i].sadb_comb_soft_addtime != 0||
+ iComb[i].sadb_comb_soft_usetime != 0)
+ {
+ aStr.AppendFormat(_L(" soft=(%d,"), (int)iComb[i].sadb_comb_soft_allocations);
+ aStr.AppendNum(iComb[i].sadb_comb_soft_bytes);
+ aStr.Append(',');
+ aStr.AppendNum(iComb[i].sadb_comb_soft_addtime);
+ aStr.Append(',');
+ aStr.AppendNum(iComb[i].sadb_comb_soft_usetime);
+ aStr.Append(')');
+ }
+ if (iComb[i].sadb_comb_hard_allocations ||
+ iComb[i].sadb_comb_hard_bytes != 0 ||
+ iComb[i].sadb_comb_hard_addtime != 0 ||
+ iComb[i].sadb_comb_hard_usetime != 0)
+ {
+ aStr.AppendFormat(_L(" hard=(%d,"), (int)iComb[i].sadb_comb_hard_allocations);
+ aStr.AppendNum(iComb[i].sadb_comb_hard_bytes);
+ aStr.Append(',');
+ aStr.AppendNum(iComb[i].sadb_comb_hard_addtime);
+ aStr.Append(',');
+ aStr.AppendNum(iComb[i].sadb_comb_hard_usetime);
+ aStr.Append(')');
+ }
+ aStr.Append(')');
+ }
+ }
+
+void TPfkeySpirange::String(TDes &aStr,const TDesC &aLabel) const
+ {
+ if (iExt)
+ {
+ aStr.Append(aLabel);
+ }
+ }
+
+void TPfkeyTs::String(TDes &aStr,const TDesC &aLabel) const
+ {
+ if (iExt)
+ {
+ for (TInt i = 0; i < SelectorCount(); ++i)
+ {
+ const TPfKeySelector& selector = Selector(i);
+
+ TBuf<50> src;
+ TBuf<50> dst;
+
+ selector.iSrc.OutputWithScope(src);
+ selector.iDst.OutputWithScope(dst);
+
+ aStr.AppendFormat(_L("%S[%d] proto=%d src=%S:%d, dst=%S:%d" ),
+ &aLabel, i, selector.sadb_x_selector_proto,
+ &src, selector.iSrc.Port(),
+ &dst, selector.iDst.Port());
+
+
+ }
+ }
+ }
+
+void TPFkeyPrivExt::String(TDes &aStr, const TDesC &aLabel) const
+ {
+ if (iExt)
+ aStr.Append(aLabel);
+ }
+
+#endif //#ifdef _DEBUG
+
+
+TPfkeyBase::TPfkeyBase()
+ : iMsg( 0 )
+ {
+ }
+
+TPfkeyAssociation::TPfkeyAssociation()
+ : iExt( 0 )
+ {
+ }
+
+TPfkeyLifetime::TPfkeyLifetime()
+ : iExt( 0 )
+ {
+ }
+
+TPfkeyAddress::TPfkeyAddress()
+ : iExt(0), iAddr(0)
+ {
+ }
+
+EXPORT_C const TInetAddr& TPfkeyAddress::Address() const
+ {
+ return *iAddr;
+ }
+
+TPfkeyKey::TPfkeyKey()
+ : iExt( 0 )
+ {
+ }
+
+TPfkeyIdentity::TPfkeyIdentity()
+ : iExt( 0 )
+ {
+ }
+
+TPfkeySensitivity::TPfkeySensitivity()
+ : iExt(0)
+ {
+ }
+
+TPfkeyProposal::TPfkeyProposal()
+ : iExt( 0 ),
+ iComb( 0 ),
+ iNumComb( 0 )
+ {
+ }
+
+TPfkeySupported::TPfkeySupported()
+ : iExt( 0 ),
+ iAlg( 0 ),
+ iNumAlg( 0 )
+ {
+ }
+
+void TPfkeySupportedAuth::AlgString( TDes &aStr,
+ TUint8 aAlg ) const
+ {
+ Alg2String( aStr, aAlg );
+ }
+
+void TPfkeySupportedAuth::Alg2String(TDes &aStr, TUint8 aAlg)
+ {
+ switch (aAlg)
+ {
+ case SADB_AALG_MD5HMAC:
+ aStr.Append(_L("md5hmac"));
+ break;
+ case SADB_AALG_SHA1HMAC:
+ aStr.Append(_L("sha1hmac"));
+ break;
+ default:
+ aStr.AppendFormat(_L("%d"), (int)aAlg);
+ }
+ }
+
+void TPfkeySupportedEncrypt::AlgString( TDes &aStr,
+ TUint8 aAlg ) const
+ {
+ Alg2String( aStr, aAlg );
+ }
+
+void TPfkeySupportedEncrypt::Alg2String(TDes &aStr, TUint8 aAlg)
+ {
+ switch (aAlg)
+ {
+ case SADB_EALG_DESCBC:
+ aStr.Append(_L("descbc"));
+ break;
+ case SADB_EALG_3DESCBC:
+ aStr.Append(_L("3descbc"));
+ break;
+ case SADB_EALG_NULL:
+ aStr.Append(_L("null"));
+ break;
+ case 4:
+ aStr.Append(_L("rc5"));
+ break;
+ case 5:
+ aStr.Append(_L("idea"));
+ break;
+ case 6:
+ aStr.Append(_L("cast"));
+ break;
+ case 7:
+ aStr.Append(_L("blowfish"));
+ break;
+ case 8:
+ aStr.Append(_L("3idea"));
+ break;
+ case 9:
+ aStr.Append(_L("desiv32"));
+ break;
+ case 10:
+ aStr.Append(_L("rc4"));
+ break;
+ case 12:
+ aStr.Append(_L("aes"));
+ break;
+
+ default:
+ aStr.AppendFormat(_L("%d"), (int)aAlg);
+ }
+ }
+
+TPfkeySpirange::TPfkeySpirange()
+ : iExt( 0 )
+ {
+ }
+
+TPfkeyTs::TPfkeyTs()
+ : iExt(0)
+ {
+ }
+
+EXPORT_C TInt TPfkeyTs::SelectorCount() const
+ {
+ return (iExt != NULL) ? iExt->sadb_x_ts_numsel : 0;
+ }
+
+EXPORT_C const TPfKeySelector& TPfkeyTs::Selector(TInt aIndex) const
+ {
+ __ASSERT_DEBUG(iExt != NULL, User::Invariant());
+ __ASSERT_DEBUG(iExt->sadb_x_ts_numsel > aIndex, User::Invariant());
+
+ TPfKeySelector *selector = (TPfKeySelector*)((TUint8*)iExt + sizeof(struct sadb_x_ts));
+ return selector[aIndex];
+ }
+
+TPFkeyPrivExt::TPFkeyPrivExt()
+ : iExt( 0 )
+ {
+ }
+
+//
+// TPfkeyMessage
+//
+TPfkeyMessage::TPfkeyMessage()
+ : iError( KErrNone )
+ {
+ }
+
+//
+// Construct TPfkeyMesage from a PF_KEY v2 byte stream (aMsg)
+//
+TPfkeyMessage::TPfkeyMessage(TPfkeyRecvMsg& aMsg)
+ {
+ const TUint8 *p = aMsg.Ptr();
+ TInt length = aMsg.Length();
+
+ iError = KErrArgument;
+ if (length < (TInt)sizeof(sadb_msg))
+ return; // EMSGSIZE (impossible message size)
+
+ // Base Message Header
+ iBase.iMsg = (struct sadb_msg *)p;
+ if (iBase.iMsg->sadb_msg_version != PF_KEY_V2)
+ return; // EINVAL
+ // SADB_ACQUIRE response can have sadb_msg_errno set to non-zero value
+ if (iBase.iMsg->sadb_msg_errno && (iBase.iMsg->sadb_msg_type != SADB_ACQUIRE))
+ return; // EINVAL (should be set zero by sender)
+ if (iBase.iMsg->sadb_msg_len * 8 != length)
+ return; // EMSGSIZE (incorrect message length)
+ // SADB_ACQUIRE response can have sadb_msg_reserved set to non-zero value
+ if (iBase.iMsg->sadb_msg_reserved && (iBase.iMsg->sadb_msg_type != SADB_ACQUIRE))
+ return; // EINVAL (unused parts must be zeroed)
+ p += sizeof(struct sadb_msg);
+ length -= sizeof(struct sadb_msg);
+
+ // Extension headers
+ // Some general rules:
+ // - only one instance of an extension type is valid
+ while (length > 0)
+ {
+ struct sadb_ext *ext = (struct sadb_ext *)p;
+ int ext_len = ext->sadb_ext_len;
+ int data_len, data_len2;
+
+ if (ext_len < 1)
+ return; // EINVAL (bad message format)
+ ext_len *= 8;
+ if (ext_len > length)
+ return; // EINVAL
+ switch (ext->sadb_ext_type)
+ {
+ case SADB_EXT_RESERVED:
+ return; // EINVAL (bad mesage format)
+
+ case SADB_EXT_SA:
+ if (iSa.iExt)
+ return; // EINVAL
+ iSa.iExt = (struct sadb_sa *)p;
+ break;
+
+ case SADB_EXT_LIFETIME_CURRENT:
+ if (iCurrent.iExt)
+ return; // EINVAL;
+ iCurrent.iExt = (struct sadb_lifetime *)p;
+ break;
+
+ case SADB_EXT_LIFETIME_HARD:
+ if (iHard.iExt)
+ return;
+ iHard.iExt = (struct sadb_lifetime *)p;
+ break;
+
+ case SADB_EXT_LIFETIME_SOFT:
+ if (iSoft.iExt)
+ return;
+ iSoft.iExt = (struct sadb_lifetime *)p;
+ break;
+
+ case SADB_EXT_ADDRESS_SRC:
+ if (iSrcAddr.iExt)
+ return;
+ if (ext_len != sizeof(struct sadb_address) + sizeof(TInetAddr))
+ return;
+ iSrcAddr.iExt = (struct sadb_address *)p;
+ iSrcAddr.iAddr = (TInetAddr *)(p + sizeof(struct sadb_address));
+ break;
+
+ case SADB_EXT_ADDRESS_DST:
+ if (iDstAddr.iExt)
+ return;
+ if (ext_len != sizeof(struct sadb_address) + sizeof(TInetAddr))
+ return;
+ iDstAddr.iExt = (struct sadb_address *)p;
+ iDstAddr.iAddr = (TInetAddr *)(p + sizeof(struct sadb_address));
+ break;
+
+ case SADB_EXT_ADDRESS_PROXY:
+ if (iProxyAddr.iExt)
+ return;
+ if (ext_len != sizeof(struct sadb_address) + sizeof(TInetAddr))
+ return;
+ iProxyAddr.iExt = (struct sadb_address *)p;
+ iProxyAddr.iAddr = (TInetAddr *)(p + sizeof(struct sadb_address));
+ break;
+
+ case SADB_EXT_KEY_AUTH:
+ if (iAuthKey.iExt)
+ return;
+ iAuthKey.iExt = (struct sadb_key *)p;
+ data_len = (iAuthKey.iExt->sadb_key_bits + 7) / 8;
+ if (data_len == 0 || data_len + (int)sizeof(struct sadb_key) > ext_len)
+ return;
+ iAuthKey.iData.Set(p + sizeof(struct sadb_key), data_len);
+ break;
+
+ case SADB_EXT_KEY_ENCRYPT:
+ if (iEncryptKey.iExt)
+ return;
+ iEncryptKey.iExt = (struct sadb_key *)p;
+ data_len = (iEncryptKey.iExt->sadb_key_bits + 7) / 8;
+ if (data_len == 0 || data_len + (int)sizeof(struct sadb_key) > ext_len)
+ return;
+ iEncryptKey.iData.Set(p + sizeof(struct sadb_key), data_len);
+ break;
+
+ case SADB_EXT_IDENTITY_SRC:
+ {
+ if (iSrcIdent.iExt)
+ return;
+ iSrcIdent.iExt = (struct sadb_ident *)p;
+ data_len = ext_len - sizeof(struct sadb_ident);
+ if (data_len < 0)
+ return;
+ iSrcIdent.iData.Set(p + sizeof(struct sadb_ident), data_len);
+ TInt i = iSrcIdent.iData.Locate((TChar)0);
+ if (i >= 0)
+ iSrcIdent.iData.Set(iSrcIdent.iData.Ptr(), i);
+ break;
+ }
+
+ case SADB_EXT_IDENTITY_DST:
+ {
+ if (iDstIdent.iExt)
+ return;
+ iDstIdent.iExt = (struct sadb_ident *)p;
+ data_len = ext_len - sizeof(struct sadb_ident);
+ if (data_len < 0)
+ return;
+ iDstIdent.iData.Set(p + sizeof(struct sadb_ident), data_len);
+ TInt i = iDstIdent.iData.Locate((TChar)0);
+ if (i >= 0)
+ iDstIdent.iData.Set(iDstIdent.iData.Ptr(), i);
+ break;
+ }
+
+ case SADB_EXT_SENSITIVITY:
+ if (iSensitivity.iExt)
+ return;
+ iSensitivity.iExt = (struct sadb_sens *)p;
+ data_len = iSensitivity.iExt->sadb_sens_sens_len * 8;
+ iSensitivity.iSensBitmap.Set(p + sizeof(struct sadb_sens), data_len);
+ data_len2 = iSensitivity.iExt->sadb_sens_integ_len * 8;
+ iSensitivity.iSensBitmap.Set(p + (sizeof(struct sadb_sens) + data_len),
+ data_len2);
+ if (data_len + data_len2 + (int)sizeof(struct sadb_sens) > ext_len)
+ return;
+ break;
+
+ case SADB_EXT_PROPOSAL:
+ if (iProposal.iExt)
+ return;
+ iProposal.iExt = (struct sadb_prop *)p;
+ iProposal.iNumComb = (ext_len - sizeof(struct sadb_prop)) / sizeof(struct sadb_comb);
+ iProposal.iComb = (struct sadb_comb *)(p + sizeof(struct sadb_prop));
+ break;
+
+ case SADB_EXT_SUPPORTED_AUTH:
+ if (iAuthAlgs.iExt)
+ return;
+ iAuthAlgs.iExt = (struct sadb_supported *)p;
+ iAuthAlgs.iNumAlg = (ext_len - sizeof(struct sadb_supported)) / sizeof(struct sadb_alg);
+ iAuthAlgs.iAlg = (struct sadb_alg *)(p + sizeof(struct sadb_supported));
+ break;
+
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ if (iEncryptAlgs.iExt)
+ return;
+ iEncryptAlgs.iExt = (struct sadb_supported *)p;
+ iEncryptAlgs.iNumAlg = (ext_len - sizeof(struct sadb_supported)) / sizeof(struct sadb_alg);
+ iEncryptAlgs.iAlg = (struct sadb_alg *)(p + sizeof(struct sadb_supported));
+ break;
+
+ case SADB_EXT_SPIRANGE:
+ if (iSpirange.iExt)
+ return;
+ iSpirange.iExt = (struct sadb_spirange *)p;
+ break;
+
+ /**---------------------------------------------------------------
+ *
+ * PFKEY API general private extension.
+ *
+ *----------------------------------------------------------------*/
+ case SADB_PRIV_GENERIC_EXT:
+ if (iPrivateExtension.iExt)
+ return;
+ iPrivateExtension.iExt = (struct sadb_gen_ext *)p;
+ data_len = (ext_len - sizeof(struct sadb_gen_ext));
+ if (data_len > ext_len)
+ return;
+ iPrivateExtension.iData.Set(p + sizeof(struct sadb_gen_ext), data_len);
+ break;
+
+
+ case SADB_X_EXT_TS:
+ if (iTs.iExt)
+ return;
+ iTs.iExt = (struct sadb_x_ts *)p;
+ break;
+
+ default:
+ // Unknown extensions must be ignored, not an error!
+ break;
+ }
+ p += ext_len;
+ length -= ext_len;
+ }
+ if (length != 0)
+ return;
+
+ iError = KErrNone; // Message unpacked successfully
+ }