Changeset View
Changeset View
Standalone View
Standalone View
sys/netipsec/key.c
Show First 20 Lines • Show All 610 Lines • ▼ Show 20 Lines | static struct supported_calgs { | ||||
{ SADB_X_CALG_DEFLATE, &comp_algo_deflate }, | { SADB_X_CALG_DEFLATE, &comp_algo_deflate }, | ||||
}; | }; | ||||
#ifndef IPSEC_DEBUG2 | #ifndef IPSEC_DEBUG2 | ||||
static struct callout key_timer; | static struct callout key_timer; | ||||
#endif | #endif | ||||
static void key_unlink(struct secpolicy *); | static void key_unlink(struct secpolicy *); | ||||
static void key_detach(struct secpolicy *); | |||||
static struct secpolicy *key_do_allocsp(struct secpolicyindex *spidx, u_int dir); | static struct secpolicy *key_do_allocsp(struct secpolicyindex *spidx, u_int dir); | ||||
static struct secpolicy *key_getsp(struct secpolicyindex *); | static struct secpolicy *key_getsp(struct secpolicyindex *); | ||||
static struct secpolicy *key_getspbyid(u_int32_t); | static struct secpolicy *key_getspbyid(u_int32_t); | ||||
static struct mbuf *key_gather_mbuf(struct mbuf *, | static struct mbuf *key_gather_mbuf(struct mbuf *, | ||||
const struct sadb_msghdr *, int, int, ...); | const struct sadb_msghdr *, int, int, ...); | ||||
static int key_spdadd(struct socket *, struct mbuf *, | static int key_spdadd(struct socket *, struct mbuf *, | ||||
const struct sadb_msghdr *); | const struct sadb_msghdr *); | ||||
static uint32_t key_getnewspid(void); | static uint32_t key_getnewspid(void); | ||||
▲ Show 20 Lines • Show All 568 Lines • ▼ Show 20 Lines | key_freesp(struct secpolicy **spp) | ||||
while (sp->tcount > 0) | while (sp->tcount > 0) | ||||
ipsec_delisr(sp->req[--sp->tcount]); | ipsec_delisr(sp->req[--sp->tcount]); | ||||
free(sp, M_IPSEC_SP); | free(sp, M_IPSEC_SP); | ||||
} | } | ||||
static void | static void | ||||
key_unlink(struct secpolicy *sp) | key_unlink(struct secpolicy *sp) | ||||
{ | { | ||||
SPTREE_WLOCK(); | |||||
key_detach(sp); | |||||
SPTREE_WUNLOCK(); | |||||
if (SPDCACHE_ENABLED()) | |||||
spdcache_clear(); | |||||
key_freesp(&sp); | |||||
} | |||||
static void | |||||
key_detach(struct secpolicy *sp) | |||||
{ | |||||
IPSEC_ASSERT(sp->spidx.dir == IPSEC_DIR_INBOUND || | IPSEC_ASSERT(sp->spidx.dir == IPSEC_DIR_INBOUND || | ||||
sp->spidx.dir == IPSEC_DIR_OUTBOUND, | sp->spidx.dir == IPSEC_DIR_OUTBOUND, | ||||
("invalid direction %u", sp->spidx.dir)); | ("invalid direction %u", sp->spidx.dir)); | ||||
SPTREE_UNLOCK_ASSERT(); | SPTREE_WLOCK_ASSERT(); | ||||
KEYDBG(KEY_STAMP, | KEYDBG(KEY_STAMP, | ||||
printf("%s: SP(%p)\n", __func__, sp)); | printf("%s: SP(%p)\n", __func__, sp)); | ||||
SPTREE_WLOCK(); | |||||
if (sp->state != IPSEC_SPSTATE_ALIVE) { | if (sp->state != IPSEC_SPSTATE_ALIVE) { | ||||
/* SP is already unlinked */ | /* SP is already unlinked */ | ||||
SPTREE_WUNLOCK(); | |||||
return; | return; | ||||
} | } | ||||
sp->state = IPSEC_SPSTATE_DEAD; | sp->state = IPSEC_SPSTATE_DEAD; | ||||
TAILQ_REMOVE(&V_sptree[sp->spidx.dir], sp, chain); | TAILQ_REMOVE(&V_sptree[sp->spidx.dir], sp, chain); | ||||
V_spd_size--; | V_spd_size--; | ||||
LIST_REMOVE(sp, idhash); | LIST_REMOVE(sp, idhash); | ||||
V_sp_genid++; | V_sp_genid++; | ||||
SPTREE_WUNLOCK(); | |||||
if (SPDCACHE_ENABLED()) | |||||
spdcache_clear(); | |||||
key_freesp(&sp); | |||||
} | } | ||||
/* | /* | ||||
* insert a secpolicy into the SP database. Lower priorities first | * insert a secpolicy into the SP database. Lower priorities first | ||||
*/ | */ | ||||
static void | static void | ||||
key_insertsp(struct secpolicy *newsp) | key_insertsp(struct secpolicy *newsp) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 702 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
static int | static int | ||||
key_spdadd(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp) | key_spdadd(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp) | ||||
{ | { | ||||
struct secpolicyindex spidx; | struct secpolicyindex spidx; | ||||
struct sadb_address *src0, *dst0; | struct sadb_address *src0, *dst0; | ||||
struct sadb_x_policy *xpl0, *xpl; | struct sadb_x_policy *xpl0, *xpl; | ||||
struct sadb_lifetime *lft = NULL; | struct sadb_lifetime *lft = NULL; | ||||
struct secpolicy *newsp; | struct secpolicy *newsp, *oldsp; | ||||
int error; | int error; | ||||
IPSEC_ASSERT(so != NULL, ("null socket")); | IPSEC_ASSERT(so != NULL, ("null socket")); | ||||
IPSEC_ASSERT(m != NULL, ("null mbuf")); | IPSEC_ASSERT(m != NULL, ("null mbuf")); | ||||
IPSEC_ASSERT(mhp != NULL, ("null msghdr")); | IPSEC_ASSERT(mhp != NULL, ("null msghdr")); | ||||
IPSEC_ASSERT(mhp->msg != NULL, ("null msg")); | IPSEC_ASSERT(mhp->msg != NULL, ("null msg")); | ||||
if (SADB_CHECKHDR(mhp, SADB_EXT_ADDRESS_SRC) || | if (SADB_CHECKHDR(mhp, SADB_EXT_ADDRESS_SRC) || | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | key_spdadd(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp) | ||||
KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, | KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir, | ||||
src0 + 1, | src0 + 1, | ||||
dst0 + 1, | dst0 + 1, | ||||
src0->sadb_address_prefixlen, | src0->sadb_address_prefixlen, | ||||
dst0->sadb_address_prefixlen, | dst0->sadb_address_prefixlen, | ||||
src0->sadb_address_proto, | src0->sadb_address_proto, | ||||
&spidx); | &spidx); | ||||
/* Checking there is SP already or not. */ | /* Checking there is SP already or not. */ | ||||
newsp = key_getsp(&spidx); | oldsp = key_getsp(&spidx); | ||||
if (newsp != NULL) { | if (oldsp != NULL) { | ||||
if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) { | if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) { | ||||
KEYDBG(KEY_STAMP, | KEYDBG(KEY_STAMP, | ||||
printf("%s: unlink SP(%p) for SPDUPDATE\n", | printf("%s: unlink SP(%p) for SPDUPDATE\n", | ||||
__func__, newsp)); | __func__, oldsp)); | ||||
KEYDBG(KEY_DATA, kdebug_secpolicy(newsp)); | KEYDBG(KEY_DATA, kdebug_secpolicy(oldsp)); | ||||
key_unlink(newsp); | |||||
key_freesp(&newsp); | |||||
} else { | } else { | ||||
key_freesp(&newsp); | key_freesp(&newsp); | ||||
ipseclog((LOG_DEBUG, | ipseclog((LOG_DEBUG, | ||||
"%s: a SP entry exists already.\n", __func__)); | "%s: a SP entry exists already.\n", __func__)); | ||||
return (key_senderror(so, m, EEXIST)); | return (key_senderror(so, m, EEXIST)); | ||||
} | } | ||||
} | } | ||||
/* allocate new SP entry */ | /* allocate new SP entry */ | ||||
if ((newsp = key_msg2sp(xpl0, PFKEY_EXTLEN(xpl0), &error)) == NULL) { | if ((newsp = key_msg2sp(xpl0, PFKEY_EXTLEN(xpl0), &error)) == NULL) { | ||||
if (oldsp != NULL) { | |||||
key_unlink(oldsp); | |||||
key_freesp(&oldsp); /* second for our reference */ | |||||
} | |||||
return key_senderror(so, m, error); | return key_senderror(so, m, error); | ||||
} | } | ||||
newsp->lastused = newsp->created = time_second; | newsp->lastused = newsp->created = time_second; | ||||
newsp->lifetime = lft ? lft->sadb_lifetime_addtime : 0; | newsp->lifetime = lft ? lft->sadb_lifetime_addtime : 0; | ||||
newsp->validtime = lft ? lft->sadb_lifetime_usetime : 0; | newsp->validtime = lft ? lft->sadb_lifetime_usetime : 0; | ||||
bcopy(&spidx, &newsp->spidx, sizeof(spidx)); | bcopy(&spidx, &newsp->spidx, sizeof(spidx)); | ||||
/* XXXAE: there is race between key_getsp() and key_insertsp() */ | |||||
SPTREE_WLOCK(); | SPTREE_WLOCK(); | ||||
if ((newsp->id = key_getnewspid()) == 0) { | if ((newsp->id = key_getnewspid()) == 0) { | ||||
if (oldsp != NULL) | |||||
key_detach(oldsp); | |||||
SPTREE_WUNLOCK(); | SPTREE_WUNLOCK(); | ||||
if (oldsp != NULL) { | |||||
key_freesp(&oldsp); /* first for key_detach */ | |||||
IPSEC_ASSERT(oldsp != NULL, ("null oldsp: refcount bug")); | |||||
key_freesp(&oldsp); /* second for our reference */ | |||||
if (SPDCACHE_ENABLED()) /* refresh cache because of key_detach */ | |||||
spdcache_clear(); | |||||
} | |||||
key_freesp(&newsp); | key_freesp(&newsp); | ||||
return key_senderror(so, m, ENOBUFS); | return key_senderror(so, m, ENOBUFS); | ||||
} | } | ||||
if (oldsp != NULL) | |||||
key_detach(oldsp); | |||||
key_insertsp(newsp); | key_insertsp(newsp); | ||||
SPTREE_WUNLOCK(); | SPTREE_WUNLOCK(); | ||||
if (oldsp != NULL) { | |||||
key_freesp(&oldsp); /* first for key_detach */ | |||||
IPSEC_ASSERT(oldsp != NULL, ("null oldsp: refcount bug")); | |||||
key_freesp(&oldsp); /* second for our reference */ | |||||
} | |||||
if (SPDCACHE_ENABLED()) | if (SPDCACHE_ENABLED()) | ||||
spdcache_clear(); | spdcache_clear(); | ||||
KEYDBG(KEY_STAMP, | KEYDBG(KEY_STAMP, | ||||
printf("%s: SP(%p)\n", __func__, newsp)); | printf("%s: SP(%p)\n", __func__, newsp)); | ||||
KEYDBG(KEY_DATA, kdebug_secpolicy(newsp)); | KEYDBG(KEY_DATA, kdebug_secpolicy(newsp)); | ||||
{ | { | ||||
struct mbuf *n, *mpolicy; | struct mbuf *n, *mpolicy; | ||||
struct sadb_msg *newmsg; | struct sadb_msg *newmsg; | ||||
int off; | int off; | ||||
▲ Show 20 Lines • Show All 6,506 Lines • Show Last 20 Lines |