diff options
author | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 2000-01-12 21:39:27 +0000 |
---|---|---|
committer | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 2000-01-12 21:39:27 +0000 |
commit | b14461307621b8ff5b61c114e4ebc7a72af72b26 (patch) | |
tree | bb360d59a9ba47ba79d09fb2a5028a25eae87cf9 /sys/net/pfkeyv2.c | |
parent | b3c5deb047476f92e27febb23a6f4c573b80a86b (diff) |
Major style cleanup for pfkeyv2.c
Diffstat (limited to 'sys/net/pfkeyv2.c')
-rw-r--r-- | sys/net/pfkeyv2.c | 3071 |
1 files changed, 1722 insertions, 1349 deletions
diff --git a/sys/net/pfkeyv2.c b/sys/net/pfkeyv2.c index b89f368e70c..08aca100434 100644 --- a/sys/net/pfkeyv2.c +++ b/sys/net/pfkeyv2.c @@ -35,38 +35,15 @@ you didn't get a copy, you may request one from <license@inner.net>. #define PFKEYV2_PROTOCOL 2 #define GETSPI_TRIES 10 -struct pfkey_version { - int protocol; - int (*create)(struct socket *socket); - int (*release)(struct socket *socket); - int (*send)(struct socket *socket, void *message, int len); -}; - -static struct pfkey_version pfkeyv2_version; - -#define PFKEYV2_SOCKETFLAGS_REGISTERED 1 -#define PFKEYV2_SOCKETFLAGS_PROMISC 2 - -#define PFKEYV2_SENDMESSAGE_UNICAST 1 -#define PFKEYV2_SENDMESSAGE_REGISTERED 2 -#define PFKEYV2_SENDMESSAGE_BROADCAST 3 - -struct pfkeyv2_socket { - struct pfkeyv2_socket *next; - struct socket *socket; - int flags; - uint32_t pid; - uint32_t registration; /* Increase size if SATYPE_MAX > 31 */ -}; - +/* Static globals */ static struct pfkeyv2_socket *pfkeyv2_sockets = NULL; - +static struct pfkey_version pfkeyv2_version; static uint32_t pfkeyv2_seq = 1; - static int nregistered = 0; static int npromisc = 0; -static struct sadb_alg ealgs[] = { +static struct sadb_alg ealgs[] = +{ { SADB_EALG_DESCBC, 64, 64, 64 }, { SADB_EALG_3DESCBC, 64, 192, 192 }, { SADB_X_EALG_BLF, 64, 5, BLF_MAXKEYLEN}, @@ -74,26 +51,24 @@ static struct sadb_alg ealgs[] = { { SADB_X_EALG_SKIPJACK, 64, 10, 10}, }; -static struct sadb_alg aalgs[] = { -{ SADB_AALG_SHA1HMAC96, 0, 160, 160 }, -{ SADB_AALG_MD5HMAC96, 0, 128, 128 }, -{ SADB_X_AALG_RIPEMD160HMAC96, 0, 160, 160 } +static struct sadb_alg aalgs[] = +{ + { SADB_AALG_SHA1HMAC96, 0, 160, 160 }, + { SADB_AALG_MD5HMAC96, 0, 128, 128 }, + { SADB_X_AALG_RIPEMD160HMAC96, 0, 160, 160 } }; -extern int pfkey_register(struct pfkey_version *version); -int pfkey_unregister(struct pfkey_version *version); -int pfkey_sendup(struct socket *socket, struct mbuf *packet, int more); - void export_address(void **, struct sockaddr *); void export_identity(void **, struct tdb *, int); void export_lifetime(void **, struct tdb *, int); void export_sa(void **, struct tdb *); + void import_address(struct sockaddr *, struct sadb_address *); void import_identity(struct tdb *, struct sadb_ident *, int); void import_key(struct ipsecinit *, struct sadb_key *, int); void import_lifetime(struct tdb *, struct sadb_lifetime *, int); void import_sa(struct tdb *, struct sadb_sa *, struct ipsecinit *); -int pfdatatopacket(void *, int, struct mbuf **); + int pfkeyv2_create(struct socket *); int pfkeyv2_get(struct tdb *, void **, void **); int pfkeyv2_release(struct socket *); @@ -103,1681 +78,2079 @@ int pfkeyv2_dump_walker(struct tdb *, void *); int pfkeyv2_flush_walker(struct tdb *, void *); int pfkeyv2_get_proto_alg(u_int8_t, u_int8_t *, int *); +int pfdatatopacket(void *, int, struct mbuf **); + +extern uint32_t sadb_exts_allowed_out[SADB_MAX+1]; +extern uint32_t sadb_exts_required_out[SADB_MAX+1]; + #define EXTLEN(x) (((struct sadb_ext *)(x))->sadb_ext_len * sizeof(uint64_t)) #define PADUP(x) (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1)) +/* + * Wrapper around m_devget(); copy data from contiguous buffer to mbuf + * chain. + */ int pfdatatopacket(void *data, int len, struct mbuf **packet) { - if (!(*packet = m_devget(data, len, 0, NULL, NULL))) - return ENOMEM; + if (!(*packet = m_devget(data, len, 0, NULL, NULL))) + return ENOMEM; - return 0; + return 0; } +/* + * Create a new PF_KEYv2 socket. + */ int pfkeyv2_create(struct socket *socket) { - struct pfkeyv2_socket *pfkeyv2_socket; + struct pfkeyv2_socket *pfkeyv2_socket; - if (!(pfkeyv2_socket = malloc(sizeof(struct pfkeyv2_socket), M_PFKEY, - M_DONTWAIT))) - return ENOMEM; + if (!(pfkeyv2_socket = malloc(sizeof(struct pfkeyv2_socket), M_PFKEY, + M_DONTWAIT))) + return ENOMEM; - bzero(pfkeyv2_socket, sizeof(struct pfkeyv2_socket)); - pfkeyv2_socket->next = pfkeyv2_sockets; - pfkeyv2_socket->socket = socket; - pfkeyv2_socket->pid = curproc->p_pid; + bzero(pfkeyv2_socket, sizeof(struct pfkeyv2_socket)); + pfkeyv2_socket->next = pfkeyv2_sockets; + pfkeyv2_socket->socket = socket; + pfkeyv2_socket->pid = curproc->p_pid; - pfkeyv2_sockets = pfkeyv2_socket; + pfkeyv2_sockets = pfkeyv2_socket; - return 0; + return 0; } +/* + * Close a PF_KEYv2 socket. + */ int pfkeyv2_release(struct socket *socket) { - struct pfkeyv2_socket **pp; + struct pfkeyv2_socket **pp; - for (pp = &pfkeyv2_sockets; - *pp && ((*pp)->socket != socket); - pp = &((*pp)->next)) - ; + for (pp = &pfkeyv2_sockets; + *pp && ((*pp)->socket != socket); + pp = &((*pp)->next)) + ; - if (*pp) { - struct pfkeyv2_socket *pfkeyv2_socket; + if (*pp) + { + struct pfkeyv2_socket *pfkeyv2_socket; - pfkeyv2_socket = *pp; - *pp = (*pp)->next; + pfkeyv2_socket = *pp; + *pp = (*pp)->next; - if (pfkeyv2_socket->flags & PFKEYV2_SOCKETFLAGS_REGISTERED) - nregistered--; + if (pfkeyv2_socket->flags & PFKEYV2_SOCKETFLAGS_REGISTERED) + nregistered--; - if (pfkeyv2_socket->flags & PFKEYV2_SOCKETFLAGS_PROMISC) - npromisc--; + if (pfkeyv2_socket->flags & PFKEYV2_SOCKETFLAGS_PROMISC) + npromisc--; - free(pfkeyv2_socket, M_PFKEY); - } + free(pfkeyv2_socket, M_PFKEY); + } - return 0; + return 0; } +/* + * (Partly) Initialize a TDB based on an SADB_SA payload. Other parts + * of the TDB will be initialized by other import routines, and tdb_init(). + */ void import_sa(struct tdb *tdb, struct sadb_sa *sadb_sa, struct ipsecinit *ii) { - if (!sadb_sa) - return; + if (!sadb_sa) + return; - if (ii) - { - ii->ii_encalg = sadb_sa->sadb_sa_encrypt; - ii->ii_authalg = sadb_sa->sadb_sa_auth; + if (ii) + { + ii->ii_encalg = sadb_sa->sadb_sa_encrypt; + ii->ii_authalg = sadb_sa->sadb_sa_auth; - tdb->tdb_spi = sadb_sa->sadb_sa_spi; - tdb->tdb_wnd = sadb_sa->sadb_sa_replay; + tdb->tdb_spi = sadb_sa->sadb_sa_spi; + tdb->tdb_wnd = sadb_sa->sadb_sa_replay; - if (sadb_sa->sadb_sa_flags & SADB_SAFLAGS_PFS) - tdb->tdb_flags |= TDBF_PFS; + if (sadb_sa->sadb_sa_flags & SADB_SAFLAGS_PFS) + tdb->tdb_flags |= TDBF_PFS; - if (sadb_sa->sadb_sa_flags & SADB_X_SAFLAGS_HALFIV) - tdb->tdb_flags |= TDBF_HALFIV; + if (sadb_sa->sadb_sa_flags & SADB_X_SAFLAGS_HALFIV) + tdb->tdb_flags |= TDBF_HALFIV; - if (sadb_sa->sadb_sa_flags & SADB_X_SAFLAGS_TUNNEL) - tdb->tdb_flags |= TDBF_TUNNELING; - } + if (sadb_sa->sadb_sa_flags & SADB_X_SAFLAGS_TUNNEL) + tdb->tdb_flags |= TDBF_TUNNELING; + } - if (sadb_sa->sadb_sa_state != SADB_SASTATE_MATURE) - tdb->tdb_flags |= TDBF_INVALID; + if (sadb_sa->sadb_sa_state != SADB_SASTATE_MATURE) + tdb->tdb_flags |= TDBF_INVALID; } +/* + * Export some of the information on a TDB. + */ void export_sa(void **p, struct tdb *tdb) { - struct sadb_sa *sadb_sa = (struct sadb_sa *)*p; + struct sadb_sa *sadb_sa = (struct sadb_sa *) *p; - sadb_sa->sadb_sa_len = sizeof(struct sadb_sa) / sizeof(uint64_t); + sadb_sa->sadb_sa_len = sizeof(struct sadb_sa) / sizeof(uint64_t); - sadb_sa->sadb_sa_spi = tdb->tdb_spi; - sadb_sa->sadb_sa_replay = tdb->tdb_wnd; + sadb_sa->sadb_sa_spi = tdb->tdb_spi; + sadb_sa->sadb_sa_replay = tdb->tdb_wnd; - if (tdb->tdb_flags & TDBF_INVALID) - sadb_sa->sadb_sa_state = SADB_SASTATE_LARVAL; + if (tdb->tdb_flags & TDBF_INVALID) + sadb_sa->sadb_sa_state = SADB_SASTATE_LARVAL; - if (tdb->tdb_authalgxform) - sadb_sa->sadb_sa_auth = tdb->tdb_authalgxform->type; + if (tdb->tdb_authalgxform) + sadb_sa->sadb_sa_auth = tdb->tdb_authalgxform->type; - if (tdb->tdb_encalgxform) - sadb_sa->sadb_sa_encrypt = tdb->tdb_encalgxform->type; + if (tdb->tdb_encalgxform) + sadb_sa->sadb_sa_encrypt = tdb->tdb_encalgxform->type; - if (tdb->tdb_flags & TDBF_PFS) - sadb_sa->sadb_sa_flags |= SADB_SAFLAGS_PFS; + if (tdb->tdb_flags & TDBF_PFS) + sadb_sa->sadb_sa_flags |= SADB_SAFLAGS_PFS; - if (tdb->tdb_flags & TDBF_HALFIV) - sadb_sa->sadb_sa_flags |= SADB_X_SAFLAGS_HALFIV; - - if (tdb->tdb_flags & TDBF_TUNNELING) - sadb_sa->sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; + /* Only relevant for the "old" IPsec transforms */ + if (tdb->tdb_flags & TDBF_HALFIV) + sadb_sa->sadb_sa_flags |= SADB_X_SAFLAGS_HALFIV; - *p += sizeof(struct sadb_sa); + if (tdb->tdb_flags & TDBF_TUNNELING) + sadb_sa->sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; + + *p += sizeof(struct sadb_sa); } +/* + * Initialize expirations and counters based on lifetime payload. + */ void import_lifetime(struct tdb *tdb, struct sadb_lifetime *sadb_lifetime, int type) { - if (!sadb_lifetime) - return; - - switch (type) { - case 0: - if ((tdb->tdb_exp_allocations = - sadb_lifetime->sadb_lifetime_allocations) != 0) - tdb->tdb_flags |= TDBF_ALLOCATIONS; - else - tdb->tdb_flags &= ~TDBF_ALLOCATIONS; + if (!sadb_lifetime) + return; + + switch (type) + { + case PFKEYV2_LIFETIME_HARD: + if ((tdb->tdb_exp_allocations = + sadb_lifetime->sadb_lifetime_allocations) != 0) + tdb->tdb_flags |= TDBF_ALLOCATIONS; + else + tdb->tdb_flags &= ~TDBF_ALLOCATIONS; - if ((tdb->tdb_exp_bytes = sadb_lifetime->sadb_lifetime_bytes) != 0) - tdb->tdb_flags |= TDBF_BYTES; - else - tdb->tdb_flags &= ~TDBF_BYTES; + if ((tdb->tdb_exp_bytes = sadb_lifetime->sadb_lifetime_bytes) != 0) + tdb->tdb_flags |= TDBF_BYTES; + else + tdb->tdb_flags &= ~TDBF_BYTES; - if ((tdb->tdb_exp_timeout = sadb_lifetime->sadb_lifetime_addtime) != 0) { - tdb->tdb_flags |= TDBF_TIMER; - tdb->tdb_exp_timeout += time.tv_sec; - } - else - tdb->tdb_flags &= ~TDBF_TIMER; + if ((tdb->tdb_exp_timeout = + sadb_lifetime->sadb_lifetime_addtime) != 0) + { + tdb->tdb_flags |= TDBF_TIMER; + tdb->tdb_exp_timeout += time.tv_sec; + } + else + tdb->tdb_flags &= ~TDBF_TIMER; - if ((tdb->tdb_exp_first_use = sadb_lifetime->sadb_lifetime_usetime) != 0) - tdb->tdb_flags |= TDBF_FIRSTUSE; - else - tdb->tdb_flags &= ~TDBF_FIRSTUSE; - break; + if ((tdb->tdb_exp_first_use = + sadb_lifetime->sadb_lifetime_usetime) != 0) + tdb->tdb_flags |= TDBF_FIRSTUSE; + else + tdb->tdb_flags &= ~TDBF_FIRSTUSE; + break; - case 1: - if ((tdb->tdb_soft_allocations = - sadb_lifetime->sadb_lifetime_allocations) != 0) - tdb->tdb_flags |= TDBF_SOFT_ALLOCATIONS; - else - tdb->tdb_flags &= ~TDBF_SOFT_ALLOCATIONS; + case PFKEYV2_LIFETIME_SOFT: + if ((tdb->tdb_soft_allocations = + sadb_lifetime->sadb_lifetime_allocations) != 0) + tdb->tdb_flags |= TDBF_SOFT_ALLOCATIONS; + else + tdb->tdb_flags &= ~TDBF_SOFT_ALLOCATIONS; - if ((tdb->tdb_soft_bytes = sadb_lifetime->sadb_lifetime_bytes) != 0) - tdb->tdb_flags |= TDBF_SOFT_BYTES; - else - tdb->tdb_flags &= ~TDBF_SOFT_BYTES; + if ((tdb->tdb_soft_bytes = + sadb_lifetime->sadb_lifetime_bytes) != 0) + tdb->tdb_flags |= TDBF_SOFT_BYTES; + else + tdb->tdb_flags &= ~TDBF_SOFT_BYTES; - if ((tdb->tdb_soft_timeout = - sadb_lifetime->sadb_lifetime_addtime) != 0) { - tdb->tdb_flags |= TDBF_SOFT_TIMER; - tdb->tdb_soft_timeout += time.tv_sec; - } - else - tdb->tdb_flags &= ~TDBF_SOFT_TIMER; + if ((tdb->tdb_soft_timeout = + sadb_lifetime->sadb_lifetime_addtime) != 0) + { + tdb->tdb_flags |= TDBF_SOFT_TIMER; + tdb->tdb_soft_timeout += time.tv_sec; + } + else + tdb->tdb_flags &= ~TDBF_SOFT_TIMER; - if ((tdb->tdb_soft_first_use = - sadb_lifetime->sadb_lifetime_usetime) != 0) - tdb->tdb_flags |= TDBF_SOFT_FIRSTUSE; - else - tdb->tdb_flags &= ~TDBF_SOFT_FIRSTUSE; - break; + if ((tdb->tdb_soft_first_use = + sadb_lifetime->sadb_lifetime_usetime) != 0) + tdb->tdb_flags |= TDBF_SOFT_FIRSTUSE; + else + tdb->tdb_flags &= ~TDBF_SOFT_FIRSTUSE; + break; - case 2: /* Nothing fancy here */ - tdb->tdb_cur_allocations = sadb_lifetime->sadb_lifetime_allocations; - tdb->tdb_cur_bytes = sadb_lifetime->sadb_lifetime_bytes; - tdb->tdb_established = sadb_lifetime->sadb_lifetime_addtime; - tdb->tdb_first_use = sadb_lifetime->sadb_lifetime_usetime; - } - - /* Setup/update our position in the expiration queue. */ - tdb_expiration(tdb, TDBEXP_TIMEOUT); + case PFKEYV2_LIFETIME_CURRENT: /* Nothing fancy here */ + tdb->tdb_cur_allocations = + sadb_lifetime->sadb_lifetime_allocations; + tdb->tdb_cur_bytes = sadb_lifetime->sadb_lifetime_bytes; + tdb->tdb_established = sadb_lifetime->sadb_lifetime_addtime; + tdb->tdb_first_use = sadb_lifetime->sadb_lifetime_usetime; + } + + /* Setup/update our position in the expiration queue. */ + tdb_expiration(tdb, TDBEXP_TIMEOUT); } +/* + * Export TDB expiration information. + */ void export_lifetime(void **p, struct tdb *tdb, int type) { - struct sadb_lifetime *sadb_lifetime = (struct sadb_lifetime *)*p; - - sadb_lifetime->sadb_lifetime_len = sizeof(struct sadb_lifetime) / - sizeof(uint64_t); - - switch (type) { - case 0: - if (tdb->tdb_flags & TDBF_ALLOCATIONS) - sadb_lifetime->sadb_lifetime_allocations = tdb->tdb_exp_allocations; - - if (tdb->tdb_flags & TDBF_BYTES) - sadb_lifetime->sadb_lifetime_bytes = tdb->tdb_exp_bytes; - - if (tdb->tdb_flags & TDBF_TIMER) - sadb_lifetime->sadb_lifetime_addtime = tdb->tdb_exp_timeout - - tdb->tdb_established; - - if (tdb->tdb_flags & TDBF_FIRSTUSE) - sadb_lifetime->sadb_lifetime_usetime = tdb->tdb_exp_first_use - - tdb->tdb_first_use; - break; - - case 1: - if (tdb->tdb_flags & TDBF_SOFT_ALLOCATIONS) - sadb_lifetime->sadb_lifetime_allocations = tdb->tdb_soft_allocations; + struct sadb_lifetime *sadb_lifetime = (struct sadb_lifetime *) *p; - if (tdb->tdb_flags & TDBF_SOFT_BYTES) - sadb_lifetime->sadb_lifetime_bytes = tdb->tdb_soft_bytes; + sadb_lifetime->sadb_lifetime_len = sizeof(struct sadb_lifetime) / + sizeof(uint64_t); - if (tdb->tdb_flags & TDBF_SOFT_TIMER) - sadb_lifetime->sadb_lifetime_addtime = tdb->tdb_soft_timeout - - tdb->tdb_established; - - if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) - sadb_lifetime->sadb_lifetime_usetime = tdb->tdb_soft_first_use - - tdb->tdb_first_use; - break; + switch (type) + { + case PFKEYV2_LIFETIME_HARD: + if (tdb->tdb_flags & TDBF_ALLOCATIONS) + sadb_lifetime->sadb_lifetime_allocations = + tdb->tdb_exp_allocations; + + if (tdb->tdb_flags & TDBF_BYTES) + sadb_lifetime->sadb_lifetime_bytes = tdb->tdb_exp_bytes; + + if (tdb->tdb_flags & TDBF_TIMER) + sadb_lifetime->sadb_lifetime_addtime = tdb->tdb_exp_timeout - + tdb->tdb_established; + + if (tdb->tdb_flags & TDBF_FIRSTUSE) + sadb_lifetime->sadb_lifetime_usetime = tdb->tdb_exp_first_use - + tdb->tdb_first_use; + break; + + case PFKEYV2_LIFETIME_SOFT: + if (tdb->tdb_flags & TDBF_SOFT_ALLOCATIONS) + sadb_lifetime->sadb_lifetime_allocations = + tdb->tdb_soft_allocations; + + if (tdb->tdb_flags & TDBF_SOFT_BYTES) + sadb_lifetime->sadb_lifetime_bytes = tdb->tdb_soft_bytes; + + if (tdb->tdb_flags & TDBF_SOFT_TIMER) + sadb_lifetime->sadb_lifetime_addtime = tdb->tdb_soft_timeout - + tdb->tdb_established; + + if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) + sadb_lifetime->sadb_lifetime_usetime = tdb->tdb_soft_first_use - + tdb->tdb_first_use; + break; - case 2: - sadb_lifetime->sadb_lifetime_allocations = tdb->tdb_cur_allocations; - sadb_lifetime->sadb_lifetime_bytes = tdb->tdb_cur_bytes; - sadb_lifetime->sadb_lifetime_addtime = tdb->tdb_established; - sadb_lifetime->sadb_lifetime_usetime = tdb->tdb_first_use; - break; - } - - *p += sizeof(struct sadb_lifetime); + case PFKEYV2_LIFETIME_CURRENT: + sadb_lifetime->sadb_lifetime_allocations = + tdb->tdb_cur_allocations; + sadb_lifetime->sadb_lifetime_bytes = tdb->tdb_cur_bytes; + sadb_lifetime->sadb_lifetime_addtime = tdb->tdb_established; + sadb_lifetime->sadb_lifetime_usetime = tdb->tdb_first_use; + break; + } + + *p += sizeof(struct sadb_lifetime); } +/* + * Copy an SADB_ADDRESS payload to a struct sockaddr. + */ void import_address(struct sockaddr *sa, struct sadb_address *sadb_address) { - int salen; - struct sockaddr *ssa = (struct sockaddr *)((void *) sadb_address + - sizeof(struct sadb_address)); - - if (!sadb_address) - return; - - if (ssa->sa_len) - salen = ssa->sa_len; - else - switch(ssa->sa_family) { - case AF_INET: - salen = sizeof(struct sockaddr_in); - break; + int salen; + struct sockaddr *ssa = (struct sockaddr *)((void *) sadb_address + + sizeof(struct sadb_address)); + + if (!sadb_address) + return; + + if (ssa->sa_len) + salen = ssa->sa_len; + else + switch(ssa->sa_family) + { +#ifdef INET + case AF_INET: + salen = sizeof(struct sockaddr_in); + break; +#endif /* INET */ + #if INET6 - case AF_INET6: - salen = sizeof(struct sockaddr_in6); - break; + case AF_INET6: + salen = sizeof(struct sockaddr_in6); + break; #endif /* INET6 */ - default: - return; + + default: + return; } - bcopy(ssa, sa, salen); - sa->sa_len = salen; + bcopy(ssa, sa, salen); + sa->sa_len = salen; } +/* + * Export a struct sockaddr as an SADB_ADDRESS payload. + */ void export_address(void **p, struct sockaddr *sa) { - struct sadb_address *sadb_address = (struct sadb_address *)*p; + struct sadb_address *sadb_address = (struct sadb_address *) *p; - sadb_address->sadb_address_len = (sizeof(struct sadb_address) + - PADUP(SA_LEN(sa))) / sizeof(uint64_t); + sadb_address->sadb_address_len = (sizeof(struct sadb_address) + + PADUP(SA_LEN(sa))) / sizeof(uint64_t); - *p += sizeof(struct sadb_address); - bcopy(sa, *p, SA_LEN(sa)); - ((struct sockaddr *)*p)->sa_family = sa->sa_family; - *p += PADUP(SA_LEN(sa)); + *p += sizeof(struct sadb_address); + bcopy(sa, *p, SA_LEN(sa)); + ((struct sockaddr *) *p)->sa_family = sa->sa_family; + *p += PADUP(SA_LEN(sa)); } +/* + * Import an identity payload into the TDB. + */ void import_identity(struct tdb *tdb, struct sadb_ident *sadb_ident, int type) { - if (!sadb_ident) - return; - - if (type == 0) { - tdb->tdb_srcid_len = EXTLEN(sadb_ident) - - sizeof(struct sadb_ident); - tdb->tdb_srcid_type = sadb_ident->sadb_ident_type; - MALLOC(tdb->tdb_srcid, u_int8_t *, tdb->tdb_srcid_len, M_XDATA, - M_WAITOK); - bcopy((void *)sadb_ident + sizeof(struct sadb_ident), - tdb->tdb_srcid, tdb->tdb_srcid_len); - } else { - tdb->tdb_dstid_len = EXTLEN(sadb_ident) - - sizeof(struct sadb_ident); - tdb->tdb_dstid_type = sadb_ident->sadb_ident_type; - MALLOC(tdb->tdb_dstid, u_int8_t *, tdb->tdb_dstid_len, M_XDATA, - M_WAITOK); - bcopy((void *)sadb_ident + sizeof(struct sadb_ident), - tdb->tdb_dstid, tdb->tdb_dstid_len); - } + if (!sadb_ident) + return; + + if (type == PFKEYV2_IDENTITY_SRC) + { + tdb->tdb_srcid_len = EXTLEN(sadb_ident) - + sizeof(struct sadb_ident); + tdb->tdb_srcid_type = sadb_ident->sadb_ident_type; + MALLOC(tdb->tdb_srcid, u_int8_t *, tdb->tdb_srcid_len, M_XDATA, + M_WAITOK); + bcopy((void *)sadb_ident + sizeof(struct sadb_ident), + tdb->tdb_srcid, tdb->tdb_srcid_len); + } + else + { + tdb->tdb_dstid_len = EXTLEN(sadb_ident) - + sizeof(struct sadb_ident); + tdb->tdb_dstid_type = sadb_ident->sadb_ident_type; + MALLOC(tdb->tdb_dstid, u_int8_t *, tdb->tdb_dstid_len, M_XDATA, + M_WAITOK); + bcopy((void *)sadb_ident + sizeof(struct sadb_ident), + tdb->tdb_dstid, tdb->tdb_dstid_len); + } } void export_identity(void **p, struct tdb *tdb, int type) { - struct sadb_ident *sadb_ident = (struct sadb_ident *)*p; - - if (type == 0) { - sadb_ident->sadb_ident_len = (sizeof(struct sadb_ident) + PADUP(tdb->tdb_srcid_len)) / sizeof(uint64_t); - sadb_ident->sadb_ident_type = tdb->tdb_srcid_type; - *p += sizeof(struct sadb_ident); - bcopy(tdb->tdb_srcid, *p, tdb->tdb_srcid_len); - *p += PADUP(tdb->tdb_srcid_len); - } else { - sadb_ident->sadb_ident_len = (sizeof(struct sadb_ident) + PADUP(tdb->tdb_dstid_len)) / sizeof(uint64_t); - sadb_ident->sadb_ident_type = tdb->tdb_dstid_type; - *p += sizeof(struct sadb_ident); - bcopy(tdb->tdb_dstid, *p, tdb->tdb_dstid_len); - *p += PADUP(tdb->tdb_dstid_len); - } + struct sadb_ident *sadb_ident = (struct sadb_ident *) *p; + + if (type == PFKEYV2_IDENTITY_SRC) + { + sadb_ident->sadb_ident_len = (sizeof(struct sadb_ident) + + PADUP(tdb->tdb_srcid_len)) / + sizeof(uint64_t); + sadb_ident->sadb_ident_type = tdb->tdb_srcid_type; + *p += sizeof(struct sadb_ident); + bcopy(tdb->tdb_srcid, *p, tdb->tdb_srcid_len); + *p += PADUP(tdb->tdb_srcid_len); + } + else + { + sadb_ident->sadb_ident_len = (sizeof(struct sadb_ident) + + PADUP(tdb->tdb_dstid_len)) / + sizeof(uint64_t); + sadb_ident->sadb_ident_type = tdb->tdb_dstid_type; + *p += sizeof(struct sadb_ident); + bcopy(tdb->tdb_dstid, *p, tdb->tdb_dstid_len); + *p += PADUP(tdb->tdb_dstid_len); + } } +/* ... */ void import_key(struct ipsecinit *ii, struct sadb_key *sadb_key, int type) { - if (!sadb_key) - return; + if (!sadb_key) + return; - if (type == 0) { /* Encryption key */ - ii->ii_enckeylen = sadb_key->sadb_key_bits / 8; - ii->ii_enckey = (void *)sadb_key + sizeof(struct sadb_key); - } else { - ii->ii_authkeylen = sadb_key->sadb_key_bits / 8; - ii->ii_authkey = (void *)sadb_key + sizeof(struct sadb_key); - } + if (type == PFKEYV2_ENCRYPTION_KEY) + { /* Encryption key */ + ii->ii_enckeylen = sadb_key->sadb_key_bits / 8; + ii->ii_enckey = (void *)sadb_key + sizeof(struct sadb_key); + } + else + { + ii->ii_authkeylen = sadb_key->sadb_key_bits / 8; + ii->ii_authkey = (void *)sadb_key + sizeof(struct sadb_key); + } } +/* + * Send a PFKEYv2 message, possibly to many receivers, based on the + * satype of the socket (which is set by the REGISTER message), and the + * third argument. + */ int pfkeyv2_sendmessage(void **headers, int mode, struct socket *socket, u_int8_t satype, int count) { - int i, j, rval; - void *p, *buffer = NULL; - struct mbuf *packet; - struct pfkeyv2_socket *s; + int i, j, rval; + void *p, *buffer = NULL; + struct mbuf *packet; + struct pfkeyv2_socket *s; + struct sadb_msg *smsg; - j = sizeof(struct sadb_msg); + /* Find out how much space we'll need... */ + j = sizeof(struct sadb_msg); - for (i = 1; i <= SADB_EXT_MAX; i++) - if (headers[i]) - j += ((struct sadb_ext *)headers[i])->sadb_ext_len * sizeof(uint64_t); + for (i = 1; i <= SADB_EXT_MAX; i++) + if (headers[i]) + j += ((struct sadb_ext *)headers[i])->sadb_ext_len * sizeof(uint64_t); - if (!(buffer = malloc(j + sizeof(struct sadb_msg), M_PFKEY, M_DONTWAIT))) { - rval = ENOMEM; - goto ret; - } - - p = buffer + sizeof(struct sadb_msg); - bcopy(headers[0], p, sizeof(struct sadb_msg)); - ((struct sadb_msg *)p)->sadb_msg_len = j / sizeof(uint64_t); - p += sizeof(struct sadb_msg); - - for (i = 1; i <= SADB_EXT_MAX; i++) - if (headers[i]) { - ((struct sadb_ext *)headers[i])->sadb_ext_type = i; - bcopy(headers[i], p, EXTLEN(headers[i])); - p += EXTLEN(headers[i]); + /* ...and allocate it */ + if (!(buffer = malloc(j + sizeof(struct sadb_msg), M_PFKEY, M_DONTWAIT))) + { + rval = ENOMEM; + goto ret; } - if ((rval = pfdatatopacket(buffer + sizeof(struct sadb_msg), - j, &packet)) != 0) - goto ret; + p = buffer + sizeof(struct sadb_msg); + bcopy(headers[0], p, sizeof(struct sadb_msg)); + ((struct sadb_msg *) p)->sadb_msg_len = j / sizeof(uint64_t); + p += sizeof(struct sadb_msg); - switch(mode) { - case PFKEYV2_SENDMESSAGE_UNICAST: - pfkey_sendup(socket, packet, 0); - - bzero(buffer, sizeof(struct sadb_msg)); - ((struct sadb_msg *)buffer)->sadb_msg_version = PF_KEY_V2; - ((struct sadb_msg *)buffer)->sadb_msg_type = SADB_X_PROMISC; - ((struct sadb_msg *)buffer)->sadb_msg_len = - (sizeof(struct sadb_msg) + j) / sizeof(uint64_t); - ((struct sadb_msg *)buffer)->sadb_msg_seq = 0; - - if ((rval = pfdatatopacket(buffer, sizeof(struct sadb_msg) + j, - &packet)) != 0) - goto ret; - - for (s = pfkeyv2_sockets; s; s = s->next) - if ((s->flags & PFKEYV2_SOCKETFLAGS_PROMISC) && (s->socket != socket)) - pfkey_sendup(s->socket, packet, 1); + /* Copy payloads in the packet */ + for (i = 1; i <= SADB_EXT_MAX; i++) + if (headers[i]) + { + ((struct sadb_ext *) headers[i])->sadb_ext_type = i; + bcopy(headers[i], p, EXTLEN(headers[i])); + p += EXTLEN(headers[i]); + } - m_zero(packet); - m_freem(packet); - break; + if ((rval = pfdatatopacket(buffer + sizeof(struct sadb_msg), + j, &packet)) != 0) + goto ret; - case PFKEYV2_SENDMESSAGE_REGISTERED: - for (s = pfkeyv2_sockets; s; s = s->next) - if (s->flags & PFKEYV2_SOCKETFLAGS_REGISTERED) { - if (!satype) /* Just send to everyone registered */ - pfkey_sendup(s->socket, packet, 1); - else { - if ((1 << satype) & s->registration) /* specified SATYPE */ - if (count-- == 0) { /* Done */ - pfkey_sendup(s->socket, packet, 1); - break; + switch(mode) + { + case PFKEYV2_SENDMESSAGE_UNICAST: + /* + * Send message to the specified socket, plus all + * promiscuous listeners. + */ + pfkey_sendup(socket, packet, 0); + + /* + * Promiscuous messages contain the original message + * encapsulated in another sadb_msg header. + */ + bzero(buffer, sizeof(struct sadb_msg)); + smsg = (struct sadb_msg *) buffer; + smsg->sadb_msg_version = PF_KEY_V2; + smsg->sadb_msg_type = SADB_X_PROMISC; + smsg->sadb_msg_len = (sizeof(struct sadb_msg) + j) / + sizeof(uint64_t); + smsg->sadb_msg_seq = 0; + + /* Copy to mbuf chain */ + if ((rval = pfdatatopacket(buffer, sizeof(struct sadb_msg) + j, + &packet)) != 0) + goto ret; + + /* + * Search for promiscuous listeners, skipping the + * original destination. + */ + for (s = pfkeyv2_sockets; s; s = s->next) + if ((s->flags & PFKEYV2_SOCKETFLAGS_PROMISC) && + (s->socket != socket)) + pfkey_sendup(s->socket, packet, 1); + + /* Done, let's be a bit paranoid */ + m_zero(packet); + m_freem(packet); + break; + + case PFKEYV2_SENDMESSAGE_REGISTERED: + /* + * Send the message to all registered sockets that match + * the specified satype (e.g., all IPSEC-ESP negotiators) + */ + for (s = pfkeyv2_sockets; s; s = s->next) + if (s->flags & PFKEYV2_SOCKETFLAGS_REGISTERED) + { + if (!satype) /* Just send to everyone registered */ + pfkey_sendup(s->socket, packet, 1); + else + { + /* Check for specified satype */ + if ((1 << satype) & s->registration) + if (count-- == 0) + { /* Done */ + pfkey_sendup(s->socket, packet, 1); + break; + } } - } - } - - m_freem(packet); - - bzero(buffer, sizeof(struct sadb_msg)); - ((struct sadb_msg *)buffer)->sadb_msg_version = PF_KEY_V2; - ((struct sadb_msg *)buffer)->sadb_msg_type = SADB_X_PROMISC; - ((struct sadb_msg *)buffer)->sadb_msg_len = - (sizeof(struct sadb_msg) + j) / sizeof(uint64_t); - ((struct sadb_msg *)buffer)->sadb_msg_seq = 0; - - if ((rval = pfdatatopacket(buffer, sizeof(struct sadb_msg) + j, - &packet)) != 0) - goto ret; - - for (s = pfkeyv2_sockets; s; s = s->next) - if ((s->flags & PFKEYV2_SOCKETFLAGS_PROMISC) && - (s->flags & PFKEYV2_SOCKETFLAGS_REGISTERED)) - pfkey_sendup(s->socket, packet, 1); + } - m_freem(packet); - break; + /* Free last/original copy of the packet */ + m_freem(packet); + + /* Encapsulate the original message "inside" an sadb_msg header */ + bzero(buffer, sizeof(struct sadb_msg)); + smsg = (struct sadb_msg *) buffer; + smsg->sadb_msg_version = PF_KEY_V2; + smsg->sadb_msg_type = SADB_X_PROMISC; + smsg->sadb_msg_len = (sizeof(struct sadb_msg) + j) / + sizeof(uint64_t); + smsg->sadb_msg_seq = 0; + + /* Convert to mbuf chain */ + if ((rval = pfdatatopacket(buffer, sizeof(struct sadb_msg) + j, + &packet)) != 0) + goto ret; + + /* Send to all registered promiscuous listeners */ + for (s = pfkeyv2_sockets; s; s = s->next) + if ((s->flags & PFKEYV2_SOCKETFLAGS_PROMISC) && + (s->flags & PFKEYV2_SOCKETFLAGS_REGISTERED)) + pfkey_sendup(s->socket, packet, 1); + + m_freem(packet); + break; + + case PFKEYV2_SENDMESSAGE_BROADCAST: + /* Send message to all sockets */ + for (s = pfkeyv2_sockets; s; s = s->next) + pfkey_sendup(s->socket, packet, 1); - case PFKEYV2_SENDMESSAGE_BROADCAST: - for (s = pfkeyv2_sockets; s; s = s->next) - pfkey_sendup(s->socket, packet, 1); + m_freem(packet); + break; + } - m_freem(packet); - break; - } + ret: + if (buffer != NULL) + { + bzero(buffer, j + sizeof(struct sadb_msg)); + free(buffer, M_PFKEY); + } -ret: - if (buffer != NULL) { - bzero(buffer, j + sizeof(struct sadb_msg)); - free(buffer, M_PFKEY); - } - return rval; + return rval; } -extern uint32_t sadb_exts_allowed_out[SADB_MAX+1]; -extern uint32_t sadb_exts_required_out[SADB_MAX+1]; - +/* + * Get all the information contained in an SA to a PFKEYV2 message. + */ int pfkeyv2_get(struct tdb *sa, void **headers, void **buffer) { - int rval, i; - void *p; + int rval, i; + void *p; - i = sizeof(struct sadb_sa) + sizeof(struct sadb_lifetime); + /* Find how much space we need */ + i = sizeof(struct sadb_sa) + sizeof(struct sadb_lifetime); - if (sa->tdb_soft_allocations || sa->tdb_soft_bytes || - sa->tdb_soft_timeout || sa->tdb_soft_first_use) - i += sizeof(struct sadb_lifetime); + if (sa->tdb_soft_allocations || sa->tdb_soft_bytes || + sa->tdb_soft_timeout || sa->tdb_soft_first_use) + i += sizeof(struct sadb_lifetime); - if (sa->tdb_exp_allocations || sa->tdb_exp_bytes || - sa->tdb_exp_timeout || sa->tdb_exp_first_use) - i += sizeof(struct sadb_lifetime); + if (sa->tdb_exp_allocations || sa->tdb_exp_bytes || + sa->tdb_exp_timeout || sa->tdb_exp_first_use) + i += sizeof(struct sadb_lifetime); - if (sa->tdb_src.sa.sa_family) - i += sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_src.sa)); + if (sa->tdb_src.sa.sa_family) + i += sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_src.sa)); - if (sa->tdb_dst.sa.sa_family) - i += sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_dst.sa)); + if (sa->tdb_dst.sa.sa_family) + i += sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_dst.sa)); - if (sa->tdb_proxy.sa.sa_family) - i += sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_proxy.sa)); + if (sa->tdb_proxy.sa.sa_family) + i += sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_proxy.sa)); - if (sa->tdb_srcid_len) - i += PADUP(sa->tdb_srcid_len) + sizeof(struct sadb_ident); + if (sa->tdb_srcid_len) + i += PADUP(sa->tdb_srcid_len) + sizeof(struct sadb_ident); - if (sa->tdb_dstid_len) - i += PADUP(sa->tdb_dstid_len) + sizeof(struct sadb_ident); + if (sa->tdb_dstid_len) + i += PADUP(sa->tdb_dstid_len) + sizeof(struct sadb_ident); - if (!(p = malloc(i, M_PFKEY, M_DONTWAIT))) { - rval = ENOMEM; - goto ret; - } + if (!(p = malloc(i, M_PFKEY, M_DONTWAIT))) + { + rval = ENOMEM; + goto ret; + } + else + { + *buffer = p; + bzero(p, i); + } - *buffer = p; + headers[SADB_EXT_SA] = p; - bzero(p, i); - - headers[SADB_EXT_SA] = p; - export_sa(&p, sa); + export_sa(&p, sa); /* Export SA information (mostly flags) */ - headers[SADB_EXT_LIFETIME_CURRENT] = p; - export_lifetime(&p, sa, 2); + /* Export lifetimes where applicable */ + headers[SADB_EXT_LIFETIME_CURRENT] = p; + export_lifetime(&p, sa, PFKEYV2_LIFETIME_CURRENT); - if (sa->tdb_soft_allocations || sa->tdb_soft_bytes || - sa->tdb_soft_first_use || sa->tdb_soft_timeout) { - headers[SADB_EXT_LIFETIME_SOFT] = p; - export_lifetime(&p, sa, 1); - } + if (sa->tdb_soft_allocations || sa->tdb_soft_bytes || + sa->tdb_soft_first_use || sa->tdb_soft_timeout) + { + headers[SADB_EXT_LIFETIME_SOFT] = p; + export_lifetime(&p, sa, PFKEYV2_LIFETIME_SOFT); + } - if (sa->tdb_exp_allocations || sa->tdb_exp_bytes || - sa->tdb_exp_first_use || sa->tdb_exp_timeout) { - headers[SADB_EXT_LIFETIME_HARD] = p; - export_lifetime(&p, sa, 0); - } + if (sa->tdb_exp_allocations || sa->tdb_exp_bytes || + sa->tdb_exp_first_use || sa->tdb_exp_timeout) + { + headers[SADB_EXT_LIFETIME_HARD] = p; + export_lifetime(&p, sa, PFKEYV2_LIFETIME_HARD); + } - headers[SADB_EXT_ADDRESS_SRC] = p; - export_address(&p, (struct sockaddr *)&sa->tdb_src); + /* Export TDB source address */ + headers[SADB_EXT_ADDRESS_SRC] = p; + export_address(&p, (struct sockaddr *) &sa->tdb_src); - headers[SADB_EXT_ADDRESS_DST] = p; - export_address(&p, (struct sockaddr *)&sa->tdb_dst); + /* Export TDB destination address */ + headers[SADB_EXT_ADDRESS_DST] = p; + export_address(&p, (struct sockaddr *) &sa->tdb_dst); - if (SA_LEN(&sa->tdb_proxy.sa)) { - headers[SADB_EXT_ADDRESS_PROXY] = p; - export_address(&p, (struct sockaddr *)&sa->tdb_proxy); - } + /* Export TDB proxy address, if present */ + if (SA_LEN(&sa->tdb_proxy.sa)) + { + headers[SADB_EXT_ADDRESS_PROXY] = p; + export_address(&p, (struct sockaddr *) &sa->tdb_proxy); + } - if (sa->tdb_srcid_len) { - headers[SADB_EXT_IDENTITY_SRC] = p; - export_identity(&p, sa, 0); - } + /* Export source identity, if present */ + if (sa->tdb_srcid_len) + { + headers[SADB_EXT_IDENTITY_SRC] = p; + export_identity(&p, sa, PFKEYV2_IDENTITY_SRC); + } - if (sa->tdb_dstid_len) { - headers[SADB_EXT_IDENTITY_DST] = p; - export_identity(&p, sa, 1); - } + /* Export destination identity, if present */ + if (sa->tdb_dstid_len) + { + headers[SADB_EXT_IDENTITY_DST] = p; + export_identity(&p, sa, PFKEYV2_IDENTITY_DST); + } - rval = 0; + /* XXX Export keys ? */ -ret: - return rval; -} + rval = 0; -struct dump_state { - struct sadb_msg *sadb_msg; - struct socket *socket; -}; + ret: + return rval; +} +/* + * Dump a TDB. + */ int pfkeyv2_dump_walker(struct tdb *sa, void *state) { - struct dump_state *dump_state = (struct dump_state *)state; - void *headers[SADB_EXT_MAX+1], *buffer; - int rval; + struct dump_state *dump_state = (struct dump_state *) state; + void *headers[SADB_EXT_MAX+1], *buffer; + int rval; - if (!dump_state->sadb_msg->sadb_msg_satype || - (sa->tdb_satype == dump_state->sadb_msg->sadb_msg_satype)) { - bzero(headers, sizeof(headers)); - headers[0] = (void *)dump_state->sadb_msg; - if ((rval = pfkeyv2_get(sa, headers, &buffer)) != 0) - return rval; - rval = pfkeyv2_sendmessage(headers, PFKEYV2_SENDMESSAGE_UNICAST, - dump_state->socket, 0, 0); - free(buffer, M_PFKEY); - if (rval) - return rval; - } + /* If not satype was specified, dump all TDBs */ + if (!dump_state->sadb_msg->sadb_msg_satype || + (sa->tdb_satype == dump_state->sadb_msg->sadb_msg_satype)) + { + bzero(headers, sizeof(headers)); + headers[0] = (void *) dump_state->sadb_msg; + + /* Get the information from the TDB to a PFKEYv2 message */ + if ((rval = pfkeyv2_get(sa, headers, &buffer)) != 0) + return rval; + + /* Send the message to the specified socket */ + rval = pfkeyv2_sendmessage(headers, PFKEYV2_SENDMESSAGE_UNICAST, + dump_state->socket, 0, 0); - return 0; + free(buffer, M_PFKEY); + if (rval) + return rval; + } + + return 0; } +/* + * Delete an SA. + */ int pfkeyv2_flush_walker(struct tdb *sa, void *satype_vp) { - if (!(*((u_int8_t *)satype_vp)) || - sa->tdb_satype == *((u_int8_t *)satype_vp)) - tdb_delete(sa, 0, 0); - return 0; + if (!(*((u_int8_t *) satype_vp)) || + sa->tdb_satype == *((u_int8_t *) satype_vp)) + tdb_delete(sa, 0, 0); + + return 0; } +/* + * Convert between SATYPEs and IPsec protocols, taking into consideration + * sysctl variables enabling/disabling ESP/AH and the presence of the old + * IPsec transforms. + */ int pfkeyv2_get_proto_alg(u_int8_t satype, u_int8_t *sproto, int *alg) { - switch (satype) { - case SADB_SATYPE_AH: - case SADB_X_SATYPE_AH_OLD: - if (!ah_enable) - return EOPNOTSUPP; - *sproto = IPPROTO_AH; - if(alg != NULL) - *alg = satype == SADB_SATYPE_AH ? XF_NEW_AH : XF_OLD_AH; - break; - - case SADB_SATYPE_ESP: - case SADB_X_SATYPE_ESP_OLD: - if (!esp_enable) - return EOPNOTSUPP; - *sproto = IPPROTO_ESP; - if(alg != NULL) - *alg = satype == SADB_SATYPE_ESP ? XF_NEW_ESP : XF_OLD_ESP; - break; - - case SADB_X_SATYPE_IPIP: - *sproto = IPPROTO_IPIP; - if (alg != NULL) - *alg = XF_IP4; - break; + switch (satype) + { + case SADB_SATYPE_AH: + case SADB_X_SATYPE_AH_OLD: + if (!ah_enable) + return EOPNOTSUPP; + + *sproto = IPPROTO_AH; + + if(alg != NULL) + *alg = satype == SADB_SATYPE_AH ? XF_NEW_AH : XF_OLD_AH; + + break; + + case SADB_SATYPE_ESP: + case SADB_X_SATYPE_ESP_OLD: + if (!esp_enable) + return EOPNOTSUPP; + + *sproto = IPPROTO_ESP; + + if(alg != NULL) + *alg = satype == SADB_SATYPE_ESP ? XF_NEW_ESP : XF_OLD_ESP; + + break; + + case SADB_X_SATYPE_IPIP: + *sproto = IPPROTO_IPIP; + + if (alg != NULL) + *alg = XF_IP4; + + break; #ifdef TCP_SIGNATURE - case SADB_X_SATYPE_TCPSIGNATURE: - *sproto = IPPROTO_TCP; - if (alg != NULL) - *alg = XF_TCPSIGNATURE; - break; + case SADB_X_SATYPE_TCPSIGNATURE: + *sproto = IPPROTO_TCP; + + if (alg != NULL) + *alg = XF_TCPSIGNATURE; + + break; #endif /* TCP_SIGNATURE */ - default: /* Nothing else supported */ - return EOPNOTSUPP; - } - return 0; + default: /* Nothing else supported */ + return EOPNOTSUPP; + } + + return 0; } +/* + * Handle all messages from userland to kernel. + */ int pfkeyv2_send(struct socket *socket, void *message, int len) { - void *headers[SADB_EXT_MAX + 1]; - int i, j, rval = 0, mode = PFKEYV2_SENDMESSAGE_BROADCAST, delflag = 0, s; - struct pfkeyv2_socket *pfkeyv2_socket, *so = NULL; - void *freeme = NULL, *bckptr = NULL; - struct tdb sa, *sa2 = NULL; - struct flow *flow = NULL; - - bzero(headers, sizeof(headers)); - - for (pfkeyv2_socket = pfkeyv2_sockets; - pfkeyv2_socket; - pfkeyv2_socket = pfkeyv2_socket->next) - if (pfkeyv2_socket->socket == socket) - break; - - if (!pfkeyv2_socket) { - rval = EINVAL; - goto ret; - } + int i, j, rval = 0, mode = PFKEYV2_SENDMESSAGE_BROADCAST, delflag = 0, s; - if (npromisc) { - struct mbuf *packet; + struct pfkeyv2_socket *pfkeyv2_socket, *so = NULL; - if (!(freeme = malloc(sizeof(struct sadb_msg) + len, M_PFKEY, - M_DONTWAIT))) { - rval = ENOMEM; - goto ret; + void *freeme = NULL, *bckptr = NULL; + void *headers[SADB_EXT_MAX + 1]; + + union sockaddr_union *sunionp; + + struct tdb sa, *sa2 = NULL; + struct flow *flow = NULL; + + struct sadb_msg *smsg; + struct sadb_spirange *sprng; + struct sadb_sa *ssa; + struct sadb_supported *ssup; + + /* Verify that we received this over a legitimate pfkeyv2 socket */ + bzero(headers, sizeof(headers)); + + for (pfkeyv2_socket = pfkeyv2_sockets; + pfkeyv2_socket; + pfkeyv2_socket = pfkeyv2_socket->next) + if (pfkeyv2_socket->socket == socket) + break; + + if (!pfkeyv2_socket) + { + rval = EINVAL; + goto ret; } - bzero(freeme, sizeof(struct sadb_msg)); - ((struct sadb_msg *)freeme)->sadb_msg_version = PF_KEY_V2; - ((struct sadb_msg *)freeme)->sadb_msg_type = SADB_X_PROMISC; - ((struct sadb_msg *)freeme)->sadb_msg_len = - (sizeof(struct sadb_msg) + len) / sizeof(uint64_t); - ((struct sadb_msg *)freeme)->sadb_msg_seq = curproc->p_pid; + /* If we have any promiscuous listeners, send them a copy of the message */ + if (npromisc) + { + struct mbuf *packet; + + if (!(freeme = malloc(sizeof(struct sadb_msg) + len, M_PFKEY, + M_DONTWAIT))) + { + rval = ENOMEM; + goto ret; + } + + /* Initialize encapsulating header */ + bzero(freeme, sizeof(struct sadb_msg)); + smsg = (struct sadb_msg *) freeme; + smsg->sadb_msg_version = PF_KEY_V2; + smsg->sadb_msg_type = SADB_X_PROMISC; + smsg->sadb_msg_len = (sizeof(struct sadb_msg) + len) / + sizeof(uint64_t); + smsg->sadb_msg_seq = curproc->p_pid; + + bcopy(message, freeme + sizeof(struct sadb_msg), len); + + /* Convert to mbuf chain */ + if ((rval = pfdatatopacket(freeme, sizeof(struct sadb_msg) + len, + &packet)) != 0) + goto ret; + + /* Send to all promiscuous listeners */ + for (so = pfkeyv2_sockets; so; so = so->next) + if (so->flags & PFKEYV2_SOCKETFLAGS_PROMISC) + pfkey_sendup(so->socket, packet, 1); + + /* Paranoid */ + m_zero(packet); + m_freem(packet); - bcopy(message, freeme + sizeof(struct sadb_msg), len); + /* Even more paranoid */ + bzero(freeme, sizeof(struct sadb_msg) + len); + free(freeme, M_PFKEY); + freeme = NULL; + } - if ((rval = pfdatatopacket(freeme, sizeof(struct sadb_msg) + len, - &packet)) != 0) + /* Validate message format */ + if ((rval = pfkeyv2_parsemessage(message, len, headers)) != 0) goto ret; + + smsg = (struct sadb_msg *) headers[0]; + switch(smsg->sadb_msg_type) + { + case SADB_GETSPI: /* Reserve an SPI */ + bzero(&sa, sizeof(struct tdb)); + + sa.tdb_satype = smsg->sadb_msg_satype; + if ((rval = pfkeyv2_get_proto_alg(sa.tdb_satype, + &sa.tdb_sproto, 0))) + goto ret; + + import_address((struct sockaddr *) &sa.tdb_src, + headers[SADB_EXT_ADDRESS_SRC]); + import_address((struct sockaddr *) &sa.tdb_dst, + headers[SADB_EXT_ADDRESS_DST]); + + /* Find an unused SA identifier */ + sprng = (struct sadb_spirange *) headers[SADB_EXT_SPIRANGE]; + sa.tdb_spi = reserve_spi(sprng->sadb_spirange_min, + sprng->sadb_spirange_max, + &sa.tdb_src, &sa.tdb_dst, + sa.tdb_sproto, &rval); + if (sa.tdb_spi == 0) + goto ret; + + /* Send a message back telling what the SA (the SPI really) is */ + if (!(freeme = malloc(sizeof(struct sadb_sa), M_PFKEY, + M_DONTWAIT))) + { + rval = ENOMEM; + goto ret; + } - for (so = pfkeyv2_sockets; so; so = so->next) - if (so->flags & PFKEYV2_SOCKETFLAGS_PROMISC) - pfkey_sendup(so->socket, packet, 1); + bzero(freeme, sizeof(struct sadb_sa)); + headers[SADB_EXT_SPIRANGE] = NULL; + headers[SADB_EXT_SA] = freeme; + bckptr = freeme; - m_zero(packet); - m_freem(packet); + /* We really only care about the SPI, but we'll export the SA */ + export_sa((void **) &bckptr, &sa); + break; - bzero(freeme, sizeof(struct sadb_msg) + len); - free(freeme, M_PFKEY); - freeme = NULL; - } + case SADB_UPDATE: + ssa = (struct sadb_sa *) headers[SADB_EXT_SA]; + sunionp = (union sockaddr_union *) (headers[SADB_EXT_ADDRESS_DST] + + sizeof(struct sadb_address)); + s = spltdb(); - if ((rval = pfkeyv2_parsemessage(message, len, headers)) != 0) - goto ret; + /* Find TDB */ + sa2 = gettdb(ssa->sadb_sa_spi, sunionp, + SADB_GETSPROTO(smsg->sadb_msg_satype)); - switch(((struct sadb_msg *)headers[0])->sadb_msg_type) { - case SADB_GETSPI: - bzero(&sa, sizeof(struct tdb)); + /* If there's no such SA, we're done */ + if (sa2 == NULL) + { + rval = ESRCH; + goto splxret; + } - sa.tdb_satype = ((struct sadb_msg *)headers[0])->sadb_msg_satype; - if ((rval = pfkeyv2_get_proto_alg(sa.tdb_satype, &sa.tdb_sproto, 0))) - goto ret; + /* If this is a reserved SA */ + if (sa2->tdb_flags & TDBF_INVALID) + { + struct tdb *newsa; + struct ipsecinit ii; + int alg; + + /* Create new TDB */ + MALLOC(freeme, struct tdb *, sizeof(struct tdb), + M_TDB, M_WAITOK); + bzero(freeme, sizeof(struct tdb)); + bzero(&ii, sizeof(struct ipsecinit)); + + newsa = (struct tdb *) freeme; + newsa->tdb_satype = smsg->sadb_msg_satype; + + if ((rval = pfkeyv2_get_proto_alg(newsa->tdb_satype, + &newsa->tdb_sproto, &alg))) + goto splxret; + + /* Initialize SA */ + import_sa(newsa, headers[SADB_EXT_SA], &ii); + import_address((struct sockaddr *) &newsa->tdb_src, + headers[SADB_EXT_ADDRESS_SRC]); + import_address((struct sockaddr *) &newsa->tdb_dst, + headers[SADB_EXT_ADDRESS_DST]); + import_address((struct sockaddr *) &newsa->tdb_proxy, + headers[SADB_EXT_ADDRESS_PROXY]); + import_lifetime(newsa, headers[SADB_EXT_LIFETIME_CURRENT], + PFKEYV2_LIFETIME_CURRENT); + import_lifetime(newsa, headers[SADB_EXT_LIFETIME_SOFT], + PFKEYV2_LIFETIME_SOFT); + import_lifetime(newsa, headers[SADB_EXT_LIFETIME_HARD], + PFKEYV2_LIFETIME_HARD); + import_key(&ii, headers[SADB_EXT_KEY_AUTH], + PFKEYV2_AUTHENTICATION_KEY); + import_key(&ii, headers[SADB_EXT_KEY_ENCRYPT], + PFKEYV2_ENCRYPTION_KEY); + import_identity(newsa, headers[SADB_EXT_IDENTITY_SRC], + PFKEYV2_IDENTITY_SRC); + import_identity(newsa, headers[SADB_EXT_IDENTITY_DST], + PFKEYV2_IDENTITY_DST); + + headers[SADB_EXT_KEY_AUTH] = NULL; + headers[SADB_EXT_KEY_ENCRYPT] = NULL; + + rval = tdb_init(newsa, alg, &ii); + if (rval) + { + rval = EINVAL; + tdb_delete(freeme, 0, TDBEXP_TIMEOUT); + freeme = NULL; + goto splxret; + } - import_address((struct sockaddr *)&sa.tdb_src, - headers[SADB_EXT_ADDRESS_SRC]); - import_address((struct sockaddr *)&sa.tdb_dst, - headers[SADB_EXT_ADDRESS_DST]); + newsa->tdb_cur_allocations = sa2->tdb_cur_allocations; - sa.tdb_spi = reserve_spi(((struct sadb_spirange *)headers[SADB_EXT_SPIRANGE])->sadb_spirange_min, ((struct sadb_spirange *)headers[SADB_EXT_SPIRANGE])->sadb_spirange_max, &sa.tdb_src, &sa.tdb_dst, sa.tdb_sproto, &rval); - if (sa.tdb_spi == 0) - goto ret; + /* Copy outgoing flows and ACL */ + newsa->tdb_flow = sa2->tdb_flow; + newsa->tdb_access = sa2->tdb_access; - if (!(freeme = malloc(sizeof(struct sadb_sa), M_PFKEY, M_DONTWAIT))) { - rval = ENOMEM; - goto ret; - } + /* Fix flow backpointers to the TDB */ + for (flow = newsa->tdb_flow; + flow != NULL; + flow = flow->flow_next) + flow->flow_sa = newsa; - bzero(freeme, sizeof(struct sadb_sa)); - headers[SADB_EXT_SPIRANGE] = NULL; - headers[SADB_EXT_SA] = freeme; - bckptr = freeme; - export_sa((void **) &bckptr, &sa); - break; - - case SADB_UPDATE: - s = spltdb(); - sa2 = gettdb(((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_spi, - (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] + - sizeof(struct sadb_address)), - SADB_GETSPROTO(((struct sadb_msg *)headers[0])->sadb_msg_satype)); - if (sa2 == NULL) { - rval = ESRCH; - goto splxret; - } - - if (sa2->tdb_flags & TDBF_INVALID) { - struct tdb *newsa; - struct ipsecinit ii; - int alg; - - MALLOC(freeme, struct tdb *, sizeof(struct tdb), M_TDB, M_WAITOK); - bzero(freeme, sizeof(struct tdb)); - newsa = (struct tdb *)freeme; - bzero(&ii, sizeof(struct ipsecinit)); - - newsa->tdb_satype = ((struct sadb_msg *)headers[0])->sadb_msg_satype; - if ((rval = pfkeyv2_get_proto_alg(newsa->tdb_satype, - &newsa->tdb_sproto, &alg))) - goto splxret; - - import_sa(newsa, headers[SADB_EXT_SA], &ii); - import_address((struct sockaddr *)&newsa->tdb_src, - headers[SADB_EXT_ADDRESS_SRC]); - import_address((struct sockaddr *)&newsa->tdb_dst, - headers[SADB_EXT_ADDRESS_DST]); - import_address((struct sockaddr *)&newsa->tdb_proxy, - headers[SADB_EXT_ADDRESS_PROXY]); - - import_lifetime(newsa, headers[SADB_EXT_LIFETIME_CURRENT], 2); - import_lifetime(newsa, headers[SADB_EXT_LIFETIME_SOFT], 1); - import_lifetime(newsa, headers[SADB_EXT_LIFETIME_HARD], 0); - import_key(&ii, headers[SADB_EXT_KEY_AUTH], 1); - import_key(&ii, headers[SADB_EXT_KEY_ENCRYPT], 0); - import_identity(newsa, headers[SADB_EXT_IDENTITY_SRC], 0); - import_identity(newsa, headers[SADB_EXT_IDENTITY_DST], 1); - - headers[SADB_EXT_KEY_AUTH] = NULL; - headers[SADB_EXT_KEY_ENCRYPT] = NULL; - - rval = tdb_init(newsa, alg, &ii); - if (rval) { - rval = EINVAL; - tdb_delete(freeme, 0, TDBEXP_TIMEOUT); - freeme = NULL; - goto splxret; - } - newsa->tdb_flow = sa2->tdb_flow; - newsa->tdb_cur_allocations = sa2->tdb_cur_allocations; - for (flow = newsa->tdb_flow; flow != NULL; flow = flow->flow_next) - flow->flow_sa = newsa; - sa2->tdb_flow = NULL; - - tdb_delete(sa2, 0, TDBEXP_TIMEOUT); - puttdb((struct tdb *) freeme); - sa2 = freeme = NULL; - } else { - if (headers[SADB_EXT_ADDRESS_PROXY] || - headers[SADB_EXT_KEY_AUTH] || - headers[SADB_EXT_KEY_ENCRYPT] || - headers[SADB_EXT_IDENTITY_SRC] || - headers[SADB_EXT_IDENTITY_DST] || - headers[SADB_EXT_SENSITIVITY]) { - rval = EINVAL; - goto splxret; - } + for (flow = newsa->tdb_access; + flow != NULL; + flow = flow->flow_next) + flow->flow_sa = newsa; - import_sa(sa2, headers[SADB_EXT_SA], NULL); - import_lifetime(sa2, headers[SADB_EXT_LIFETIME_CURRENT], 2); - import_lifetime(sa2, headers[SADB_EXT_LIFETIME_SOFT], 1); - import_lifetime(sa2, headers[SADB_EXT_LIFETIME_HARD], 0); - } - splx(s); - break; - - case SADB_ADD: - s = spltdb(); - sa2 = gettdb(((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_spi, - (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] + - sizeof(struct sadb_address)), - SADB_GETSPROTO(((struct sadb_msg *)headers[0])->sadb_msg_satype)); - if (sa2 != NULL) { - rval = EEXIST; - goto splxret; - } - if (((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_state != - SADB_SASTATE_MATURE) { - rval = EINVAL; - goto splxret; - } + sa2->tdb_access = NULL; + sa2->tdb_flow = NULL; + + /* Delete old version of the SA, insert new one */ + tdb_delete(sa2, 0, TDBEXP_TIMEOUT); + puttdb((struct tdb *) freeme); + sa2 = freeme = NULL; + } + else + { + /* + * The SA is already initialized, so we're only allowed to + * change lifetimes and some other information; we're + * not allowed to change keys, addresses or identities. + */ + if (headers[SADB_EXT_ADDRESS_PROXY] || + headers[SADB_EXT_KEY_AUTH] || + headers[SADB_EXT_KEY_ENCRYPT] || + headers[SADB_EXT_IDENTITY_SRC] || + headers[SADB_EXT_IDENTITY_DST] || + headers[SADB_EXT_SENSITIVITY]) + { + rval = EINVAL; + goto splxret; + } - MALLOC(freeme, struct tdb *, sizeof(struct tdb), M_TDB, M_WAITOK); - bzero(freeme, sizeof(struct tdb)); + import_sa(sa2, headers[SADB_EXT_SA], NULL); + import_lifetime(sa2, headers[SADB_EXT_LIFETIME_CURRENT], + PFKEYV2_LIFETIME_CURRENT); + import_lifetime(sa2, headers[SADB_EXT_LIFETIME_SOFT], + PFKEYV2_LIFETIME_SOFT); + import_lifetime(sa2, headers[SADB_EXT_LIFETIME_HARD], + PFKEYV2_LIFETIME_HARD); + } - { - struct tdb *newsa = (struct tdb *) freeme; - struct ipsecinit ii; - int alg; - - bzero(&ii, sizeof(struct ipsecinit)); - - newsa->tdb_satype = ((struct sadb_msg *)headers[0])->sadb_msg_satype; - if ((rval = pfkeyv2_get_proto_alg(newsa->tdb_satype, - &newsa->tdb_sproto, &alg))) - goto splxret; - - import_sa(newsa, headers[SADB_EXT_SA], &ii); - import_address((struct sockaddr *)&newsa->tdb_src, - headers[SADB_EXT_ADDRESS_SRC]); - import_address((struct sockaddr *)&newsa->tdb_dst, - headers[SADB_EXT_ADDRESS_DST]); - import_address((struct sockaddr *)&newsa->tdb_proxy, - headers[SADB_EXT_ADDRESS_PROXY]); - - import_lifetime(newsa, headers[SADB_EXT_LIFETIME_CURRENT], 2); - import_lifetime(newsa, headers[SADB_EXT_LIFETIME_SOFT], 1); - import_lifetime(newsa, headers[SADB_EXT_LIFETIME_HARD], 0); - import_key(&ii, headers[SADB_EXT_KEY_AUTH], 1); - import_key(&ii, headers[SADB_EXT_KEY_ENCRYPT], 0); - import_identity(newsa, headers[SADB_EXT_IDENTITY_SRC], 0); - import_identity(newsa, headers[SADB_EXT_IDENTITY_DST], 1); - - headers[SADB_EXT_KEY_AUTH] = NULL; - headers[SADB_EXT_KEY_ENCRYPT] = NULL; - - rval = tdb_init(newsa, alg, &ii); - if (rval) { - rval = EINVAL; - tdb_delete(freeme, 0, TDBEXP_TIMEOUT); - freeme = NULL; - goto splxret; - } - } + splx(s); + break; - puttdb((struct tdb *)freeme); - splx(s); - freeme = NULL; - break; - - case SADB_DELETE: - s = spltdb(); - sa2 = gettdb(((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_spi, - (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] + - sizeof(struct sadb_address)), - SADB_GETSPROTO(((struct sadb_msg *)headers[0])->sadb_msg_satype)); - if (sa2 == NULL) { - rval = ESRCH; - goto splxret; - } + case SADB_ADD: + ssa = (struct sadb_sa *) headers[SADB_EXT_SA]; + sunionp = (union sockaddr_union *) (headers[SADB_EXT_ADDRESS_DST] + + sizeof(struct sadb_address)); + + s = spltdb(); + + sa2 = gettdb(ssa->sadb_sa_spi, sunionp, + SADB_GETSPROTO(smsg->sadb_msg_satype)); + + /* We can't add an existing SA! */ + if (sa2 != NULL) + { + rval = EEXIST; + goto splxret; + } + + /* We can only add "mature" SAs */ + if (ssa->sadb_sa_state != SADB_SASTATE_MATURE) + { + rval = EINVAL; + goto splxret; + } + + /* Allocate and initialize new TDB */ + MALLOC(freeme, struct tdb *, sizeof(struct tdb), M_TDB, M_WAITOK); + bzero(freeme, sizeof(struct tdb)); + + { + struct tdb *newsa = (struct tdb *) freeme; + struct ipsecinit ii; + int alg; + + bzero(&ii, sizeof(struct ipsecinit)); + + newsa->tdb_satype = smsg->sadb_msg_satype; + if ((rval = pfkeyv2_get_proto_alg(newsa->tdb_satype, + &newsa->tdb_sproto, &alg))) + goto splxret; + + import_sa(newsa, headers[SADB_EXT_SA], &ii); + import_address((struct sockaddr *) &newsa->tdb_src, + headers[SADB_EXT_ADDRESS_SRC]); + import_address((struct sockaddr *) &newsa->tdb_dst, + headers[SADB_EXT_ADDRESS_DST]); + import_address((struct sockaddr *) &newsa->tdb_proxy, + headers[SADB_EXT_ADDRESS_PROXY]); + + import_lifetime(newsa, headers[SADB_EXT_LIFETIME_CURRENT], + PFKEYV2_LIFETIME_CURRENT); + import_lifetime(newsa, headers[SADB_EXT_LIFETIME_SOFT], + PFKEYV2_LIFETIME_SOFT); + import_lifetime(newsa, headers[SADB_EXT_LIFETIME_HARD], + PFKEYV2_LIFETIME_HARD); + + import_key(&ii, headers[SADB_EXT_KEY_AUTH], + PFKEYV2_AUTHENTICATION_KEY); + import_key(&ii, headers[SADB_EXT_KEY_ENCRYPT], + PFKEYV2_ENCRYPTION_KEY); + + import_identity(newsa, headers[SADB_EXT_IDENTITY_SRC], + PFKEYV2_IDENTITY_SRC); + import_identity(newsa, headers[SADB_EXT_IDENTITY_DST], + PFKEYV2_IDENTITY_DST); + + headers[SADB_EXT_KEY_AUTH] = NULL; + headers[SADB_EXT_KEY_ENCRYPT] = NULL; + + rval = tdb_init(newsa, alg, &ii); + if (rval) + { + rval = EINVAL; + tdb_delete(freeme, 0, TDBEXP_TIMEOUT); + freeme = NULL; + goto splxret; + } + } + + /* Add TDB in table */ + puttdb((struct tdb *) freeme); + + splx(s); + + freeme = NULL; + break; + + case SADB_DELETE: + ssa = (struct sadb_sa *) headers[SADB_EXT_SA]; + sunionp = (union sockaddr_union *) (headers[SADB_EXT_ADDRESS_DST] + + sizeof(struct sadb_address)); + s = spltdb(); + + sa2 = gettdb(ssa->sadb_sa_spi, sunionp, + SADB_GETSPROTO(smsg->sadb_msg_satype)); + if (sa2 == NULL) + { + rval = ESRCH; + goto splxret; + } - tdb_delete(sa2, ((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_flags & SADB_X_SAFLAGS_CHAINDEL, TDBEXP_TIMEOUT); - splx(s); - sa2 = NULL; - break; - - case SADB_GET: - s = spltdb(); - sa2 = gettdb(((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_spi, - (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] + - sizeof(struct sadb_address)), - SADB_GETSPROTO(((struct sadb_msg *)headers[0])->sadb_msg_satype)); - if (sa2 == NULL) { - rval = ESRCH; - goto splxret; - } + tdb_delete(sa2, ssa->sadb_sa_flags & SADB_X_SAFLAGS_CHAINDEL, + TDBEXP_TIMEOUT); + + splx(s); + + sa2 = NULL; + break; + + case SADB_GET: + ssa = (struct sadb_sa *) headers[SADB_EXT_SA]; + sunionp = (union sockaddr_union *) (headers[SADB_EXT_ADDRESS_DST] + + sizeof(struct sadb_address)); + s = spltdb(); + + sa2 = gettdb(ssa->sadb_sa_spi, sunionp, + SADB_GETSPROTO(smsg->sadb_msg_satype)); + if (sa2 == NULL) + { + rval = ESRCH; + goto splxret; + } - rval = pfkeyv2_get(sa2, headers, &freeme); - if (rval) - mode = PFKEYV2_SENDMESSAGE_UNICAST; - splx(s); - break; + rval = pfkeyv2_get(sa2, headers, &freeme); + if (rval) + mode = PFKEYV2_SENDMESSAGE_UNICAST; - case SADB_REGISTER: - pfkeyv2_socket->flags |= PFKEYV2_SOCKETFLAGS_REGISTERED; - nregistered++; + splx(s); - i = sizeof(struct sadb_supported) + sizeof(ealgs) + sizeof(aalgs); + break; - if (!(freeme = malloc(i, M_PFKEY, M_DONTWAIT))) { - rval = ENOMEM; - goto ret; - } + case SADB_REGISTER: + pfkeyv2_socket->flags |= PFKEYV2_SOCKETFLAGS_REGISTERED; + nregistered++; + + i = sizeof(struct sadb_supported) + sizeof(ealgs) + sizeof(aalgs); + + if (!(freeme = malloc(i, M_PFKEY, M_DONTWAIT))) + { + rval = ENOMEM; + goto ret; + } - /* Keep track what this socket has registered for */ - pfkeyv2_socket->registration |= (1 << ((struct sadb_msg *)message)->sadb_msg_satype); + /* Keep track what this socket has registered for */ + pfkeyv2_socket->registration |= (1 << ((struct sadb_msg *)message)->sadb_msg_satype); - bzero(freeme, i); + bzero(freeme, i); - ((struct sadb_supported *)freeme)->sadb_supported_len = - i / sizeof(uint64_t); - ((struct sadb_supported *)freeme)->sadb_supported_nauth = - sizeof(aalgs) / sizeof(struct sadb_alg); - ((struct sadb_supported *)freeme)->sadb_supported_nencrypt = - sizeof(ealgs) / sizeof(struct sadb_alg); + ssup = (struct sadb_supported *) freeme; + ssup->sadb_supported_len = i / sizeof(uint64_t); + ssup->sadb_supported_nauth = sizeof(aalgs) / + sizeof(struct sadb_alg); + ssup->sadb_supported_nencrypt = sizeof(ealgs) / + sizeof(struct sadb_alg); - { - void *p = freeme + sizeof(struct sadb_supported); + { + void *p = freeme + sizeof(struct sadb_supported); - bcopy(&aalgs[0], p, sizeof(aalgs)); - p += sizeof(aalgs); - bcopy(&ealgs[0], p, sizeof(ealgs)); - } + bcopy(&aalgs[0], p, sizeof(aalgs)); + p += sizeof(aalgs); + bcopy(&ealgs[0], p, sizeof(ealgs)); + } - headers[SADB_EXT_SUPPORTED] = freeme; - break; + headers[SADB_EXT_SUPPORTED] = freeme; + break; - case SADB_ACQUIRE: - rval = 0; - break; + case SADB_ACQUIRE: + case SADB_EXPIRE: + /* Nothing to handle */ + rval = 0; + break; - case SADB_EXPIRE: - rval = 0; - break; + case SADB_FLUSH: + rval = 0; - case SADB_FLUSH: - { - union sockaddr_union dst; - rval = 0; - switch(((struct sadb_msg *)headers[0])->sadb_msg_satype) - { - case SADB_SATYPE_UNSPEC: - case SADB_SATYPE_AH: - case SADB_SATYPE_ESP: - case SADB_X_SATYPE_AH_OLD: - case SADB_X_SATYPE_ESP_OLD: - case SADB_X_SATYPE_IPIP: + switch(smsg->sadb_msg_satype) + { + case SADB_SATYPE_UNSPEC: + case SADB_X_SATYPE_BYPASS: + { + union sockaddr_union dst; + /* XXX IPv4 dependency -- does it matter though ? */ + dst.sin.sin_family = AF_INET; + dst.sin.sin_len = sizeof(struct sockaddr_in); + dst.sin.sin_addr.s_addr = INADDR_ANY; + + s = spltdb(); + + sa2 = gettdb(SPI_LOCAL_USE, &dst, IPPROTO_IP); + if (sa2 != NULL) + tdb_delete(sa2, 0, 0); + + if (smsg->sadb_msg_satype == SADB_X_SATYPE_BYPASS) + break; + /* for SADB_SATYPE_UNSPEC, fall through */ + } + + case SADB_SATYPE_AH: + case SADB_SATYPE_ESP: + case SADB_X_SATYPE_AH_OLD: + case SADB_X_SATYPE_ESP_OLD: + case SADB_X_SATYPE_IPIP: #ifdef TCP_SIGNATURE - case SADB_X_SATYPE_TCPSIGNATURE: + case SADB_X_SATYPE_TCPSIGNATURE: #endif /* TCP_SIGNATURE */ - s = spltdb(); - tdb_walk(pfkeyv2_flush_walker, - (u_int8_t *)&(((struct sadb_msg *)headers[0])->sadb_msg_satype)); - break; - case SADB_X_SATYPE_BYPASS: - break; - default: - rval = EINVAL; /* Unknown/unsupported type */ - } + s = spltdb(); - switch(((struct sadb_msg *)headers[0])->sadb_msg_satype) - { - case SADB_SATYPE_UNSPEC: - case SADB_X_SATYPE_BYPASS: - /* XXX IPv4 dependency -- does it matter though ? */ - dst.sin.sin_family = AF_INET; - dst.sin.sin_len = sizeof(struct sockaddr_in); - dst.sin.sin_addr.s_addr = INADDR_ANY; - s = spltdb(); - sa2 = gettdb(SPI_LOCAL_USE, &dst, IPPROTO_IP); - if (sa2 != NULL) - tdb_delete(sa2, 0, 0); - default: - } + tdb_walk(pfkeyv2_flush_walker, + (u_int8_t *) &(smsg->sadb_msg_satype)); + break; - if (rval == 0) - goto splxret; - break; - } + default: + rval = EINVAL; /* Unknown/unsupported type */ + } - case SADB_DUMP: - { - struct dump_state dump_state; - dump_state.sadb_msg = (struct sadb_msg *)headers[0]; - dump_state.socket = socket; - - if (!(rval = tdb_walk(pfkeyv2_dump_walker, &dump_state))) - goto realret; + if (rval == 0) + goto splxret; - if ((rval == ENOMEM) || (rval == ENOBUFS)) - rval = 0; - } - break; + break; - - case SADB_X_DELFLOW: - delflag = 1; /* fall through */ - - case SADB_X_ADDFLOW: /* XXX This is highly INET dependent */ - { - struct sockaddr_encap encapdst, encapgw, encapnetmask; - struct flow *flow2 = NULL, *old_flow = NULL, *old_flow2 = NULL; - union sockaddr_union *src, *dst, *srcmask, *dstmask; - u_int8_t sproto = 0, replace; - struct rtentry *rt; - - /* - * SADB_X_SAFLAGS_REPLACEFLOW set means we should remove any - * potentially conflicting flow while we are adding this new one. - */ - replace = ((struct sadb_sa *) headers[SADB_EXT_SA])->sadb_sa_flags & - SADB_X_SAFLAGS_REPLACEFLOW; - if (replace && delflag) + case SADB_DUMP: { - rval = EINVAL; - goto ret; + struct dump_state dump_state; + dump_state.sadb_msg = (struct sadb_msg *) headers[0]; + dump_state.socket = socket; + + if (!(rval = tdb_walk(pfkeyv2_dump_walker, &dump_state))) + goto realret; + + if ((rval == ENOMEM) || (rval == ENOBUFS)) + rval = 0; } - src = (union sockaddr_union *) (headers[SADB_X_EXT_SRC_FLOW] + sizeof(struct sadb_address)); - dst = (union sockaddr_union *) (headers[SADB_X_EXT_DST_FLOW] + sizeof(struct sadb_address)); - srcmask = (union sockaddr_union *) (headers[SADB_X_EXT_SRC_MASK] + sizeof(struct sadb_address)); - dstmask = (union sockaddr_union *) (headers[SADB_X_EXT_DST_MASK] + sizeof(struct sadb_address)); - - /* - * Check that all the address families match. We know they are - * valid and supported because pfkeyv2_parsemessage() checked that. - */ - if ((src->sa.sa_family != dst->sa.sa_family) || - (src->sa.sa_family != srcmask->sa.sa_family) || - (src->sa.sa_family != dstmask->sa.sa_family)) + break; + + + case SADB_X_DELFLOW: + delflag = 1; /* fall through */ + + case SADB_X_ADDFLOW: { - rval = EINVAL; - goto splxret; - } + struct sockaddr_encap encapdst, encapgw, encapnetmask; + struct flow *flow2 = NULL, *old_flow = NULL, *old_flow2 = NULL; + union sockaddr_union *src, *dst, *srcmask, *dstmask; + u_int8_t sproto = 0, replace; + struct rtentry *rt; + + ssa = (struct sadb_sa *) headers[SADB_EXT_SA]; + sunionp = (union sockaddr_union *) (headers[SADB_EXT_ADDRESS_DST] + + sizeof(struct sadb_address)); + + /* + * SADB_X_SAFLAGS_REPLACEFLOW set means we should remove any + * potentially conflicting flow while we are adding this new one. + */ + replace = ssa->sadb_sa_flags & SADB_X_SAFLAGS_REPLACEFLOW; + if (replace && delflag) + { + rval = EINVAL; + goto ret; + } - bzero(&encapdst, sizeof(struct sockaddr_encap)); - bzero(&encapnetmask, sizeof(struct sockaddr_encap)); - bzero(&encapgw, sizeof(struct sockaddr_encap)); + src = (union sockaddr_union *) (headers[SADB_X_EXT_SRC_FLOW] + + sizeof(struct sadb_address)); + dst = (union sockaddr_union *) (headers[SADB_X_EXT_DST_FLOW] + + sizeof(struct sadb_address)); + srcmask = (union sockaddr_union *) (headers[SADB_X_EXT_SRC_MASK] + + sizeof(struct sadb_address)); + dstmask = (union sockaddr_union *) (headers[SADB_X_EXT_DST_MASK] + + sizeof(struct sadb_address)); + + /* + * Check that all the address families match. We know they are + * valid and supported because pfkeyv2_parsemessage() checked that. + */ + if ((src->sa.sa_family != dst->sa.sa_family) || + (src->sa.sa_family != srcmask->sa.sa_family) || + (src->sa.sa_family != dstmask->sa.sa_family)) + { + rval = EINVAL; + goto splxret; + } + + bzero(&encapdst, sizeof(struct sockaddr_encap)); + bzero(&encapnetmask, sizeof(struct sockaddr_encap)); + bzero(&encapgw, sizeof(struct sockaddr_encap)); - if (headers[SADB_X_EXT_PROTOCOL]) - sproto = ((struct sadb_protocol *) headers[SADB_X_EXT_PROTOCOL])->sadb_protocol_proto; - else - sproto = 0; + if (headers[SADB_X_EXT_PROTOCOL]) + sproto = ((struct sadb_protocol *) headers[SADB_X_EXT_PROTOCOL])->sadb_protocol_proto; + else + sproto = 0; - /* Generic netmask handling, works for IPv4 and IPv6 */ - rt_maskedcopy(&src->sa, &src->sa, &srcmask->sa); - rt_maskedcopy(&dst->sa, &dst->sa, &dstmask->sa); + /* Generic netmask handling, works for IPv4 and IPv6 */ + rt_maskedcopy(&src->sa, &src->sa, &srcmask->sa); + rt_maskedcopy(&dst->sa, &dst->sa, &dstmask->sa); - s = spltdb(); + s = spltdb(); - if (!delflag) - { - /* Find the relevant SA */ - sa2 = gettdb(((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_spi, (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] + sizeof(struct sadb_address)), SADB_GETSPROTO(((struct sadb_msg *)headers[0])->sadb_msg_satype)); + if (!delflag) + { + /* Find the relevant SA */ + sa2 = gettdb(ssa->sadb_sa_spi, sunionp, + SADB_GETSPROTO(smsg->sadb_msg_satype)); - if (sa2 == NULL) { - rval = ESRCH; - goto splxret; + if (sa2 == NULL) + { + rval = ESRCH; + goto splxret; + } } - } - - flow = find_global_flow(src, srcmask, dst, dstmask, sproto); - if (!replace && - ((delflag && (flow == NULL)) || (!delflag && (flow != NULL)))) - { - rval = delflag ? ESRCH : EEXIST; - goto splxret; - } - if (!delflag) - { - if (replace) - old_flow = flow; - flow = get_flow(); - bcopy(src, &flow->flow_src, src->sa.sa_len); - bcopy(dst, &flow->flow_dst, dst->sa.sa_len); - bcopy(srcmask, &flow->flow_srcmask, srcmask->sa.sa_len); - bcopy(dstmask, &flow->flow_dstmask, dstmask->sa.sa_len); - flow->flow_proto = sproto; - put_flow(flow, sa2); - } - - /* Setup the encap fields */ - encapdst.sen_family = PF_KEY; - switch (flow->flow_src.sa.sa_family) - { - case AF_INET: - encapdst.sen_len = SENT_IP4_LEN; - encapdst.sen_type = SENT_IP4; - encapdst.sen_ip_src = flow->flow_src.sin.sin_addr; - encapdst.sen_ip_dst = flow->flow_dst.sin.sin_addr; - encapdst.sen_proto = flow->flow_proto; - encapdst.sen_sport = flow->flow_src.sin.sin_port; - encapdst.sen_dport = flow->flow_dst.sin.sin_port; - - encapnetmask.sen_len = SENT_IP4_LEN; - encapnetmask.sen_family = PF_KEY; - encapnetmask.sen_type = SENT_IP4; - encapnetmask.sen_ip_src = flow->flow_srcmask.sin.sin_addr; - encapnetmask.sen_ip_dst = flow->flow_dstmask.sin.sin_addr; - break; + flow = find_global_flow(src, srcmask, dst, dstmask, sproto); + if (!replace && + ((delflag && (flow == NULL)) || (!delflag && (flow != NULL)))) + { + rval = delflag ? ESRCH : EEXIST; + goto splxret; + } -#if INET6 - case AF_INET6: - encapdst.sen_len = SENT_IP6_LEN; - encapdst.sen_type = SENT_IP6; - encapdst.sen_ip6_src = flow->flow_src.sin6.sin6_addr; - encapdst.sen_ip6_dst = flow->flow_dst.sin6.sin6_addr; - encapdst.sen_ip6_proto = flow->flow_proto; - encapdst.sen_ip6_sport = flow->flow_src.sin6.sin6_port; - encapdst.sen_ip6_dport = flow->flow_dst.sin6.sin6_port; - - encapnetmask.sen_len = SENT_IP6_LEN; - encapnetmask.sen_family = PF_KEY; - encapnetmask.sen_type = SENT_IP6; - encapnetmask.sen_ip6_src = flow->flow_srcmask.sin6.sin6_addr; - encapnetmask.sen_ip6_dst = flow->flow_dstmask.sin6.sin6_addr; - break; -#endif /* INET6 */ - } + if (!delflag) + { + if (replace) + old_flow = flow; + + flow = get_flow(); + bcopy(src, &flow->flow_src, src->sa.sa_len); + bcopy(dst, &flow->flow_dst, dst->sa.sa_len); + bcopy(srcmask, &flow->flow_srcmask, srcmask->sa.sa_len); + bcopy(dstmask, &flow->flow_dstmask, dstmask->sa.sa_len); + flow->flow_proto = sproto; + put_flow(flow, sa2); + } - if (!delflag) - { - switch (sa2->tdb_dst.sa.sa_family) + /* Setup the encap fields */ + encapdst.sen_family = PF_KEY; + switch (flow->flow_src.sa.sa_family) { case AF_INET: - encapgw.sen_len = SENT_IPSP_LEN; - encapgw.sen_family = PF_KEY; - encapgw.sen_type = SENT_IPSP; - encapgw.sen_ipsp_dst = sa2->tdb_dst.sin.sin_addr; - encapgw.sen_ipsp_spi = sa2->tdb_spi; - encapgw.sen_ipsp_sproto = sa2->tdb_sproto; - - if (flow->flow_proto) - { - encapnetmask.sen_proto = 0xff; - if (flow->flow_src.sin.sin_port) - encapnetmask.sen_sport = 0xffff; - if (flow->flow_dst.sin.sin_port) - encapnetmask.sen_dport = 0xffff; - } + encapdst.sen_len = SENT_IP4_LEN; + encapdst.sen_type = SENT_IP4; + encapdst.sen_ip_src = flow->flow_src.sin.sin_addr; + encapdst.sen_ip_dst = flow->flow_dst.sin.sin_addr; + encapdst.sen_proto = flow->flow_proto; + encapdst.sen_sport = flow->flow_src.sin.sin_port; + encapdst.sen_dport = flow->flow_dst.sin.sin_port; + + encapnetmask.sen_len = SENT_IP4_LEN; + encapnetmask.sen_family = PF_KEY; + encapnetmask.sen_type = SENT_IP4; + encapnetmask.sen_ip_src = flow->flow_srcmask.sin.sin_addr; + encapnetmask.sen_ip_dst = flow->flow_dstmask.sin.sin_addr; break; #if INET6 case AF_INET6: - encapgw.sen_len = SENT_IPSP6_LEN; - encapgw.sen_family = PF_KEY; - encapgw.sen_type = SENT_IPSP6; - encapgw.sen_ipsp6_dst = sa2->tdb_dst.sin6.sin6_addr; - encapgw.sen_ipsp6_spi = sa2->tdb_spi; - encapgw.sen_ipsp6_sproto = sa2->tdb_sproto; - - if (flow->flow_proto) - { - encapnetmask.sen_ip6_proto = 0xff; - if (flow->flow_src.sin6.sin6_port) - encapnetmask.sen_ip6_sport = 0xffff; - if (flow->flow_dst.sin6.sin6_port) - encapnetmask.sen_ip6_dport = 0xffff; - } + encapdst.sen_len = SENT_IP6_LEN; + encapdst.sen_type = SENT_IP6; + encapdst.sen_ip6_src = flow->flow_src.sin6.sin6_addr; + encapdst.sen_ip6_dst = flow->flow_dst.sin6.sin6_addr; + encapdst.sen_ip6_proto = flow->flow_proto; + encapdst.sen_ip6_sport = flow->flow_src.sin6.sin6_port; + encapdst.sen_ip6_dport = flow->flow_dst.sin6.sin6_port; + + encapnetmask.sen_len = SENT_IP6_LEN; + encapnetmask.sen_family = PF_KEY; + encapnetmask.sen_type = SENT_IP6; + encapnetmask.sen_ip6_src = + flow->flow_srcmask.sin6.sin6_addr; + encapnetmask.sen_ip6_dst = + flow->flow_dstmask.sin6.sin6_addr; break; #endif /* INET6 */ - - default: - /* - * This shouldn't ever happen really, as SAs - * should be checked at establishment time. - */ - rval = EPFNOSUPPORT; - delete_flow(flow, flow->flow_sa); - goto splxret; } - } - - /* Add the entry in the routing table */ - if (delflag) - { - rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst, - (struct sockaddr *) 0, - (struct sockaddr *) &encapnetmask, - 0, (struct rtentry **) 0); - delete_flow(flow, flow->flow_sa); - } - else if (!replace) - { - rval = rtrequest(RTM_ADD, (struct sockaddr *) &encapdst, - (struct sockaddr *) &encapgw, - (struct sockaddr *) &encapnetmask, - RTF_UP | RTF_GATEWAY | RTF_STATIC, - (struct rtentry **) 0); - - if (rval) + if (!delflag) { - delete_flow(flow, sa2); - if (flow2) - delete_flow(flow2, sa2); - goto splxret; + switch (sa2->tdb_dst.sa.sa_family) + { + case AF_INET: + encapgw.sen_len = SENT_IPSP_LEN; + encapgw.sen_family = PF_KEY; + encapgw.sen_type = SENT_IPSP; + encapgw.sen_ipsp_dst = sa2->tdb_dst.sin.sin_addr; + encapgw.sen_ipsp_spi = sa2->tdb_spi; + encapgw.sen_ipsp_sproto = sa2->tdb_sproto; + + if (flow->flow_proto) + { + encapnetmask.sen_proto = 0xff; + + if (flow->flow_src.sin.sin_port) + encapnetmask.sen_sport = 0xffff; + + if (flow->flow_dst.sin.sin_port) + encapnetmask.sen_dport = 0xffff; + } + break; + +#if INET6 + case AF_INET6: + encapgw.sen_len = SENT_IPSP6_LEN; + encapgw.sen_family = PF_KEY; + encapgw.sen_type = SENT_IPSP6; + encapgw.sen_ipsp6_dst = sa2->tdb_dst.sin6.sin6_addr; + encapgw.sen_ipsp6_spi = sa2->tdb_spi; + encapgw.sen_ipsp6_sproto = sa2->tdb_sproto; + + if (flow->flow_proto) + { + encapnetmask.sen_ip6_proto = 0xff; + + if (flow->flow_src.sin6.sin6_port) + encapnetmask.sen_ip6_sport = 0xffff; + + if (flow->flow_dst.sin6.sin6_port) + encapnetmask.sen_ip6_dport = 0xffff; + } + break; +#endif /* INET6 */ + + default: + /* + * This shouldn't ever happen really, as SAs + * should be checked at establishment time. + */ + rval = EPFNOSUPPORT; + delete_flow(flow, flow->flow_sa); + goto splxret; + } } - sa2->tdb_cur_allocations++; - } - else - { - rt = (struct rtentry *) rn_lookup(&encapdst, &encapnetmask, - rt_tables[PF_KEY]); - if (rt == NULL) + /* Add the entry in the routing table */ + if (delflag) + { + rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst, + (struct sockaddr *) 0, + (struct sockaddr *) &encapnetmask, + 0, (struct rtentry **) 0); + + delete_flow(flow, flow->flow_sa); + } + else if (!replace) { rval = rtrequest(RTM_ADD, (struct sockaddr *) &encapdst, (struct sockaddr *) &encapgw, (struct sockaddr *) &encapnetmask, RTF_UP | RTF_GATEWAY | RTF_STATIC, (struct rtentry **) 0); - + if (rval) { delete_flow(flow, sa2); + if (flow2) delete_flow(flow2, sa2); + goto splxret; } + + sa2->tdb_cur_allocations++; } - else if (rt_setgate(rt, rt_key(rt), (struct sockaddr *) &encapgw)) + else { - rval = ENOMEM; - delete_flow(flow, sa2); - if (flow2) - delete_flow(flow2, sa2); - goto splxret; + rt = (struct rtentry *) rn_lookup(&encapdst, &encapnetmask, + rt_tables[PF_KEY]); + if (rt == NULL) + { + rval = rtrequest(RTM_ADD, (struct sockaddr *) &encapdst, + (struct sockaddr *) &encapgw, + (struct sockaddr *) &encapnetmask, + RTF_UP | RTF_GATEWAY | RTF_STATIC, + (struct rtentry **) 0); + + if (rval) + { + delete_flow(flow, sa2); + + if (flow2) + delete_flow(flow2, sa2); + + goto splxret; + } + } + else if (rt_setgate(rt, rt_key(rt), + (struct sockaddr *) &encapgw)) + { + rval = ENOMEM; + delete_flow(flow, sa2); + + if (flow2) + delete_flow(flow2, sa2); + + goto splxret; + } + + sa2->tdb_cur_allocations++; } - sa2->tdb_cur_allocations++; + if (replace) + { + if (old_flow != NULL) + delete_flow(old_flow, old_flow->flow_sa); + + if (old_flow2 != NULL) + delete_flow(old_flow2, old_flow2->flow_sa); + } + + /* If we are adding flows, check for allocation expirations */ + if (!delflag && !(replace && old_flow != NULL)) + { + if ((sa2->tdb_flags & TDBF_ALLOCATIONS) && + (sa2->tdb_cur_allocations >= sa2->tdb_exp_allocations)) + { + pfkeyv2_expire(sa2, SADB_EXT_LIFETIME_HARD); + tdb_delete(sa2, 0, TDBEXP_TIMEOUT); + } + else + if ((sa2->tdb_flags & TDBF_SOFT_ALLOCATIONS) && + (sa2->tdb_cur_allocations >= sa2->tdb_soft_allocations)) + { + pfkeyv2_expire(sa2, SADB_EXT_LIFETIME_SOFT); + sa2->tdb_flags &= ~TDBF_SOFT_ALLOCATIONS; + } + } } - if (replace) + splx(s); + break; + + case SADB_X_GRPSPIS: { - if (old_flow != NULL) - delete_flow(old_flow, old_flow->flow_sa); - if (old_flow2 != NULL) - delete_flow(old_flow2, old_flow2->flow_sa); - } + struct tdb *tdb1, *tdb2, *tdb3; + struct sadb_protocol *sa_proto; - /* If we are adding flows, check for allocation expirations */ - if (!delflag && !(replace && old_flow != NULL)) { - if ((sa2->tdb_flags & TDBF_ALLOCATIONS) && - (sa2->tdb_cur_allocations > sa2->tdb_exp_allocations)) { - /* XXX expiration notification */ + ssa = (struct sadb_sa *) headers[SADB_EXT_SA]; + sunionp = (union sockaddr_union *) (headers[SADB_EXT_ADDRESS_DST] + + sizeof(struct sadb_address)); - tdb_delete(sa2, 0, TDBEXP_TIMEOUT); - } else - if ((sa2->tdb_flags & TDBF_SOFT_ALLOCATIONS) && - (sa2->tdb_cur_allocations > sa2->tdb_soft_allocations)) { - /* XXX expiration notification */ - sa2->tdb_flags &= ~TDBF_SOFT_ALLOCATIONS; + s = spltdb(); + + tdb1 = gettdb(ssa->sadb_sa_spi, sunionp, + SADB_GETSPROTO(smsg->sadb_msg_satype)); + if (tdb1 == NULL) + { + rval = ESRCH; + goto splxret; + } + + ssa = (struct sadb_sa *) headers[SADB_X_EXT_SA2]; + sunionp = (union sockaddr_union *) (headers[SADB_X_EXT_DST2] + + sizeof(struct sadb_address)); + sa_proto = ((struct sadb_protocol *) headers[SADB_X_EXT_PROTOCOL]); + + tdb2 = gettdb(ssa->sadb_sa_spi, sunionp, + SADB_GETSPROTO(sa_proto->sadb_protocol_proto)); + if (tdb2 == NULL) + { + rval = ESRCH; + goto splxret; + } + + /* Detect cycles */ + for (tdb3 = tdb2; tdb3; tdb3 = tdb3->tdb_onext) + if (tdb3 == tdb1) + { + rval = ESRCH; + goto splxret; } + + /* Maintenance */ + if ((tdb1->tdb_onext) && + (tdb1->tdb_onext->tdb_inext == tdb1)) + tdb1->tdb_onext->tdb_inext = NULL; + + if ((tdb2->tdb_inext) && + (tdb2->tdb_inext->tdb_onext == tdb2)) + tdb2->tdb_inext->tdb_onext = NULL; + + /* Link them */ + tdb1->tdb_onext = tdb2; + tdb2->tdb_inext = tdb1; + + splx(s); } - } - splx(s); - break; + + break; - case SADB_X_GRPSPIS: - { - struct tdb *tdb1, *tdb2, *tdb3; - - s = spltdb(); - tdb1 = gettdb(((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_spi, - (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] + - sizeof(struct sadb_address)), - SADB_GETSPROTO(((struct sadb_msg *)headers[0])->sadb_msg_satype)); - if (tdb1 == NULL) { - rval = ESRCH; - goto splxret; - } + case SADB_X_BINDSA: + { + struct tdb *tdb1, *tdb2; + struct sadb_protocol *sa_proto; - tdb2 = gettdb(((struct sadb_sa *)headers[SADB_X_EXT_SA2])->sadb_sa_spi, - (union sockaddr_union *)(headers[SADB_X_EXT_DST2] + - sizeof(struct sadb_address)), - SADB_GETSPROTO(((struct sadb_protocol *)headers[SADB_X_EXT_PROTOCOL])->sadb_protocol_proto)); + ssa = (struct sadb_sa *) headers[SADB_EXT_SA]; + sunionp = (union sockaddr_union *) (headers[SADB_EXT_ADDRESS_DST] + + sizeof(struct sadb_address)); - if (tdb2 == NULL) { - rval = ESRCH; - goto splxret; - } + s = spltdb(); - /* Detect cycles */ - for (tdb3 = tdb2; tdb3; tdb3 = tdb3->tdb_onext) - if (tdb3 == tdb1) - { - rval = ESRCH; - goto splxret; - } + tdb1 = gettdb(ssa->sadb_sa_spi, sunionp, + SADB_GETSPROTO(smsg->sadb_msg_satype)); + if (tdb1 == NULL) + { + rval = ESRCH; + goto splxret; + } - /* Maintenance */ - if ((tdb1->tdb_onext) && - (tdb1->tdb_onext->tdb_inext == tdb1)) - tdb1->tdb_onext->tdb_inext = NULL; + if (TAILQ_FIRST(&tdb1->tdb_bind_in)) + { + /* Incoming SA has not list of referencing incoming SAs */ + rval = EINVAL; + goto splxret; + } - if ((tdb2->tdb_inext) && - (tdb2->tdb_inext->tdb_onext == tdb2)) - tdb2->tdb_inext->tdb_onext = NULL; + ssa = (struct sadb_sa *) headers[SADB_X_EXT_SA2]; + sunionp = (union sockaddr_union *) (headers[SADB_X_EXT_DST2] + + sizeof(struct sadb_address)); + sa_proto = ((struct sadb_protocol *) headers[SADB_X_EXT_PROTOCOL]); - /* Link them */ - tdb1->tdb_onext = tdb2; - tdb2->tdb_inext = tdb1; - splx(s); - } - break; - - case SADB_X_BINDSA: - { - struct tdb *tdb1, *tdb2; - - s = spltdb(); - tdb1 = gettdb(((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_spi, - (union sockaddr_union *)(headers[SADB_EXT_ADDRESS_DST] + - sizeof(struct sadb_address)), - SADB_GETSPROTO(((struct sadb_msg *)headers[0])->sadb_msg_satype)); - if (tdb1 == NULL) { - rval = ESRCH; - goto splxret; - } + tdb2 = gettdb(ssa->sadb_sa_spi, sunionp, + SADB_GETSPROTO(sa_proto->sadb_protocol_proto)); + if (tdb2 == NULL) + { + rval = ESRCH; + goto splxret; + } - if (TAILQ_FIRST(&tdb1->tdb_bind_in)) { - /* Incoming SA has not list of referencing incoming SAs */ - rval = EINVAL; - goto splxret; - } + if (tdb2->tdb_bind_out) + { + /* Outgoing SA has no pointer to an outgoing SA */ + rval = EINVAL; + goto splxret; + } - tdb2 = gettdb(((struct sadb_sa *)headers[SADB_X_EXT_SA2])->sadb_sa_spi, - (union sockaddr_union *)(headers[SADB_X_EXT_DST2] + - sizeof(struct sadb_address)), - SADB_GETSPROTO(((struct sadb_protocol *)headers[SADB_X_EXT_PROTOCOL])->sadb_protocol_proto)); + /* Maintenance */ + if (tdb1->tdb_bind_out) + TAILQ_REMOVE(&tdb1->tdb_bind_out->tdb_bind_in, tdb1, + tdb_bind_in_next); - if (tdb2 == NULL) { - rval = ESRCH; - goto splxret; - } + /* Link them */ + tdb1->tdb_bind_out = tdb2; + TAILQ_INSERT_TAIL(&tdb2->tdb_bind_in, tdb1, tdb_bind_in_next); - if (tdb2->tdb_bind_out) { - /* Outgoing SA has no pointer to an outgoing SA */ - rval = EINVAL; - goto splxret; + splx(s); } - /* Maintenance */ - if (tdb1->tdb_bind_out) - TAILQ_REMOVE(&tdb1->tdb_bind_out->tdb_bind_in, tdb1, - tdb_bind_in_next); - - /* Link them */ - tdb1->tdb_bind_out = tdb2; - TAILQ_INSERT_TAIL(&tdb2->tdb_bind_in, tdb1, tdb_bind_in_next); - } - splx(s); - break; + break; - case SADB_X_PROMISC: - if (len >= 2 * sizeof(struct sadb_msg)) { - struct mbuf *packet; + case SADB_X_PROMISC: + if (len >= 2 * sizeof(struct sadb_msg)) + { + struct mbuf *packet; - if ((rval = pfdatatopacket(message, len, &packet)) != 0) - goto ret; + if ((rval = pfdatatopacket(message, len, &packet)) != 0) + goto ret; - for (so = pfkeyv2_sockets; so; so = so->next) - if ((so != pfkeyv2_socket) && - (!((struct sadb_msg *)headers[0])->sadb_msg_seq || - (((struct sadb_msg *)headers[0])->sadb_msg_seq == - pfkeyv2_socket->pid))) - pfkey_sendup(so->socket, packet, 1); + for (so = pfkeyv2_sockets; so; so = so->next) + if ((so != pfkeyv2_socket) && + (!smsg->sadb_msg_seq || + (smsg->sadb_msg_seq == pfkeyv2_socket->pid))) + pfkey_sendup(so->socket, packet, 1); - m_freem(packet); - } else { - if (len != sizeof(struct sadb_msg)) { - rval = EINVAL; - goto ret; - } + m_freem(packet); + } + else + { + if (len != sizeof(struct sadb_msg)) + { + rval = EINVAL; + goto ret; + } - i = (pfkeyv2_socket->flags & PFKEYV2_SOCKETFLAGS_PROMISC) ? 1 : 0; - j = ((struct sadb_msg *)headers[0])->sadb_msg_satype ? 1 : 0; - - if (i ^ j) { - if (j) { - pfkeyv2_socket->flags |= PFKEYV2_SOCKETFLAGS_PROMISC; - npromisc++; - } else { - pfkeyv2_socket->flags &= ~PFKEYV2_SOCKETFLAGS_PROMISC; - npromisc--; - } - } - } - break; - default: - rval = EINVAL; - goto ret; - } + i = (pfkeyv2_socket->flags & + PFKEYV2_SOCKETFLAGS_PROMISC) ? 1 : 0; + j = smsg->sadb_msg_satype ? 1 : 0; + + if (i ^ j) + { + if (j) + { + pfkeyv2_socket->flags |= PFKEYV2_SOCKETFLAGS_PROMISC; + npromisc++; + } + else + { + pfkeyv2_socket->flags &= ~PFKEYV2_SOCKETFLAGS_PROMISC; + npromisc--; + } + } + } + + break; + + default: + rval = EINVAL; + goto ret; + } ret: - if (rval) { - if ((rval == EINVAL) || (rval == ENOMEM) || - (rval == ENOBUFS)) - goto realret; - for (i = 1; i <= SADB_EXT_MAX; i++) - headers[i] = NULL; - ((struct sadb_msg *)headers[0])->sadb_msg_errno = abs(rval); - } else { - uint32_t seen = 0; + if (rval) + { + if ((rval == EINVAL) || (rval == ENOMEM) || (rval == ENOBUFS)) + goto realret; - for (i = 1; i <= SADB_EXT_MAX; i++) - if (headers[i]) - seen |= (1 << i); + for (i = 1; i <= SADB_EXT_MAX; i++) + headers[i] = NULL; - if ((seen & sadb_exts_allowed_out[((struct sadb_msg *)headers[0])->sadb_msg_type]) != seen) { - goto realret; - } + smsg->sadb_msg_errno = abs(rval); + } + else + { + uint32_t seen = 0; - if ((seen & sadb_exts_required_out[((struct sadb_msg *)headers[0])->sadb_msg_type]) != sadb_exts_required_out[((struct sadb_msg *)headers[0])->sadb_msg_type]) { - goto realret; - } - } + for (i = 1; i <= SADB_EXT_MAX; i++) + if (headers[i]) + seen |= (1 << i); + + if ((seen & sadb_exts_allowed_out[smsg->sadb_msg_type]) != seen) + goto realret; + + if ((seen & sadb_exts_required_out[smsg->sadb_msg_type]) != + sadb_exts_required_out[smsg->sadb_msg_type]) + goto realret; + } - rval = pfkeyv2_sendmessage(headers, mode, socket, 0, 0); + rval = pfkeyv2_sendmessage(headers, mode, socket, 0, 0); realret: - if (freeme) - free(freeme, M_PFKEY); - free(message, M_PFKEY); + if (freeme) + free(freeme, M_PFKEY); - return rval; + free(message, M_PFKEY); - splxret: - splx(s); - goto ret; + return rval; + +splxret: + splx(s); + goto ret; } +/* + * Send an ACQUIRE message to key management, to get a new SA. + */ int pfkeyv2_acquire(struct tdb *tdb, int rekey) { - int rval = 0; - int i, j; - void *p, *headers[SADB_EXT_MAX+1], *buffer = NULL; - - if (!nregistered) { - rval = ESRCH; - goto ret; - } - - /* How large a buffer do we need... */ - i = sizeof(struct sadb_msg) + sizeof(struct sadb_address) + - PADUP(SA_LEN(&tdb->tdb_src.sa)) + sizeof(struct sadb_address) + - PADUP(SA_LEN(&tdb->tdb_dst.sa)) + sizeof(struct sadb_prop) + - 1 * sizeof(struct sadb_comb) + /* XXX We only do one proposal for now */ - 2 * sizeof(struct sadb_ident); - - if (rekey) - i += PADUP(tdb->tdb_srcid_len) + - PADUP(tdb->tdb_dstid_len); - - /* Allocate */ - if (!(p = malloc(i, M_PFKEY, M_DONTWAIT))) { - rval = ENOMEM; - goto ret; - } + void *p, *headers[SADB_EXT_MAX+1], *buffer = NULL; + struct sadb_address *sadd; + struct sadb_msg *smsg; + struct sadb_ident *sa_ident; + struct sadb_prop *sa_prop; + struct sadb_comb *sadb_comb; + int rval = 0; + int i, j; + + if (!nregistered) + { + rval = ESRCH; + goto ret; + } - bzero(headers, sizeof(headers)); + /* How large a buffer do we need... XXX we only do one proposal for now */ + i = sizeof(struct sadb_msg) + sizeof(struct sadb_address) + + PADUP(SA_LEN(&tdb->tdb_src.sa)) + sizeof(struct sadb_address) + + PADUP(SA_LEN(&tdb->tdb_dst.sa)) + sizeof(struct sadb_prop) + + 1 * sizeof(struct sadb_comb) + + 2 * sizeof(struct sadb_ident); - buffer = p; - bzero(p, i); + if (rekey) + i += PADUP(tdb->tdb_srcid_len) + PADUP(tdb->tdb_dstid_len); - headers[0] = p; - p += sizeof(struct sadb_msg); - ((struct sadb_msg *)headers[0])->sadb_msg_version = PF_KEY_V2; - ((struct sadb_msg *)headers[0])->sadb_msg_type = SADB_ACQUIRE; - ((struct sadb_msg *)headers[0])->sadb_msg_len = i / sizeof(uint64_t); - ((struct sadb_msg *)headers[0])->sadb_msg_seq = pfkeyv2_seq++; - ((struct sadb_msg *)headers[0])->sadb_msg_satype = tdb->tdb_satype; + /* Allocate */ + if (!(p = malloc(i, M_PFKEY, M_DONTWAIT))) + { + rval = ENOMEM; + goto ret; + } - headers[SADB_EXT_ADDRESS_SRC] = p; - p += sizeof(struct sadb_address) + PADUP(SA_LEN(&tdb->tdb_src.sa)); - ((struct sadb_address *)headers[SADB_EXT_ADDRESS_SRC])->sadb_address_len = (sizeof(struct sadb_address) + SA_LEN(&tdb->tdb_src.sa) + sizeof(uint64_t) - 1) / sizeof(uint64_t); - bcopy(&tdb->tdb_src, headers[SADB_EXT_ADDRESS_SRC] + sizeof(struct sadb_address), SA_LEN(&tdb->tdb_src.sa)); + bzero(headers, sizeof(headers)); - headers[SADB_EXT_ADDRESS_DST] = p; - p += sizeof(struct sadb_address) + PADUP(SA_LEN(&tdb->tdb_dst.sa)); - ((struct sadb_address *)headers[SADB_EXT_ADDRESS_DST])->sadb_address_len = (sizeof(struct sadb_address) + SA_LEN(&tdb->tdb_dst.sa) + sizeof(uint64_t) - 1) / sizeof(uint64_t); - bcopy(&tdb->tdb_dst, headers[SADB_EXT_ADDRESS_DST] + sizeof(struct sadb_address), SA_LEN(&tdb->tdb_dst.sa)); + buffer = p; + bzero(p, i); + + headers[0] = p; + p += sizeof(struct sadb_msg); + + smsg = (struct sadb_msg *) headers[0]; + smsg->sadb_msg_version = PF_KEY_V2; + smsg->sadb_msg_type = SADB_ACQUIRE; + smsg->sadb_msg_len = i / sizeof(uint64_t); + smsg->sadb_msg_seq = pfkeyv2_seq++; + smsg->sadb_msg_satype = tdb->tdb_satype; + + headers[SADB_EXT_ADDRESS_SRC] = p; + p += sizeof(struct sadb_address) + PADUP(SA_LEN(&tdb->tdb_src.sa)); + sadd = (struct sadb_address *) headers[SADB_EXT_ADDRESS_SRC]; + sadd->sadb_address_len = (sizeof(struct sadb_address) + + SA_LEN(&tdb->tdb_src.sa) + + sizeof(uint64_t) - 1) / sizeof(uint64_t); + bcopy(&tdb->tdb_src, + headers[SADB_EXT_ADDRESS_SRC] + sizeof(struct sadb_address), + SA_LEN(&tdb->tdb_src.sa)); + + headers[SADB_EXT_ADDRESS_DST] = p; + p += sizeof(struct sadb_address) + PADUP(SA_LEN(&tdb->tdb_dst.sa)); + sadd = (struct sadb_address *) headers[SADB_EXT_ADDRESS_DST]; + sadd->sadb_address_len = (sizeof(struct sadb_address) + + SA_LEN(&tdb->tdb_dst.sa) + + sizeof(uint64_t) - 1) / sizeof(uint64_t); + bcopy(&tdb->tdb_dst, + headers[SADB_EXT_ADDRESS_DST] + sizeof(struct sadb_address), + SA_LEN(&tdb->tdb_dst.sa)); - headers[SADB_EXT_IDENTITY_SRC] = p; - p += sizeof(struct sadb_ident); - ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC])->sadb_ident_type = tdb->tdb_srcid_type; + headers[SADB_EXT_IDENTITY_SRC] = p; + p += sizeof(struct sadb_ident); + sa_ident = (struct sadb_ident *) headers[SADB_EXT_IDENTITY_SRC]; + sa_ident->sadb_ident_type = tdb->tdb_srcid_type; - /* XXX some day we'll have to deal with real ident_ids for users */ - ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC])->sadb_ident_id = 0; + /* XXX some day we'll have to deal with real ident_ids for users */ + sa_ident->sadb_ident_id = 0; - if (rekey) { - ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC])->sadb_ident_len = (sizeof(struct sadb_ident) + PADUP(tdb->tdb_srcid_len)) / sizeof(uint64_t); - bcopy(tdb->tdb_srcid, p, tdb->tdb_srcid_len); - p += PADUP(tdb->tdb_srcid_len); - } else - ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC])->sadb_ident_len = (sizeof(struct sadb_ident)) / sizeof(uint64_t); + if (rekey) + { + sa_ident->sadb_ident_len = (sizeof(struct sadb_ident) + + PADUP(tdb->tdb_srcid_len)) / + sizeof(uint64_t); + bcopy(tdb->tdb_srcid, p, tdb->tdb_srcid_len); + p += PADUP(tdb->tdb_srcid_len); + } + else + sa_ident->sadb_ident_len = sizeof(struct sadb_ident) / sizeof(uint64_t); - headers[SADB_EXT_IDENTITY_DST] = p; - p += sizeof(struct sadb_ident); - ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_DST])->sadb_ident_type = tdb->tdb_dstid_type; + headers[SADB_EXT_IDENTITY_DST] = p; + p += sizeof(struct sadb_ident); + sa_ident = (struct sadb_ident *) headers[SADB_EXT_IDENTITY_DST]; + sa_ident->sadb_ident_type = tdb->tdb_dstid_type; - /* XXX some day we'll have to deal with real ident_ids for users */ - ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_DST])->sadb_ident_id = 0; + /* XXX some day we'll have to deal with real ident_ids for users */ + sa_ident->sadb_ident_id = 0; - if (rekey) { - ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_DST])->sadb_ident_len = (sizeof(struct sadb_ident) + PADUP(tdb->tdb_dstid_len)) / sizeof(uint64_t); - bcopy(tdb->tdb_dstid, p, tdb->tdb_dstid_len); - p += PADUP(tdb->tdb_dstid_len); - } else - ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_DST])->sadb_ident_len = (sizeof(struct sadb_ident)) / sizeof(uint64_t); + if (rekey) + { + sa_ident->sadb_ident_len = (sizeof(struct sadb_ident) + + PADUP(tdb->tdb_dstid_len)) / + sizeof(uint64_t); + bcopy(tdb->tdb_dstid, p, tdb->tdb_dstid_len); + p += PADUP(tdb->tdb_dstid_len); + } + else + sa_ident->sadb_ident_len = sizeof(struct sadb_ident) / sizeof(uint64_t); - headers[SADB_EXT_PROPOSAL] = p; - p += sizeof(struct sadb_prop); - ((struct sadb_prop *)headers[SADB_EXT_PROPOSAL])->sadb_prop_len = (sizeof(struct sadb_prop) + sizeof(struct sadb_comb) * 1) / sizeof(uint64_t); /* XXX 1 proposal only */ - ((struct sadb_prop *)headers[SADB_EXT_PROPOSAL])->sadb_prop_num = 1; /* XXX 1 proposal only */ + headers[SADB_EXT_PROPOSAL] = p; + p += sizeof(struct sadb_prop); + sa_prop = (struct sadb_prop *) headers[SADB_EXT_PROPOSAL]; + sa_prop->sadb_prop_num = 1; /* XXX Only 1 proposal supported for now */ + sa_prop->sadb_prop_len = (sizeof(struct sadb_prop) + + (sizeof(struct sadb_comb) * + sa_prop->sadb_prop_num)) / sizeof(uint64_t); - { - struct sadb_comb *sadb_comb = p; + sadb_comb = p; - /* XXX 1 proposal only */ - for (j = 0; j < 1; j++) { - sadb_comb->sadb_comb_flags = 0; + for (j = 0; j < sa_prop->sadb_prop_num; j++) + { + sadb_comb->sadb_comb_flags = 0; - if (tdb->tdb_flags & TDBF_PFS) - sadb_comb->sadb_comb_flags |= SADB_SAFLAGS_PFS; + if (tdb->tdb_flags & TDBF_PFS) + sadb_comb->sadb_comb_flags |= SADB_SAFLAGS_PFS; - if (tdb->tdb_flags & TDBF_HALFIV) - sadb_comb->sadb_comb_flags |= SADB_X_SAFLAGS_HALFIV; + if (tdb->tdb_flags & TDBF_HALFIV) + sadb_comb->sadb_comb_flags |= SADB_X_SAFLAGS_HALFIV; - if (tdb->tdb_flags & TDBF_TUNNELING) - sadb_comb->sadb_comb_flags |= SADB_X_SAFLAGS_TUNNEL; + if (tdb->tdb_flags & TDBF_TUNNELING) + sadb_comb->sadb_comb_flags |= SADB_X_SAFLAGS_TUNNEL; - if (tdb->tdb_authalgxform) - { - sadb_comb->sadb_comb_auth = tdb->tdb_authalgxform->type; - sadb_comb->sadb_comb_auth_minbits = tdb->tdb_authalgxform->keysize * 8; - sadb_comb->sadb_comb_auth_maxbits = tdb->tdb_authalgxform->keysize * 8; - } - else - { - sadb_comb->sadb_comb_auth = 0; - sadb_comb->sadb_comb_auth_minbits = 0; - sadb_comb->sadb_comb_auth_maxbits = 0; - } + if (tdb->tdb_authalgxform) + { + sadb_comb->sadb_comb_auth = tdb->tdb_authalgxform->type; + sadb_comb->sadb_comb_auth_minbits = + tdb->tdb_authalgxform->keysize * 8; + sadb_comb->sadb_comb_auth_maxbits = + tdb->tdb_authalgxform->keysize * 8; + } + else + { + sadb_comb->sadb_comb_auth = 0; + sadb_comb->sadb_comb_auth_minbits = 0; + sadb_comb->sadb_comb_auth_maxbits = 0; + } - if (tdb->tdb_encalgxform) - { - sadb_comb->sadb_comb_encrypt = tdb->tdb_encalgxform->type; - sadb_comb->sadb_comb_encrypt_minbits = tdb->tdb_encalgxform->minkey * 8; - sadb_comb->sadb_comb_encrypt_maxbits = tdb->tdb_encalgxform->maxkey * 8; - } - else - { - sadb_comb->sadb_comb_encrypt = 0; - sadb_comb->sadb_comb_encrypt_minbits = 0; - sadb_comb->sadb_comb_encrypt_maxbits = 0; - } + if (tdb->tdb_encalgxform) + { + sadb_comb->sadb_comb_encrypt = tdb->tdb_encalgxform->type; + sadb_comb->sadb_comb_encrypt_minbits = + tdb->tdb_encalgxform->minkey * 8; + sadb_comb->sadb_comb_encrypt_maxbits = + tdb->tdb_encalgxform->maxkey * 8; + } + else + { + sadb_comb->sadb_comb_encrypt = 0; + sadb_comb->sadb_comb_encrypt_minbits = 0; + sadb_comb->sadb_comb_encrypt_maxbits = 0; + } - sadb_comb->sadb_comb_soft_allocations = tdb->tdb_soft_allocations; - sadb_comb->sadb_comb_hard_allocations = tdb->tdb_exp_allocations; + sadb_comb->sadb_comb_soft_allocations = tdb->tdb_soft_allocations; + sadb_comb->sadb_comb_hard_allocations = tdb->tdb_exp_allocations; - sadb_comb->sadb_comb_soft_bytes = tdb->tdb_soft_bytes; - sadb_comb->sadb_comb_hard_bytes = tdb->tdb_exp_bytes; + sadb_comb->sadb_comb_soft_bytes = tdb->tdb_soft_bytes; + sadb_comb->sadb_comb_hard_bytes = tdb->tdb_exp_bytes; - sadb_comb->sadb_comb_soft_addtime = tdb->tdb_soft_timeout; - sadb_comb->sadb_comb_hard_addtime = tdb->tdb_exp_timeout; + sadb_comb->sadb_comb_soft_addtime = tdb->tdb_soft_timeout; + sadb_comb->sadb_comb_hard_addtime = tdb->tdb_exp_timeout; - sadb_comb->sadb_comb_soft_usetime = tdb->tdb_soft_first_use; - sadb_comb->sadb_comb_hard_usetime = tdb->tdb_exp_first_use; - sadb_comb++; + sadb_comb->sadb_comb_soft_usetime = tdb->tdb_soft_first_use; + sadb_comb->sadb_comb_hard_usetime = tdb->tdb_exp_first_use; + sadb_comb++; } - } - if ((rval = pfkeyv2_sendmessage(headers, PFKEYV2_SENDMESSAGE_REGISTERED, - NULL, ((struct sadb_msg *)headers[0])->sadb_msg_satype, 1))!= 0) /* XXX notice count of 1 as last arg -- is that right ? */ - goto ret; + /* + * Send the ACQUIRE message to all compliant registered listeners. + * XXX We only send it to the first compliant registered + * listener (as specified by the last argument) + */ + if ((rval = pfkeyv2_sendmessage(headers, PFKEYV2_SENDMESSAGE_REGISTERED, + NULL, smsg->sadb_msg_satype, 1)) != 0) + goto ret; - rval = 0; + rval = 0; ret: - if (buffer != NULL) { - bzero(buffer, i); - free(buffer, M_PFKEY); - } - return rval; + if (buffer != NULL) + { + bzero(buffer, i); + free(buffer, M_PFKEY); + } + + return rval; } +/* + * Notify key management that an expiration went off. The second argument + * specifies the type of expiration (soft or hard). + */ int pfkeyv2_expire(struct tdb *sa, u_int16_t type) { - int rval = 0; - int i; - void *p, *headers[SADB_EXT_MAX+1], *buffer = NULL; - - switch (sa->tdb_sproto) { - case IPPROTO_AH: - case IPPROTO_ESP: - case IPPROTO_IPIP: + void *p, *headers[SADB_EXT_MAX+1], *buffer = NULL; + struct sadb_msg *smsg; + int rval = 0; + int i; + + switch (sa->tdb_sproto) + { + case IPPROTO_AH: + case IPPROTO_ESP: + case IPPROTO_IPIP: #ifdef TCP_SIGNATURE - case IPPROTO_TCP: + case IPPROTO_TCP: #endif /* TCP_SIGNATURE */ - break; - default: - rval = EOPNOTSUPP; - goto ret; - } + break; - i = sizeof(struct sadb_msg) + sizeof(struct sadb_sa) + - 2 * sizeof(struct sadb_lifetime) + - sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_src.sa)) + - sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_dst.sa)); + default: + rval = EOPNOTSUPP; + goto ret; + } - if (!(p = malloc(i, M_PFKEY, M_DONTWAIT))) { - rval = ENOMEM; - goto ret; - } + i = sizeof(struct sadb_msg) + sizeof(struct sadb_sa) + + 2 * sizeof(struct sadb_lifetime) + + sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_src.sa)) + + sizeof(struct sadb_address) + PADUP(SA_LEN(&sa->tdb_dst.sa)); + + if (!(p = malloc(i, M_PFKEY, M_DONTWAIT))) + { + rval = ENOMEM; + goto ret; + } - bzero(headers, sizeof(headers)); + bzero(headers, sizeof(headers)); - buffer = p; - bzero(p, i); + buffer = p; + bzero(p, i); - headers[0] = p; - p += sizeof(struct sadb_msg); - ((struct sadb_msg *)headers[0])->sadb_msg_version = PF_KEY_V2; - ((struct sadb_msg *)headers[0])->sadb_msg_type = SADB_EXPIRE; - ((struct sadb_msg *)headers[0])->sadb_msg_satype = sa->tdb_satype; - ((struct sadb_msg *)headers[0])->sadb_msg_len = i / sizeof(uint64_t); - ((struct sadb_msg *)headers[0])->sadb_msg_seq = pfkeyv2_seq++; + headers[0] = p; + p += sizeof(struct sadb_msg); - headers[SADB_EXT_SA] = p; - export_sa(&p, sa); + smsg = (struct sadb_msg *) headers[0]; + smsg->sadb_msg_version = PF_KEY_V2; + smsg->sadb_msg_type = SADB_EXPIRE; + smsg->sadb_msg_satype = sa->tdb_satype; + smsg->sadb_msg_len = i / sizeof(uint64_t); + smsg->sadb_msg_seq = pfkeyv2_seq++; - headers[SADB_EXT_LIFETIME_CURRENT] = p; - export_lifetime(&p, sa, 2); + headers[SADB_EXT_SA] = p; + export_sa(&p, sa); - headers[type] = p; - export_lifetime(&p, sa, type == SADB_EXT_LIFETIME_SOFT ? 1 : 0); + headers[SADB_EXT_LIFETIME_CURRENT] = p; + export_lifetime(&p, sa, 2); - headers[SADB_EXT_ADDRESS_SRC] = p; - export_address(&p, (struct sockaddr *)&sa->tdb_src); + headers[type] = p; + type = (SADB_EXT_LIFETIME_SOFT ? PFKEYV2_LIFETIME_SOFT : + PFKEYV2_LIFETIME_HARD); + export_lifetime(&p, sa, type); - headers[SADB_EXT_ADDRESS_DST] = p; - export_address(&p, (struct sockaddr *)&sa->tdb_dst); + headers[SADB_EXT_ADDRESS_SRC] = p; + export_address(&p, (struct sockaddr *) &sa->tdb_src); - if ((rval = pfkeyv2_sendmessage(headers, PFKEYV2_SENDMESSAGE_BROADCAST, - NULL, 0, 0))!= 0) - goto ret; + headers[SADB_EXT_ADDRESS_DST] = p; + export_address(&p, (struct sockaddr *) &sa->tdb_dst); - rval = 0; + if ((rval = pfkeyv2_sendmessage(headers, PFKEYV2_SENDMESSAGE_BROADCAST, + NULL, 0, 0)) != 0) + goto ret; + + rval = 0; ret: - if (buffer != NULL) { - bzero(buffer, i); - free(buffer, M_PFKEY); - } - return rval; + if (buffer != NULL) + { + bzero(buffer, i); + free(buffer, M_PFKEY); + } + + return rval; } int pfkeyv2_init(void) { - int rval; + int rval; - bzero(&pfkeyv2_version, sizeof(struct pfkey_version)); - pfkeyv2_version.protocol = PFKEYV2_PROTOCOL; - pfkeyv2_version.create = &pfkeyv2_create; - pfkeyv2_version.release = &pfkeyv2_release; - pfkeyv2_version.send = &pfkeyv2_send; + bzero(&pfkeyv2_version, sizeof(struct pfkey_version)); + pfkeyv2_version.protocol = PFKEYV2_PROTOCOL; + pfkeyv2_version.create = &pfkeyv2_create; + pfkeyv2_version.release = &pfkeyv2_release; + pfkeyv2_version.send = &pfkeyv2_send; - rval = pfkey_register(&pfkeyv2_version); - return rval; + rval = pfkey_register(&pfkeyv2_version); + return rval; } int pfkeyv2_cleanup(void) { - pfkey_unregister(&pfkeyv2_version); - return 0; + pfkey_unregister(&pfkeyv2_version); + return 0; } |