// 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_msg.cpp - IPv6/IPv4 IPSEC PFKEY messages
// This module contains the main entry points for the
// implementations of the PFKEY messages, currently:
// SADB_GETSPI CProtocolKey::ExecGetSPI
// SADB_UPDATE CProtocolKey::ExecUpdate
// SADB_ADD CProtocolKey::ExecAdd
// SADB_DELETE CProtocolKey::ExecDelete
// SADB_GET CProtocolKey::ExecGet
// SADB_ACQUIRE CProtocolKey::ExecAcquire
// SADB_REGISTER CProtocolKey::ExecRegister
// SADB_EXPIRE (only sent to clients by IPsec)
// SADB_FLUSH CProtocolKey::ExecFlush
// SADB_DUMP CProtocolKey::ExecDump
// This module belongs to CProtocolKey implementation
// Common to all methods
// Return
// the request was syntactically correct and the
// ultimate success or failur can be checked from
// the reply PFKEY message (to all interested
// listeners).
// the request has some fatal flaws (programming
// errors). No PFKEY reply message is generated and
// the issuing socket write should indicate a failed
// operation to the application.
// The Base sadb_msg_errno field of the reply PFKEY message
// contains the ultimate result of the operation, again using
// the EPOC32 error codes. However, as the field is declared
// as "unsigned char", a positive value is stored in every
// case, that is for example "-KErrAlreadyExists". That is,
// this implementation makes a hidden assumption that KErrNone
// is ZERO, and all other errors that get used have a negative
// value! (the reserved field is now used to store extra 16
// bits of the error).
// Each ExecNNN method gets the same three parameters, even
// though not all need them all
// can be modified (a copy
// of the original and already
// linked to aMsg)
//
/**
@file key_msg.cpp
@code
@endcode
@li KErrNone
@li != KErrNone
@li TPfkeyMessage &aMsg - the message to be acted
@li struct sadb_msg &aBase - a working BASE part that
@li CProviderKey *aSrc - the originating SAP
*/
#include "sadb.h"
#include "sa_crypt.h"
#include <networking/pfkeyv2.h>
#include "pfkey.h"
#include "pfkeymsg.h"
static void Update(struct sadb_msg &aBase, CSecurityAssoc &aSa, TPfkeyMessage &aMsg, MAssociationManager &aManager, CIpsecCryptoManager *aCrypto)
/**
* Update SA without leaving.
*
* Implement a local help function for the SA Update, which is not leaving.
*
* @param aBase The writable copy of the base part of PFKEY message.
* @param aMsg The PFKEY message
* @param aSa The Security Association to update
* @param aManager The manager of assocaitions
* @param aCrypto The crypto library manager
*/
{
TRAPD(ret, ret = aSa.UpdateL(aManager, aMsg, aCrypto));
// PFKEY official error field is only 8 bits. Normal EPOC errors will usually
// fit this space, when treated as small positive integers. However, IPSEC and
// other components may return much bigger numbers. As suggested by Craig Metz,
// the low order 8 bits of the error code are placed to the official field,
// and the next 16 bits into the unused portion of the base structure. This
// may give some breathing space, until the full 32 bit error can be fit into
// the base structure...
ret = -ret; // Turn error number into positive number
aBase.sadb_msg_errno = (TUint8)ret;
aBase.sadb_msg_reserved = (TUint16)(ret >> 8);
if (aMsg.iTs.iExt)
aMsg.iTs.iTS = &aSa.iTS;
}
CSecurityAssoc *CProtocolKey::FindEgg
(
CSecurityAssoc *sa,
const TPfkeyMessage &aMsg,
const struct sadb_msg &aBase
)
/**
* Find the "Egg SA".
*
* A very local utility function to check if a iHash[i] chain
* contains a matching "Egg" SA. This is not a general function,
* ot has very specific preconditions (iDstAddr) etc, This is
* more like inline macro, just coded to make code shorter.
*
* @param sa The first sa to check
* @param aMsg PFKEYv2 message to identify the Egg.
* @param aBase The base part of the PFKEYv2 message.
* @return NULL, if not found, and SA pointer, if found
*/
{
const TIpAddress &dst = aMsg.iDstAddr.iAddr();
for ( ; sa != NULL; sa = sa->iNext)
if (sa->iSPI == 0 &&
sa->iSendSeq == aBase.sadb_msg_seq &&
sa->iType == aBase.sadb_msg_satype &&
sa->iDst() == dst)
break; // Found!!
return sa;
}
void CProtocolKey::DumpSA
(TPfkeyMessage &aMsg, struct sadb_msg &aBase, CProviderKey *aDst, CSecurityAssoc *sa)
/**
* Dump SA information into requesting socket.
*
* Build PFKEY message from the specified SA and deliver (CProtocolKey::Deliver())
* it to the requesting socket (SAP). The keying information is never returned
* this way.
*
* @param aMsg The PFKEY message to use
* @param aBase The base part of the message.
* @param aDst The requesting socket
* @param sa The Security Assocication.
*/
{
T_sadb_sa xSa
(
sa->iSPI,
sa->iReplayCheck ? KMaxReplayWindowLength : 0,
sa->iState,
sa->iAalg,
sa->iEalg,
sa->iFlags);
aMsg.iSa.iExt = &xSa;
T_sadb_lifetime xCurrent(sa->iCurrent);
aMsg.iCurrent.iExt = &xCurrent;
T_sadb_lifetime xHard(SADB_EXT_LIFETIME_HARD, sa->iHard, sa->iCurrent);
aMsg.iHard.iExt = &xHard;
T_sadb_lifetime xSoft(SADB_EXT_LIFETIME_SOFT, sa->iSoft, sa->iCurrent);
aMsg.iSoft.iExt = &xSoft;
T_sadb_address xDst(SADB_EXT_ADDRESS_DST, sa->iInfo.iProtocol);
aMsg.iDstAddr.iExt = &xDst;
aMsg.iDstAddr.iAddr = sa->iDst;
aMsg.iDstAddr.iPort = sa->iInfo.iPortDst;
T_sadb_address xSrc(SADB_EXT_ADDRESS_SRC, sa->iInfo.iProtocol);
if (!sa->iSrc().IsNone())
{
aMsg.iSrcAddr.iExt = &xSrc;
aMsg.iSrcAddr.iAddr = sa->iSrc;
aMsg.iSrcAddr.iPort = sa->iInfo.iPortSrc;
}
TIpAddress xProxyAddr(KInet6AddrNone, sa->TunnelIndex());
T_sadb_address xProxy(SADB_EXT_ADDRESS_PROXY, sa->iInfo.iProtocol);
if (!sa->iInfo.iSrc().IsNone())
{
aMsg.iProxyAddr.iExt = &xProxy;
aMsg.iProxyAddr.iAddr = sa->iInfo.iSrc;
}
else if (xProxyAddr.iScope)
{
aMsg.iProxyAddr.iExt = &xProxy;
aMsg.iProxyAddr.iAddr.Open(iEndPointCollection, xProxyAddr);
}
T_sadb_ident xSrcId(SADB_EXT_IDENTITY_SRC);
if (sa->iInfo.iSrcIdentity)
{
// Build Source Identity Extension for the PFKEY
aMsg.iSrcIdent.iExt = &xSrcId;
aMsg.iSrcIdent.iData.Set(sa->iInfo.iSrcIdentity->Identity());
xSrcId = T_sadb_ident(SADB_EXT_IDENTITY_SRC, aMsg.iSrcIdent.iData.Length());
xSrcId.sadb_ident_type = sa->iInfo.iSrcIdentity->Type();
}
T_sadb_ident xDstId(SADB_EXT_IDENTITY_DST);
if (sa->iInfo.iDstIdentity)
{
// Build Destination Identity Extension for the PFKEY
aMsg.iDstIdent.iExt = &xDstId;
aMsg.iDstIdent.iData.Set(sa->iInfo.iDstIdentity->Identity());
xDstId = T_sadb_ident(SADB_EXT_IDENTITY_DST, aMsg.iDstIdent.iData.Length());
xDstId.sadb_ident_type = sa->iInfo.iDstIdentity->Type();
}
T_sadb_ident xSrcEp(SADB_X_EXT_ENDPOINT_SRC);
if (sa->iSrc.IsNamed())
{
// Build Source End Point Extension for the PFKEY
aMsg.iSrcEndpoint.iExt = &xSrcEp;
aMsg.iSrcEndpoint.iData.Set(sa->iSrc.Name());
xSrcEp = T_sadb_ident(SADB_X_EXT_ENDPOINT_SRC, aMsg.iSrcEndpoint.iData.Length());
}
T_sadb_ident xDstEp(SADB_X_EXT_ENDPOINT_DST);
if (sa->iDst.IsNamed())
{
// Build Destination End Point Extension for the PFKEY
aMsg.iDstEndpoint.iExt = &xDstEp;
aMsg.iDstEndpoint.iData.Set(sa->iDst.Name());
xDstEp = T_sadb_ident(SADB_X_EXT_ENDPOINT_DST, aMsg.iDstEndpoint.iData.Length());
}
T_sadb_ts xTs(sa->iTS.Count());
if (xTs.sadb_x_ts_numsel)
{
aMsg.iTs.iExt = &xTs;
aMsg.iTs.iTS = &sa->iTS;
}
aBase.sadb_msg_satype = sa->iType;
aBase.sadb_msg_len = aMsg.Length64();
aDst->Deliver(aMsg);
LOG(aMsg.LogPrint(_L("---->"), iCrypto->Algorithms()));
// Can't leave pointers hanging.. clear them
aMsg.iSa.iExt = NULL;
aMsg.iCurrent.iExt = NULL;
aMsg.iHard.iExt = NULL;
aMsg.iSoft.iExt = NULL;
aMsg.iSrcAddr.iExt = NULL;
aMsg.iSrcAddr.iAddr.Close();
aMsg.iDstAddr.iExt = NULL;
aMsg.iDstAddr.iAddr.Close();
aMsg.iProxyAddr.iExt = NULL;
aMsg.iProxyAddr.iAddr.Close();
aMsg.iSrcIdent.iExt = NULL;
aMsg.iDstIdent.iExt = NULL;
aMsg.iSrcEndpoint.iExt = NULL;
aMsg.iDstEndpoint.iExt = NULL;
aMsg.iTs.iExt = NULL;
}
TInt CProtocolKey::ExecGetSPI
(TPfkeyMessage &aMsg, struct sadb_msg &aBase, CProviderKey * /*aSrc*/)
/**
* GetSPI -- allocate next free SPI number for incoming SA
*
* @param aMsg The PFKEY message to process.
* @param aBase Modifiable copy of the base extension.
* @param aSrc The originating socket
*/
{
// base, address, SPI range
if (aMsg.iDstAddr.iExt == NULL ||
aMsg.iSpirange.iExt == NULL ||
aMsg.iSpirange.iExt->sadb_spirange_max <
aMsg.iSpirange.iExt->sadb_spirange_min)
return KErrGeneral;
const int i = Hash(aMsg.iDstAddr.iAddr(), aBase.sadb_msg_satype);
TUint32 spi = aMsg.iSpirange.iExt->sadb_spirange_min;
if (!spi)
spi++; // Do not allow a request for SPI=0, this
// value is used internally to mark "eggs"
// (SA's acting as ACQUIRE request queue)!
// Locate an unused SPI value within the requested range
T_sadb_sa xsa(ByteOrder::Swap32(spi));
CSecurityAssoc *sa = iHash[i];
while (sa)
{
if (sa->iType == aBase.sadb_msg_satype &&
sa->iDst() == aMsg.iDstAddr.iAddr() &&
sa->iSPI == xsa.sadb_sa_spi)
{
// The spi is already in use, try next one in range
if (xsa.sadb_sa_spi < aMsg.iSpirange.iExt->sadb_spirange_max)
{
xsa.sadb_sa_spi = ByteOrder::Swap32(++spi);
sa = iHash[i]; // Restart search (might consider ordering
// this list by SPI value, perhaps?)
// *Don't reorder, unless something is
// also done to support the current
// ACQUIRE, which uses the current ordering
// as a "feature" (check KEY_SA.CPP Acquire!)
// -- msa
continue;
}
break; // --> Already Exists error!
}
else
sa = sa->iNext;
}
if (sa)
// Requested SPI could not be allocated
aBase.sadb_msg_errno = -KErrAlreadyExists;
else
{
if (aBase.sadb_msg_pid == 0 &&
(sa = FindEgg(iHash[i], aMsg, aBase)) != NULL)
{
// This GETSPI is a reply to earlier kernel originated ACQUIRE,
// locate the matching larval (egg) SA from the SAD.
// (With current implementation this should really not happen,
// as the Egg is for outgoing direction, and assigning SPI to
// it at this end is somewhat dubious...
//
// However, could this branch be taken when the dst is multicast,
// localhost or some other own address? Thus, leave code in just
// in case -- msa
sa->iSPI = xsa.sadb_sa_spi;
sa->iSendSeq = 0;
}
else
{
// Application just requested an SPI value, need to create a larval
// SA to hold this assigned value.
// A problem? if application doesn't do update within timelimit, the
// SA is expired and spi may get allocated to someone else. How to
// verify that this "old" application doesn't have access to it anymore?
// Have a SAP stored in larval SA? And, allow UPDATE only from this SAP?
// Delete larval SA's if the owning SAP dies?
aMsg.iSa.iExt = &xsa;
sa = new CSecurityAssoc(aMsg);
if (sa)
{
sa->iNext = iHash[i];
iHash[i] = sa;
}
else
aBase.sadb_msg_errno = -KErrNoMemory;
}
//
// Add Association Extension to the PFKEY
// Reply Message (SA(*))
//
aMsg.iSa.iExt = &xsa;
aBase.sadb_msg_len = aMsg.Length64();
}
//
// Report GETSPI to all interested listeners
//
Deliver(aMsg);
return sa ? sa->TimerInit(*this) : KErrNone;
}
TInt CProtocolKey::ExecUpdate
(TPfkeyMessage &aMsg, struct sadb_msg &aBase, CProviderKey * /*aSrc*/)
/**
* Update existing SA.
*
* Uses PFKEY extensions:
* base, SA, (lifetime(HSC)), address(SD), (address(P)), key(AE),
* (identify(SD), (sensitivity)
*
* @param aMsg The PFKEY message to process.
* @param aBase Modifiable copy of the base extension.
* @param aSrc The originating socket
*/
{
if (aMsg.iDstAddr.iExt == NULL ||
aMsg.iSa.iExt == NULL)
return KErrGeneral;
TInt i;
CSecurityAssoc *sa =
Lookup(aBase.sadb_msg_satype, aMsg.iSa.iExt->sadb_sa_spi, aMsg.iDstAddr.iAddr(), i);
if (sa)
Update(aBase, *sa, aMsg, *this, iCrypto);
else if (aBase.sadb_msg_pid == 0 &&
(sa = FindEgg(iHash[i], aMsg, aBase)) != NULL)
{
//
// This ADD is a reply to earlier kernel originated ACQUIRE,
// Change the state from larval egg to real LARVAL state
sa->iSendSeq = 0;
Update(aBase, *sa, aMsg, *this, iCrypto);
}
else
aBase.sadb_msg_errno = -KErrNotFound;
//
// Reply all Listeners
//
aMsg.iAuthKey.iExt = NULL;
aMsg.iEncryptKey.iExt = NULL;
aBase.sadb_msg_len = aMsg.Length64();
Deliver(aMsg);
return sa ? sa->TimerInit(*this) : KErrNone;
}
TInt CProtocolKey::ExecAdd
(TPfkeyMessage &aMsg, struct sadb_msg &aBase, CProviderKey * /*aSrc*/)
/**
* Add mew SA.
*
* Uses PFKEY extensions:
* base, SA, (lifetime(HS)), address(SD), (address(P),) key(AE),
* (identity(SD),) (sensitivity)
*
* @param aMsg The PFKEY message to process.
* @param aBase Modifiable copy of the base extension.
* @param aSrc The originating socket
*/
{
if (aMsg.iDstAddr.iExt == NULL ||
aMsg.iSa.iExt == NULL ||
aMsg.iSa.iExt->sadb_sa_state != SADB_SASTATE_MATURE)
return KErrGeneral;
CSecurityAssoc *sa;
TInt i;
sa = Lookup(aBase.sadb_msg_satype, aMsg.iSa.iExt->sadb_sa_spi, aMsg.iDstAddr.iAddr(), i);
if (sa)
aBase.sadb_msg_errno = -KErrAlreadyExists;
else if (aBase.sadb_msg_pid == 0 &&
(sa = FindEgg(iHash[i], aMsg, aBase)) != NULL)
{
// This ADD is a reply to earlier kernel originated ACQUIRE,
// Change the state from larval egg to real LARVAL state
sa->iSendSeq = 0;
Update(aBase, *sa, aMsg, *this, iCrypto);
}
else
{
// No matching SA exist yet, can create a new
sa = new CSecurityAssoc(aMsg);
if (sa)
{
Update(aBase, *sa, aMsg, *this, iCrypto);
if(aBase.sadb_msg_errno == 0 && aBase.sadb_msg_reserved == 0 )
{
// *NOTE*
// Adding always front may have some useful semantics, It will
// make outbound traffic to use newest matching SA (see ACQUIRE
// processing).
sa->iNext = iHash[i];
iHash[i] = sa;
}
else
{
delete (sa);
sa = NULL;
}
}
else
aBase.sadb_msg_errno = -KErrNoMemory;
}
// Return the message to all listeners
// (Keying information removed, which changes the length and
// thus the sadb_msg_len must be recomputed. The byte length
// *should* already be divisible by 8, no roundup coded!!!)
aMsg.iAuthKey.iExt = NULL;
aMsg.iEncryptKey.iExt = NULL;
aBase.sadb_msg_len = aMsg.Length64();
Deliver(aMsg);
return sa ? sa->TimerInit(*this) : KErrNone;
}
TInt CProtocolKey::ExecDelete
(TPfkeyMessage &aMsg, struct sadb_msg &aBase, CProviderKey * /*aSrc*/, TBool deliverMsg)
/**
* Delete an existing SA.
*
* Uses PKEFY extensions:
* base, SA(*), address(SD)
*
* @param aMsg The PFKEY message to process.
* @param aBase Modifiable copy of the base extension.
* @param aSrc The originating socket
* @param deliverMsg Value to determine whether or not to deliver the PFKEY
* message to the listeners (ETrue by default).
*/
{
if (aMsg.iDstAddr.iExt == NULL ||
aMsg.iSa.iExt == NULL)
return KErrGeneral;
TInt i; // not used
CSecurityAssoc *sa;
sa = Lookup(aBase.sadb_msg_satype, aMsg.iSa.iExt->sadb_sa_spi, aMsg.iDstAddr.iAddr(), i);
if (sa)
Delete(sa);
else
aBase.sadb_msg_errno = -KErrNotFound;
if (deliverMsg)
Deliver(aMsg);
return KErrNone;
}
TInt CProtocolKey::ExecGet
(TPfkeyMessage &aMsg, struct sadb_msg &aBase, CProviderKey *aSrc)
/**
* Get dump of specificic SA,
*
* Uses PKEFY extensions:
* base, SA(*), address(SD)
*
* @param aMsg The PFKEY message to process.
* @param aBase Modifiable copy of the base extension.
* @param aSrc The originating socket (SAP).
*/
{
if (aMsg.iDstAddr.iExt == NULL ||
aMsg.iSa.iExt == NULL)
return KErrGeneral;
TInt i;
CSecurityAssoc *sa;
sa = Lookup(aBase.sadb_msg_satype, aMsg.iSa.iExt->sadb_sa_spi, aMsg.iDstAddr.iAddr(), i);
if (sa)
DumpSA(aMsg, aBase, aSrc, sa);
else
{
aBase.sadb_msg_errno = -KErrNotFound;
aSrc->Deliver(aMsg);
LOG(aMsg.LogPrint(_L("---->"), iCrypto->Algorithms()));
}
return KErrNone;
}
TInt CProtocolKey::ExecAcquire
(TPfkeyMessage &aMsg, struct sadb_msg & aBase, CProviderKey* aSrc)
/**
* Acquire from the socket.
*
* Pass application originated ACQUIRE messages
* to other application sockets as is.
* Also used to handle ACQUIRE responses from listeners.
*
* @param aMsg The PFKEY message to process.
* @param aBase Modifiable copy of the base extension.
* @param aSrc The originating socket (SAP).
*/
{
TInt errNo = -((aBase.sadb_msg_reserved <<8 ) + (aBase.sadb_msg_errno));
TInt retValue = KErrNone;
/* sa is created to set the error value in the iErrValue memeber variable,
* which will be used by the ReadErr() of RSecurityAssociation
*/
TInt iTemp;
CSecurityAssoc *sa;
sa = Lookup(aBase.sadb_msg_satype, aMsg.iSa.iExt->sadb_sa_spi, aMsg.iDstAddr.iAddr(), iTemp);
if(sa)
{
sa->SetErrorValue(errNo);
}
if (errNo == KErrNone)
{
DeliverRegistered(aMsg);
}
else
{
retValue = ExecDelete(aMsg, aBase, aSrc, EFalse);
}
return retValue;
}
TInt CProtocolKey::ExecRegister
(TPfkeyMessage &aMsg, struct sadb_msg &aBase, CProviderKey *aSrc)
/**
* Register application socket as a key manager.
*
* The return message reports the list of currently
* supported algorithms.
*
* @param aMsg The PFKEY message to process.
* @param aBase Modifiable copy of the base extension.
* @param aSrc The originating socket (SAP).
*/
{
TUint i = aBase.sadb_msg_satype;
TUint8 m = (TUint8)(1 << (i % 8));
i = i / 8;
aSrc->iRegistered[i] |= m;
// Prepare the reply message
//
// This returns all known algorithms, whether the register
// was for AH, ESP or any unknown SA type.
TInt num_auth = 0, num_encrypt = 0;
// Supported algorithms returns an array of sadb_alg
// descriptors, first num_auth are authentication, the
// the last num_encrypt are encryption algorithms.
// NOTE: There may be some unused/unfilled entries
// in the middle!!!
// (may return NULL, if both counts are zero). A NULL
// return with non-zero count indicates out of memory
// situation.
CArrayFixFlat<struct sadb_alg> *algs =
iCrypto->SupportedAlgorithms(num_auth, num_encrypt);
if (algs == NULL && (num_auth || num_encrypt))
return KErrNoMemory;
T_sadb_supported auth(SADB_EXT_SUPPORTED_AUTH, num_auth);
T_sadb_supported encrypt(SADB_EXT_SUPPORTED_ENCRYPT, num_encrypt);
if (num_auth > 0)
aMsg.iAuthAlgs.Init(&auth, num_auth, algs->Back(0));
else
aMsg.iAuthAlgs.iExt = NULL;
if (num_encrypt > 0)
aMsg.iEncryptAlgs.Init(&encrypt, num_encrypt, algs->End(0) - num_encrypt);
else
aMsg.iEncryptAlgs.iExt = NULL;
aBase.sadb_msg_len = aMsg.Length64();
DeliverRegistered(aMsg);
delete algs;
return KErrNone;
}
TInt CProtocolKey::ExecFlush
(TPfkeyMessage &aMsg, struct sadb_msg &aBase, CProviderKey * /*aSrc*/)
/**
* Release all security associations of matching the type.
*
* The type selections can be: AH, ESP or all.
*
* @param aMsg The PFKEY message to process.
* @param aBase Modifiable copy of the base extension.
* @param aSrc The originating socket (SAP).
*/
{
for (TInt i = 0; i < HashSize(); ++i)
{
for (CSecurityAssoc *p, **pp = &iHash[i]; (p = *pp) != NULL;)
if (aBase.sadb_msg_satype == SADB_SATYPE_UNSPEC ||
aBase.sadb_msg_satype == p->iType)
{
*pp = p->iNext; // Removes SA from the list
delete p;
}
else
pp = &p->iNext;
}
Deliver(aMsg);
return KErrNone;
}
TInt CProtocolKey::ExecDump
(TPfkeyMessage &aMsg, struct sadb_msg &aBase, CProviderKey *aSrc)
/**
* Dump all security associations of matching type.
*
* Generate one PFKEY message from each selected SA and
* deliver messages to the requesting socket.
*
* The type selections can be: AH, ESP or all.
*
* @param aMsg The PFKEY message to process.
* @param aBase Modifiable copy of the base extension.
* @param aSrc The originating socket (SAP).
*/
{
TUint8 type = aBase.sadb_msg_satype;
for (TInt i = 0; i < HashSize(); ++i)
{
for (CSecurityAssoc *sa = iHash[i]; sa != NULL; sa = sa->iNext)
if (type == SADB_SATYPE_UNSPEC || type == sa->iType)
{
// Deliver SA as PFKEY message to aSrc
// (need a local PFkeyMessage for this)
//
// Generate TPfkeyMsg from the SA
// Seq#?
DumpSA(aMsg, aBase, aSrc, sa);
}
}
// Return the terminator Message
aBase.sadb_msg_seq = 0;
aBase.sadb_msg_pid = 0;
aBase.sadb_msg_satype = type;
aBase.sadb_msg_len = aMsg.Length64();
aSrc->Deliver(aMsg);
LOG(aMsg.LogPrint(_L("---->"), iCrypto->Algorithms()));
return KErrNone;
}
TInt CProtocolKey::Exec(const TDesC8 &aMsg, CProviderKey *aSrc)
/**
* Execute PFKEYv2 Messages from the socket interface.
*
* Called from CProviderKey::Write().
*
* This is the main function that calls the actual message handler
* according to the message type:
*
* @li SADB_GETSPI
* ExecGetSPI allocates a new SPI value from the specified SPI range.
* Echo the reply message to all listeners.
* @li SADB_UPDATE
* ExecUpdate updates a SA.
* Echo the reply message to all listeners.
* @li SADB_ADD
* ExecAdd adds a new SA.
* Echo the reply message all listeners.
* @li SADB_DELETE
* ExecDelete deletes the SA.
* Echo the reply message to all listeners.
* @li SADB_GET
* ExecGet returns the information about the specified SA.
* Return the reply only to the requesting socket (the key information is not included).
* @li SADB_ACQUIRE
* ExecAcquire passes application originated ACQUIRE to other listeners.
* Echo the message to all registered listeners. The IPSEC implementation makes no other
* processing for them.
* @li SADB_REGISTER
* ExecRegister registers the source (aSrc) socket for receiving the specified
* ACQUIRE messages for the specified security association type.
* Echo the reply to all registered listeners.
* @li SADB_FLUSH
* ExecFlush deletes all existing security associations from the SAD.
* Echo the message to all listeners (done after completed operation).
* @li SADB_DUMP
* ExecDump return the description of every Security Association of the
* specified type to the requesting socket (aSrc). Return each association
* as a separate PFKEY message.
* The last message is an empty message with PID=0 and SEQ=0
* @li SADB_EXPIRE is not a valid PFKEY request from the socket (it only generated
* by the IPsec itself).
* @li Others
* Echo all other messages as is to all registered listeners. IPsec implementation
* does not do anything with them.
*
* @param aMsg The PFKEYv2 message
* @param aSrc The originating socket.
* @return KErrNone or error code on fail.
*/
{
TPfkeyMessage msg(aMsg, iEndPointCollection);
LOG(msg.LogPrint(_L("PFKEY"), iCrypto->Algorithms()));
if (msg.iError != KErrNone)
{
// We have an exception for scenario involving SADB_ACQUIRE message with sadb_msg_errno != KErrNone.
// The TPfkeyMessage's constructor would have initialized the iError value as KErrArgument.
// But we need to permit futher processing. For all other scenarios we can return with error.
if (!msg.iBase.iMsg ||
msg.iBase.iMsg->sadb_msg_type != SADB_ACQUIRE ||
msg.iBase.iMsg->sadb_msg_errno == KErrNone)
{
return msg.iError;
}
}
if (msg.iBase.iMsg) // (the BASE part must always be present)
{
// Many of the Exec functions need to modify the
// message content before it is passed on to the
// listeners. As the BASE part pointed by aMsg is
// const, create a modifiable copy of it for the
// Exec use (change msg to point this).
struct sadb_msg base = *msg.iBase.iMsg;
msg.iBase.iMsg = &base;
switch (msg.iBase.iMsg->sadb_msg_type)
{
case SADB_GETSPI:
return ExecGetSPI (msg, base, aSrc);
case SADB_UPDATE:
return ExecUpdate (msg, base, aSrc);
case SADB_ADD:
return ExecAdd (msg, base, aSrc);
case SADB_DELETE:
return ExecDelete (msg, base, aSrc);
case SADB_GET:
return ExecGet (msg, base, aSrc);
case SADB_ACQUIRE:
return ExecAcquire (msg, base, aSrc);
case SADB_REGISTER:
return ExecRegister (msg, base, aSrc);
case SADB_FLUSH:
return ExecFlush (msg, base, aSrc);
case SADB_DUMP:
return ExecDump (msg, base, aSrc);
default:
DeliverRegistered(msg);
return KErrNone;
case SADB_RESERVED: // RESERVED is not used!
case SADB_EXPIRE: // EXPIRE is not a valid from application!
return KErrGeneral; // Invalid message
}
}
// Gets here only if the message is considered invalid at this
// method (no ExecXXXX called). KErrGeneral is used in a sense
// of EINVAL here.
return KErrGeneral;
}