pull in SPD lifetime management code. fix refcnt for SPD entries.
sync w/kame XXX dead SPD entry lifetime - undergoing sakane's review
This commit is contained in:
parent
74b7155205
commit
12bdf036e2
307
sys/netkey/key.c
307
sys/netkey/key.c
|
@ -1,5 +1,5 @@
|
|||
/* $NetBSD: key.c,v 1.62 2002/05/19 08:12:55 itojun Exp $ */
|
||||
/* $KAME: key.c,v 1.203 2001/07/28 03:12:18 itojun Exp $ */
|
||||
/* $NetBSD: key.c,v 1.63 2002/05/19 08:22:12 itojun Exp $ */
|
||||
/* $KAME: key.c,v 1.234 2002/05/13 03:21:17 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
|
@ -35,7 +35,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.62 2002/05/19 08:12:55 itojun Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: key.c,v 1.63 2002/05/19 08:22:12 itojun Exp $");
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_ipsec.h"
|
||||
|
@ -332,6 +332,7 @@ static int key_spddump __P((struct socket *, struct mbuf *,
|
|||
static struct mbuf *key_setdumpsp __P((struct secpolicy *,
|
||||
u_int8_t, u_int32_t, u_int32_t));
|
||||
static u_int key_getspreqmsglen __P((struct secpolicy *));
|
||||
static int key_spdexpire __P((struct secpolicy *));
|
||||
static struct secashead *key_newsah __P((struct secasindex *));
|
||||
static void key_delsah __P((struct secashead *));
|
||||
static struct secasvar *key_newsav __P((struct mbuf *,
|
||||
|
@ -355,6 +356,8 @@ static struct mbuf *key_setsadbident __P((u_int16_t, u_int16_t, caddr_t,
|
|||
int, u_int64_t));
|
||||
#endif
|
||||
static struct mbuf *key_setsadbxsa2 __P((u_int8_t, u_int32_t, u_int32_t));
|
||||
static struct mbuf *key_setsadblifetime __P((u_int16_t, u_int32_t,
|
||||
u_int64_t, u_int64_t, u_int64_t));
|
||||
static struct mbuf *key_setsadbxpolicy __P((u_int16_t, u_int8_t,
|
||||
u_int32_t));
|
||||
static void *key_newbuf __P((const void *, u_int));
|
||||
|
@ -428,6 +431,8 @@ static const char *key_getfqdn __P((void));
|
|||
static const char *key_getuserfqdn __P((void));
|
||||
#endif
|
||||
static void key_sa_chgstate __P((struct secasvar *, u_int8_t));
|
||||
static void key_sp_dead __P((struct secpolicy *));
|
||||
static void key_sp_unlink __P((struct secpolicy *));
|
||||
static struct mbuf *key_alloc_mbuf __P((int));
|
||||
struct callout key_timehandler_ch;
|
||||
|
||||
|
@ -484,6 +489,7 @@ found:
|
|||
KEY_CHKSPDIR(sp->spidx.dir, dir, "key_allocsp");
|
||||
|
||||
/* found a SPD entry */
|
||||
sp->lastused = time.tv_sec;
|
||||
sp->refcnt++;
|
||||
splx(s);
|
||||
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
||||
|
@ -494,8 +500,8 @@ found:
|
|||
}
|
||||
|
||||
/*
|
||||
* allocating a SA entry for a *OUTBOUND* packet.
|
||||
* checking each request entries in SP, and acquire SA if need.
|
||||
* allocating an SA entry for a *OUTBOUND* packet.
|
||||
* checking each request entries in SP, and acquire an SA if need.
|
||||
* OUT: 0: there are valid requests.
|
||||
* ENOENT: policy may be valid, but SA with REQUIRE is on acquiring.
|
||||
*/
|
||||
|
@ -955,17 +961,12 @@ key_delsp(sp)
|
|||
|
||||
/* sanity check */
|
||||
if (sp == NULL)
|
||||
panic("key_delsp: NULL pointer is passed.\n");
|
||||
|
||||
sp->state = IPSEC_SPSTATE_DEAD;
|
||||
panic("key_delsp: NULL pointer is passed.");
|
||||
|
||||
if (sp->refcnt > 0)
|
||||
return; /* can't free */
|
||||
panic("key_delsp: called with positive refcnt");
|
||||
|
||||
s = splsoftnet(); /*called from softclock()*/
|
||||
/* remove from SP index */
|
||||
if (__LIST_CHAINED(sp))
|
||||
LIST_REMOVE(sp, chain);
|
||||
|
||||
{
|
||||
struct ipsecrequest *isr = sp->req, *nextisr;
|
||||
|
@ -1460,11 +1461,11 @@ fail:
|
|||
/*
|
||||
* SADB_X_SPDADD, SADB_X_SPDSETIDX or SADB_X_SPDUPDATE processing
|
||||
* add a entry to SP database, when received
|
||||
* <base, address(SD), policy>
|
||||
* <base, address(SD), (lifetime(H),) policy>
|
||||
* from the user(?).
|
||||
* Adding to SP database,
|
||||
* and send
|
||||
* <base, address(SD), policy>
|
||||
* <base, address(SD), (lifetime(H),) policy>
|
||||
* to the socket which was send.
|
||||
*
|
||||
* SPDADD set a unique policy entry.
|
||||
|
@ -1481,6 +1482,7 @@ key_spdadd(so, m, mhp)
|
|||
{
|
||||
struct sadb_address *src0, *dst0;
|
||||
struct sadb_x_policy *xpl0, *xpl;
|
||||
struct sadb_lifetime *lft = NULL;
|
||||
struct secpolicyindex spidx;
|
||||
struct secpolicy *newsp;
|
||||
int error;
|
||||
|
@ -1501,6 +1503,14 @@ key_spdadd(so, m, mhp)
|
|||
ipseclog((LOG_DEBUG, "key_spdadd: invalid message is passed.\n"));
|
||||
return key_senderror(so, m, EINVAL);
|
||||
}
|
||||
if (mhp->ext[SADB_EXT_LIFETIME_HARD] != NULL) {
|
||||
if (mhp->extlen[SADB_EXT_LIFETIME_HARD]
|
||||
< sizeof(struct sadb_lifetime)) {
|
||||
ipseclog((LOG_DEBUG, "key_spdadd: invalid message is passed.\n"));
|
||||
return key_senderror(so, m, EINVAL);
|
||||
}
|
||||
lft = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_HARD];
|
||||
}
|
||||
|
||||
src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
|
||||
dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
|
||||
|
@ -1552,8 +1562,10 @@ key_spdadd(so, m, mhp)
|
|||
newsp = key_getsp(&spidx);
|
||||
if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) {
|
||||
if (newsp) {
|
||||
newsp->state = IPSEC_SPSTATE_DEAD;
|
||||
key_freesp(newsp);
|
||||
key_sp_dead(newsp);
|
||||
key_freesp(newsp); /* ref gained by key_getsp */
|
||||
key_sp_unlink(newsp);
|
||||
newsp = NULL;
|
||||
}
|
||||
} else {
|
||||
if (newsp != NULL) {
|
||||
|
@ -1612,6 +1624,11 @@ key_spdadd(so, m, mhp)
|
|||
}
|
||||
#endif
|
||||
|
||||
newsp->created = time.tv_sec;
|
||||
newsp->lastused = time.tv_sec;
|
||||
newsp->lifetime = lft ? lft->sadb_lifetime_addtime : 0;
|
||||
newsp->validtime = lft ? lft->sadb_lifetime_usetime : 0;
|
||||
|
||||
newsp->refcnt = 1; /* do not reclaim until I say I do */
|
||||
newsp->state = IPSEC_SPSTATE_ALIVE;
|
||||
LIST_INSERT_TAIL(&sptree[newsp->spidx.dir], newsp, secpolicy, chain);
|
||||
|
@ -1635,8 +1652,15 @@ key_spdadd(so, m, mhp)
|
|||
int off;
|
||||
|
||||
/* create new sadb_msg to reply. */
|
||||
n = key_gather_mbuf(m, mhp, 2, 4, SADB_EXT_RESERVED,
|
||||
SADB_X_EXT_POLICY, SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST);
|
||||
if (lft) {
|
||||
n = key_gather_mbuf(m, mhp, 2, 5, SADB_EXT_RESERVED,
|
||||
SADB_X_EXT_POLICY, SADB_EXT_LIFETIME_HARD,
|
||||
SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST);
|
||||
} else {
|
||||
n = key_gather_mbuf(m, mhp, 2, 4, SADB_EXT_RESERVED,
|
||||
SADB_X_EXT_POLICY,
|
||||
SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST);
|
||||
}
|
||||
if (!n)
|
||||
return key_senderror(so, m, ENOBUFS);
|
||||
|
||||
|
@ -1772,8 +1796,10 @@ key_spddelete(so, m, mhp)
|
|||
/* save policy id to buffer to be returned. */
|
||||
xpl0->sadb_x_policy_id = sp->id;
|
||||
|
||||
sp->state = IPSEC_SPSTATE_DEAD;
|
||||
key_freesp(sp);
|
||||
key_sp_dead(sp);
|
||||
key_freesp(sp); /* ref gained by key_getsp */
|
||||
key_sp_unlink(sp);
|
||||
sp = NULL;
|
||||
|
||||
/* invalidate all cached SPD pointers on pcb */
|
||||
ipsec_invalpcbcacheall();
|
||||
|
@ -1837,8 +1863,10 @@ key_spddelete2(so, m, mhp)
|
|||
key_senderror(so, m, EINVAL);
|
||||
}
|
||||
|
||||
sp->state = IPSEC_SPSTATE_DEAD;
|
||||
key_freesp(sp);
|
||||
key_sp_dead(sp);
|
||||
key_freesp(sp); /* ref gained by key_getsp */
|
||||
key_sp_unlink(sp);
|
||||
sp = NULL;
|
||||
|
||||
/* invalidate all cached SPD pointers on pcb */
|
||||
ipsec_invalpcbcacheall();
|
||||
|
@ -2036,7 +2064,7 @@ key_spdflush(so, m, mhp)
|
|||
const struct sadb_msghdr *mhp;
|
||||
{
|
||||
struct sadb_msg *newmsg;
|
||||
struct secpolicy *sp;
|
||||
struct secpolicy *sp, *nextsp;
|
||||
u_int dir;
|
||||
|
||||
/* sanity check */
|
||||
|
@ -2047,8 +2075,13 @@ key_spdflush(so, m, mhp)
|
|||
return key_senderror(so, m, EINVAL);
|
||||
|
||||
for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
|
||||
LIST_FOREACH(sp, &sptree[dir], chain) {
|
||||
sp->state = IPSEC_SPSTATE_DEAD;
|
||||
for (sp = LIST_FIRST(&sptree[dir]); sp != NULL; sp = nextsp) {
|
||||
nextsp = LIST_NEXT(sp, chain);
|
||||
if (sp->state == IPSEC_SPSTATE_DEAD)
|
||||
continue;
|
||||
key_sp_dead(sp);
|
||||
key_sp_unlink(sp);
|
||||
sp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2155,6 +2188,18 @@ key_setdumpsp(sp, type, seq, pid)
|
|||
goto fail;
|
||||
m_cat(result, m);
|
||||
|
||||
m = key_setsadblifetime(SADB_EXT_LIFETIME_CURRENT,
|
||||
0, 0, (u_int64_t)sp->created, (u_int64_t)sp->lastused);
|
||||
if (!m)
|
||||
goto fail;
|
||||
m_cat(result, m);
|
||||
|
||||
m = key_setsadblifetime(SADB_EXT_LIFETIME_HARD,
|
||||
0, 0, (u_int64_t)sp->lifetime, (u_int64_t)sp->validtime);
|
||||
if (!m)
|
||||
goto fail;
|
||||
m_cat(result, m);
|
||||
|
||||
if ((result->m_flags & M_PKTHDR) == 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -2210,6 +2255,127 @@ key_getspreqmsglen(sp)
|
|||
return tlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* SADB_SPDEXPIRE processing
|
||||
* send
|
||||
* <base, address(SD), lifetime(CH), policy>
|
||||
* to KMD by PF_KEY.
|
||||
*
|
||||
* OUT: 0 : succeed
|
||||
* others : error number
|
||||
*/
|
||||
static int
|
||||
key_spdexpire(sp)
|
||||
struct secpolicy *sp;
|
||||
{
|
||||
int s;
|
||||
struct mbuf *result = NULL, *m;
|
||||
int len;
|
||||
int error = -1;
|
||||
struct sadb_lifetime *lt;
|
||||
|
||||
/* XXX: Why do we lock ? */
|
||||
#ifdef __NetBSD__
|
||||
s = splsoftnet(); /*called from softclock()*/
|
||||
#else
|
||||
s = splnet(); /*called from softclock()*/
|
||||
#endif
|
||||
|
||||
/* sanity check */
|
||||
if (sp == NULL)
|
||||
panic("key_spdexpire: NULL pointer is passed.\n");
|
||||
|
||||
/* set msg header */
|
||||
m = key_setsadbmsg(SADB_X_SPDEXPIRE, 0, 0, 0, 0, 0);
|
||||
if (!m) {
|
||||
error = ENOBUFS;
|
||||
goto fail;
|
||||
}
|
||||
result = m;
|
||||
|
||||
/* create lifetime extension (current and hard) */
|
||||
len = PFKEY_ALIGN8(sizeof(*lt)) * 2;
|
||||
m = key_alloc_mbuf(len);
|
||||
if (!m || m->m_next) { /*XXX*/
|
||||
if (m)
|
||||
m_freem(m);
|
||||
error = ENOBUFS;
|
||||
goto fail;
|
||||
}
|
||||
bzero(mtod(m, caddr_t), len);
|
||||
lt = mtod(m, struct sadb_lifetime *);
|
||||
lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime));
|
||||
lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT;
|
||||
lt->sadb_lifetime_allocations = 0;
|
||||
lt->sadb_lifetime_bytes = 0;
|
||||
lt->sadb_lifetime_addtime = sp->created;
|
||||
lt->sadb_lifetime_usetime = sp->lastused;
|
||||
lt = (struct sadb_lifetime *)(mtod(m, caddr_t) + len / 2);
|
||||
lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime));
|
||||
lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
|
||||
lt->sadb_lifetime_allocations = 0;
|
||||
lt->sadb_lifetime_bytes = 0;
|
||||
lt->sadb_lifetime_addtime = sp->lifetime;
|
||||
lt->sadb_lifetime_usetime = sp->validtime;
|
||||
m_cat(result, m);
|
||||
|
||||
/* set sadb_address for source */
|
||||
m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,
|
||||
(struct sockaddr *)&sp->spidx.src,
|
||||
sp->spidx.prefs, sp->spidx.ul_proto);
|
||||
if (!m) {
|
||||
error = ENOBUFS;
|
||||
goto fail;
|
||||
}
|
||||
m_cat(result, m);
|
||||
|
||||
/* set sadb_address for destination */
|
||||
m = key_setsadbaddr(SADB_EXT_ADDRESS_DST,
|
||||
(struct sockaddr *)&sp->spidx.dst,
|
||||
sp->spidx.prefd, sp->spidx.ul_proto);
|
||||
if (!m) {
|
||||
error = ENOBUFS;
|
||||
goto fail;
|
||||
}
|
||||
m_cat(result, m);
|
||||
|
||||
/* set secpolicy */
|
||||
m = key_sp2msg(sp);
|
||||
if (!m) {
|
||||
error = ENOBUFS;
|
||||
goto fail;
|
||||
}
|
||||
m_cat(result, m);
|
||||
|
||||
if ((result->m_flags & M_PKTHDR) == 0) {
|
||||
error = EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (result->m_len < sizeof(struct sadb_msg)) {
|
||||
result = m_pullup(result, sizeof(struct sadb_msg));
|
||||
if (result == NULL) {
|
||||
error = ENOBUFS;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
result->m_pkthdr.len = 0;
|
||||
for (m = result; m; m = m->m_next)
|
||||
result->m_pkthdr.len += m->m_len;
|
||||
|
||||
mtod(result, struct sadb_msg *)->sadb_msg_len =
|
||||
PFKEY_UNIT64(result->m_pkthdr.len);
|
||||
|
||||
return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED);
|
||||
|
||||
fail:
|
||||
if (result)
|
||||
m_freem(result);
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* %%% SAD management */
|
||||
/*
|
||||
* allocating a memory for new SA head, and copy from the values of mhp.
|
||||
|
@ -2409,7 +2575,7 @@ key_delsav(sav)
|
|||
panic("key_delsav: NULL pointer is passed.\n");
|
||||
|
||||
if (sav->refcnt > 0)
|
||||
return; /* can't free */
|
||||
panic("key_delsav: called with positive refcnt");
|
||||
|
||||
/* remove from SA header */
|
||||
if (__LIST_CHAINED(sav))
|
||||
|
@ -2757,7 +2923,12 @@ key_setsaval(sav, m, mhp)
|
|||
error = ENOBUFS;
|
||||
goto fail;
|
||||
}
|
||||
/* to be initialize ? */
|
||||
/* we no longer support byte lifetime */
|
||||
if (sav->lft_h->sadb_lifetime_bytes) {
|
||||
error = EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
/* initialize? */
|
||||
}
|
||||
|
||||
lft0 = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_SOFT];
|
||||
|
@ -2773,7 +2944,12 @@ key_setsaval(sav, m, mhp)
|
|||
error = ENOBUFS;
|
||||
goto fail;
|
||||
}
|
||||
/* to be initialize ? */
|
||||
/* we no longer support byte lifetime */
|
||||
if (sav->lft_s->sadb_lifetime_bytes) {
|
||||
error = EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
/* initialize? */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3348,6 +3524,40 @@ key_setsadbxsa2(mode, seq, reqid)
|
|||
return m;
|
||||
}
|
||||
|
||||
/*
|
||||
* set data into sadb_lifetime
|
||||
*/
|
||||
static struct mbuf *
|
||||
key_setsadblifetime(type, alloc, bytes, addtime, usetime)
|
||||
u_int16_t type;
|
||||
u_int32_t alloc;
|
||||
u_int64_t bytes, addtime, usetime;
|
||||
{
|
||||
struct mbuf *m;
|
||||
struct sadb_lifetime *p;
|
||||
size_t len;
|
||||
|
||||
len = PFKEY_ALIGN8(sizeof(struct sadb_lifetime));
|
||||
m = key_alloc_mbuf(len);
|
||||
if (!m || m->m_next) { /*XXX*/
|
||||
if (m)
|
||||
m_freem(m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = mtod(m, struct sadb_lifetime *);
|
||||
|
||||
bzero(p, len);
|
||||
p->sadb_lifetime_len = PFKEY_UNIT64(len);
|
||||
p->sadb_lifetime_exttype = type;
|
||||
p->sadb_lifetime_allocations = alloc;
|
||||
p->sadb_lifetime_bytes = bytes;
|
||||
p->sadb_lifetime_addtime = addtime;
|
||||
p->sadb_lifetime_usetime = usetime;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/*
|
||||
* set data into sadb_x_policy
|
||||
*/
|
||||
|
@ -3854,11 +4064,26 @@ key_timehandler(arg)
|
|||
for (sp = LIST_FIRST(&sptree[dir]);
|
||||
sp != NULL;
|
||||
sp = nextsp) {
|
||||
|
||||
nextsp = LIST_NEXT(sp, chain);
|
||||
|
||||
if (sp->state == IPSEC_SPSTATE_DEAD)
|
||||
key_freesp(sp);
|
||||
if (sp->state == IPSEC_SPSTATE_DEAD) {
|
||||
key_sp_unlink(sp); /*XXX*/
|
||||
sp = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sp->lifetime == 0 && sp->validtime == 0)
|
||||
continue;
|
||||
|
||||
/* the deletion will occur next time */
|
||||
if ((sp->lifetime &&
|
||||
tv.tv_sec - sp->created > sp->lifetime) ||
|
||||
(sp->validtime &&
|
||||
tv.tv_sec - sp->lastused > sp->validtime)) {
|
||||
key_sp_dead(sp);
|
||||
key_spdexpire(sp);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7087,6 +7312,26 @@ key_sa_stir_iv(sav)
|
|||
key_randomfill(sav->iv, sav->ivlen);
|
||||
}
|
||||
|
||||
static void
|
||||
key_sp_dead(sp)
|
||||
struct secpolicy *sp;
|
||||
{
|
||||
|
||||
/* mark the SP dead */
|
||||
sp->state = IPSEC_SPSTATE_DEAD;
|
||||
}
|
||||
|
||||
static void
|
||||
key_sp_unlink(sp)
|
||||
struct secpolicy *sp;
|
||||
{
|
||||
|
||||
/* remove from SP index */
|
||||
if (__LIST_CHAINED(sp))
|
||||
LIST_REMOVE(sp, chain);
|
||||
key_freesp(sp);
|
||||
}
|
||||
|
||||
/* XXX too much? */
|
||||
static struct mbuf *
|
||||
key_alloc_mbuf(l)
|
||||
|
|
Loading…
Reference in New Issue