summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAngelos D. Keromytis <angelos@cvs.openbsd.org>1999-02-24 22:36:05 +0000
committerAngelos D. Keromytis <angelos@cvs.openbsd.org>1999-02-24 22:36:05 +0000
commit0532902b4468dd0077e53b22b3ccbf2f409ca26e (patch)
tree843d815a52c4d7879e3e51ad04bcd6e533b29c8e
parentac584a07f76e50d29c32c02d92c215beb3185a8a (diff)
PF_KEY_V2, with local extensions for SPD management.
-rw-r--r--sys/net/pfkey.c308
-rw-r--r--sys/net/pfkeyv2.c1507
-rw-r--r--sys/net/pfkeyv2.h571
-rw-r--r--sys/net/pfkeyv2_parsemessage.c550
4 files changed, 2612 insertions, 324 deletions
diff --git a/sys/net/pfkey.c b/sys/net/pfkey.c
new file mode 100644
index 00000000000..e603d6a3bda
--- /dev/null
+++ b/sys/net/pfkey.c
@@ -0,0 +1,308 @@
+/*
+%%% copyright-nrl-97
+This software is Copyright 1997-1998 by Randall Atkinson, Ronald Lee,
+Daniel McDonald, Bao Phan, and Chris Winters. All Rights Reserved. All
+rights under this copyright have been assigned to the US Naval Research
+Laboratory (NRL). The NRL Copyright Notice and License Agreement Version
+1.1 (January 17, 1995) applies to this software.
+You should have received a copy of the license with this software. If you
+didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
+
+%%% copyright-cmetz-97
+This software is Copyright 1997-1998 by Craig Metz, All Rights Reserved.
+The Inner Net License Version 2 applies to this software.
+You should have received a copy of the license with this software. If
+you didn't get a copy, you may request one from <license@inner.net>.
+
+*/
+#include <sys/osdep.h>
+#include <sys/protosw.h>
+#include <sys/domain.h>
+#include <net/raw_cb.h>
+#include <sys/sysctl.h>
+#include <netinet/ip_ipsp.h>
+
+int pfkey_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+extern int encdebug;
+
+struct pfkey_version {
+ int protocol;
+ int (*create)(struct socket *socket);
+ int (*release)(struct socket *socket);
+ int (*send)(struct socket *socket, void *message, int len);
+};
+
+#define PFKEY_PROTOCOL_MAX 3
+static struct pfkey_version *pfkey_versions[PFKEY_PROTOCOL_MAX+1] = { NULL, NULL, NULL, NULL };
+
+#define PFKEY_MSG_MAXSZ 4096
+
+struct sockaddr pfkey_addr = { 2, PF_KEY, };
+
+/* static struct domain pfkey_domain; */
+static int pfkey_usrreq(struct socket *socket, int req, struct mbuf *mbuf,
+ struct mbuf *nam, struct mbuf *control);
+static int pfkey_output(struct mbuf *mbuf, struct socket *socket);
+
+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);
+int pfkeyv2_init(void);
+void pfkey_init(void);
+static int pfkey_buildprotosw(void);
+
+int
+pfkey_register(struct pfkey_version *version)
+{
+ int rval;
+
+ if ((version->protocol > PFKEY_PROTOCOL_MAX) || (version->protocol < 0))
+ return OSDEP_ERROR(EPROTONOSUPPORT);
+
+ if (pfkey_versions[version->protocol])
+ return OSDEP_ERROR(EADDRINUSE);
+
+ pfkey_versions[version->protocol] = version;
+
+ if ((rval = pfkey_buildprotosw()) != 0) {
+ pfkey_versions[version->protocol] = NULL;
+ return rval;
+ }
+
+ return 0;
+}
+
+int
+pfkey_unregister(struct pfkey_version *version)
+{
+ int rval;
+
+ if ((rval = pfkey_buildprotosw()) != 0)
+ return rval;
+
+ pfkey_versions[version->protocol] = NULL;
+ return 0;
+}
+
+int
+pfkey_sendup(struct socket *socket, struct mbuf *packet, int more)
+{
+ struct mbuf *packet2;
+
+ if (more) {
+ if (!(packet2 = m_copym(packet, 0, M_COPYALL, M_DONTWAIT)))
+ return ENOMEM;
+ } else
+ packet2 = packet;
+
+ if (!sbappendaddr(&socket->so_rcv, &pfkey_addr, packet2, NULL)) {
+ m_freem(packet2);
+ return 0;
+ }
+
+ sorwakeup(socket);
+ return 0;
+}
+
+static int
+pfkey_output(struct mbuf *mbuf, struct socket *socket)
+{
+ void *message;
+
+#if DIAGNOSTIC
+ if (!mbuf || !(mbuf->m_flags & M_PKTHDR))
+ return EINVAL;
+#endif /* DIAGNOSTIC */
+
+ if (mbuf->m_pkthdr.len > PFKEY_MSG_MAXSZ)
+ return EMSGSIZE;
+
+ if (!(message = malloc((unsigned long) mbuf->m_pkthdr.len, M_TEMP,
+ M_DONTWAIT)))
+ return ENOMEM;
+
+ m_copydata(mbuf, 0, mbuf->m_pkthdr.len, message);
+
+ return pfkey_versions[socket->so_proto->pr_protocol]->send(socket, message, mbuf->m_pkthdr.len);
+}
+
+static int
+pfkey_attach(struct socket *socket, struct mbuf *proto)
+{
+ int rval;
+ int s;
+
+ if (!(socket->so_pcb = malloc(sizeof(struct rawcb), M_PCB, M_DONTWAIT)))
+ return ENOMEM;
+ bzero(socket->so_pcb, sizeof(struct rawcb));
+
+ s = splnet();
+ rval = raw_usrreq(socket, PRU_ATTACH, NULL, proto, NULL);
+ splx(s);
+ if (rval)
+ goto ret;
+
+ ((struct rawcb *)socket->so_pcb)->rcb_faddr = &pfkey_addr;
+ soisconnected(socket);
+
+ socket->so_options |= SO_USELOOPBACK;
+ if ((rval = pfkey_versions[socket->so_proto->pr_protocol]->create(socket))
+ != 0)
+ goto ret;
+
+ return 0;
+
+ret:
+ free(socket->so_pcb, M_PCB);
+ return rval;
+}
+
+static int
+pfkey_detach(struct socket *socket)
+{
+ int rval, i, s;
+
+ rval = pfkey_versions[socket->so_proto->pr_protocol]->release(socket);
+ s = splnet();
+ i = raw_usrreq(socket, PRU_DETACH, NULL, NULL, NULL);
+ splx(s);
+
+ if (!rval)
+ rval = i;
+
+ return rval;
+}
+
+static int
+pfkey_usrreq(struct socket *socket, int req, struct mbuf *mbuf,
+ struct mbuf *nam, struct mbuf *control)
+{
+ int rval;
+ int s;
+
+ if ((socket->so_proto->pr_protocol > PFKEY_PROTOCOL_MAX) ||
+ (socket->so_proto->pr_protocol < 0) ||
+ !pfkey_versions[socket->so_proto->pr_protocol])
+ return EPROTONOSUPPORT;
+
+ switch(req) {
+ case PRU_ATTACH:
+ return pfkey_attach(socket, nam);
+
+ case PRU_DETACH:
+ return pfkey_detach(socket);
+
+ default:
+ s = splnet();
+ rval = raw_usrreq(socket, req, mbuf, nam, control);
+ splx(s);
+ }
+
+ return rval;
+}
+
+static struct domain pfkey_domain = {
+ PF_KEY,
+ "PF_KEY",
+ NULL, /* init */
+ NULL, /* externalize */
+ NULL, /* dispose */
+ NULL, /* protosw */
+ NULL, /* protoswNPROTOSW */
+ NULL, /* dom_next */
+ rn_inithead, /* dom_rtattach */
+ 16, /* rtoffset */
+ sizeof(struct sockaddr_encap) /* maxrtkey */
+};
+
+static struct protosw pfkey_protosw_template = {
+ SOCK_RAW,
+ &pfkey_domain,
+ -1, /* protocol */
+ PR_ATOMIC | PR_ADDR,
+ (void *) raw_input,
+ (void *) pfkey_output,
+ (void *) raw_ctlinput,
+ NULL, /* ctloutput */
+ pfkey_usrreq,
+ NULL, /* init */
+ NULL, /* fasttimo */
+ NULL, /* slowtimo */
+ NULL, /* drain */
+ pfkey_sysctl,
+};
+
+/* XXX fix this so it's reachable */
+int
+pfkey_sysctl(int *name, u_int namelen, void *oldp, size_t *oldplenp,
+ void *newp, size_t newlen)
+{
+ /* All sysctl names at this level are terminal */
+ if (namelen != 1)
+ return ENOTDIR;
+
+ switch (name[0])
+ {
+ case PFKEYCTL_ENCDEBUG:
+ return (sysctl_int(oldp, oldplenp, newp, newlen, &encdebug));
+
+ default:
+ return ENOPROTOOPT;
+ }
+ /* Not reached */
+}
+
+static int
+pfkey_buildprotosw(void)
+{
+ struct protosw *protosw, *p;
+ int i, j;
+
+ for (i = j = 0; i <= PFKEY_PROTOCOL_MAX; i++)
+ if (pfkey_versions[i])
+ j++;
+
+ if (j) {
+ if (!(protosw = malloc(j * sizeof(struct protosw), M_TEMP, M_DONTWAIT)))
+ return ENOMEM;
+
+ for (i = 0, p = protosw; i <= PFKEY_PROTOCOL_MAX; i++)
+ if (pfkey_versions[i]) {
+ bcopy(&pfkey_protosw_template, p, sizeof(struct protosw));
+ p->pr_protocol = pfkey_versions[i]->protocol;
+ p++;
+ }
+
+ if (pfkey_domain.dom_protosw)
+ free(pfkey_domain.dom_protosw, M_TEMP);
+
+ pfkey_domain.dom_protosw = protosw;
+ pfkey_domain.dom_protoswNPROTOSW = p;
+ } else {
+ if (!(protosw = malloc(sizeof(struct protosw), M_TEMP, M_DONTWAIT)))
+ return ENOMEM;
+
+ bcopy(&pfkey_protosw_template, protosw, sizeof(struct protosw));
+
+ if (pfkey_domain.dom_protosw)
+ free(pfkey_domain.dom_protosw, M_TEMP);
+
+ pfkey_domain.dom_protosw = protosw;
+ pfkey_domain.dom_protoswNPROTOSW = protosw;
+ }
+
+ return 0;
+}
+
+void pfkey_init(void)
+{
+ if (pfkey_buildprotosw() != 0)
+ return;
+
+ pfkey_domain.dom_next = domains;
+ domains = &pfkey_domain;
+
+#if KEY || CONFIG_PFKEY_V2
+ pfkeyv2_init();
+#endif /* KEY || CONFIG_PFKEY_V2 */
+}
diff --git a/sys/net/pfkeyv2.c b/sys/net/pfkeyv2.c
new file mode 100644
index 00000000000..b8d9c448a49
--- /dev/null
+++ b/sys/net/pfkeyv2.c
@@ -0,0 +1,1507 @@
+/*
+%%% copyright-nrl-97
+This software is Copyright 1997-1998 by Randall Atkinson, Ronald Lee,
+Daniel McDonald, Bao Phan, and Chris Winters. All Rights Reserved. All
+rights under this copyright have been assigned to the US Naval Research
+Laboratory (NRL). The NRL Copyright Notice and License Agreement Version
+1.1 (January 17, 1995) applies to this software.
+You should have received a copy of the license with this software. If you
+didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
+
+%%% copyright-cmetz-97
+This software is Copyright 1997-1998 by Craig Metz, All Rights Reserved.
+The Inner Net License Version 2 applies to this software.
+You should have received a copy of the license with this software. If
+you didn't get a copy, you may request one from <license@inner.net>.
+
+*/
+#include <sys/osdep.h>
+#include <net/pfkeyv2.h>
+#include <netinet/ip_ipsp.h>
+
+#define PFKEYV2_PROTOCOL 2
+#define GETSPI_TRIES 10
+
+struct pfkey_version {
+ int protocol;
+ int (*create)(OSDEP_SOCKET *socket);
+ int (*release)(OSDEP_SOCKET *socket);
+ int (*send)(OSDEP_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;
+ OSDEP_SOCKET *socket;
+ int flags;
+ uint32_t pid;
+};
+
+static struct pfkeyv2_socket *pfkeyv2_sockets = NULL;
+
+#if 0 /* XXX */
+static uint32_t pfkeyv2_seq = 1;
+#endif
+
+static int nregistered = 0;
+static int npromisc = 0;
+
+static struct sadb_alg ealgs[] = {
+{ SADB_EALG_DESCBC, 64, 64, 64 },
+{ SADB_EALG_3DESCBC, 64, 192, 192 },
+{ SADB_EALG_X_BLF, 64, 5, BLF_MAXKEYLEN},
+{ SADB_EALG_X_CAST, 64, 5, 16},
+{ SADB_EALG_X_SKIPJACK, 64, 10, 10},
+};
+
+static struct sadb_alg aalgs[] = {
+{ SADB_AALG_SHA1HMAC96, 0, 160, 160 },
+{ SADB_AALG_MD5HMAC96, 0, 128, 128 },
+{ SADB_AALG_X_RIPEMD160HMAC96, 0, 160, 160 }
+};
+
+extern int pfkey_register(struct pfkey_version *version);
+int pfkey_unregister(struct pfkey_version *version);
+int pfkey_sendup(OSDEP_SOCKET *socket, OSDEP_PACKET *packet, int more);
+int pfkeyv2_parsemessage(void *p, int len, void **headers);
+int pfkeyv2_acquire(void *);
+int pfkeyv2_init(void);
+int pfkeyv2_cleanup(void);
+int pfkeyv2_expire(struct tdb *);
+
+#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))
+
+static int
+pfkeyv2_create(OSDEP_SOCKET *socket)
+{
+ struct pfkeyv2_socket *pfkeyv2_socket;
+
+ if (!(pfkeyv2_socket = OSDEP_MALLOC(sizeof(struct pfkeyv2_socket))))
+ return OSDEP_ERROR(ENOMEM);
+
+ bzero(pfkeyv2_socket, sizeof(struct pfkeyv2_socket));
+ pfkeyv2_socket->next = pfkeyv2_sockets;
+ pfkeyv2_socket->socket = socket;
+ pfkeyv2_socket->pid = OSDEP_CURRENTPID;
+
+ pfkeyv2_sockets = pfkeyv2_socket;
+
+ return 0;
+}
+
+static int
+pfkeyv2_release(OSDEP_SOCKET *socket)
+{
+ struct pfkeyv2_socket **pp;
+
+ for (pp = &pfkeyv2_sockets;
+ *pp && ((*pp)->socket != socket);
+ pp = &((*pp)->next))
+ ;
+
+ if (*pp) {
+ struct pfkeyv2_socket *pfkeyv2_socket;
+
+ pfkeyv2_socket = *pp;
+ *pp = (*pp)->next;
+
+ if (pfkeyv2_socket->flags & PFKEYV2_SOCKETFLAGS_REGISTERED)
+ nregistered--;
+
+ if (pfkeyv2_socket->flags & PFKEYV2_SOCKETFLAGS_PROMISC)
+ npromisc--;
+
+ OSDEP_FREE(pfkeyv2_socket);
+ }
+
+ return 0;
+}
+
+static void
+import_sa(struct tdb *tdb, struct sadb_sa *sadb_sa, struct ipsecinit *ii)
+{
+ if (!sadb_sa)
+ return;
+
+ 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;
+
+ if (sadb_sa->sadb_sa_flags & SADB_SAFLAGS_PFS)
+ tdb->tdb_flags |= TDBF_PFS;
+
+ if (sadb_sa->sadb_sa_flags & SADB_SAFLAGS_X_HALFIV)
+ tdb->tdb_flags |= TDBF_HALFIV;
+
+ if (sadb_sa->sadb_sa_flags & SADB_SAFLAGS_X_TUNNEL)
+ tdb->tdb_flags |= TDBF_TUNNELING;
+ }
+
+ if (sadb_sa->sadb_sa_state != SADB_SASTATE_MATURE)
+ tdb->tdb_flags |= TDBF_INVALID;
+}
+
+static void
+export_sa(void **p, struct tdb *tdb)
+{
+ 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_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_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_flags & TDBF_PFS)
+ sadb_sa->sadb_sa_flags |= SADB_SAFLAGS_PFS;
+
+ if (tdb->tdb_flags & TDBF_HALFIV)
+ sadb_sa->sadb_sa_flags |= SADB_SAFLAGS_X_HALFIV;
+
+ if (tdb->tdb_flags & TDBF_TUNNELING)
+ sadb_sa->sadb_sa_flags |= SADB_SAFLAGS_X_TUNNEL;
+
+ *p += sizeof(struct sadb_sa);
+}
+
+static void
+import_lifetime(struct tdb *tdb, struct sadb_lifetime *sadb_lifetime, int type)
+{
+ struct expiration *exp;
+
+ 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 ((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;
+ exp = get_expiration();
+ bcopy(&tdb->tdb_dst, &exp->exp_dst, SA_LEN(&tdb->tdb_dst.sa));
+ exp->exp_spi = tdb->tdb_spi;
+ exp->exp_sproto = tdb->tdb_sproto;
+ exp->exp_timeout = tdb->tdb_exp_timeout;
+ put_expiration(exp);
+ }
+ 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;
+
+ 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;
+
+ 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;
+ exp = get_expiration();
+ bcopy(&tdb->tdb_dst, &exp->exp_dst, SA_LEN(&tdb->tdb_dst.sa));
+ exp->exp_spi = tdb->tdb_spi;
+ exp->exp_sproto = tdb->tdb_sproto;
+ exp->exp_timeout = tdb->tdb_soft_timeout;
+ put_expiration(exp);
+ }
+ 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;
+
+ 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;
+ }
+}
+
+static 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;
+
+ 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);
+}
+
+static 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;
+#if INET6
+ case AF_INET6:
+ salen = sizeof(struct sockaddr_in6);
+ break;
+#endif /* INET6 */
+ default:
+ return;
+ }
+
+ bcopy(ssa, sa, salen);
+ sa->sa_len = salen;
+}
+
+static void
+export_address(void **p, struct sockaddr *sa)
+{
+ 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);
+
+ *p += sizeof(struct sadb_address);
+
+ bcopy(sa, *p, SA_LEN(sa));
+
+#if !OSDEP_SALEN
+ ((struct sockaddr *)*p)->sa_family = sa->sa_family;
+#endif /* !OSDEP_SALEN */
+
+ *p += PADUP(SA_LEN(sa));
+}
+
+static 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);
+ }
+}
+
+static 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);
+ }
+}
+
+static void
+import_key(struct ipsecinit *ii, struct sadb_key *sadb_key, int type)
+{
+ 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);
+ }
+}
+
+static int
+pfkeyv2_sendmessage(void **headers, int mode, OSDEP_SOCKET *socket)
+{
+ int i, j, rval;
+ void *p, *buffer = NULL;
+ OSDEP_PACKET *packet;
+ struct pfkeyv2_socket *s;
+
+ 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);
+
+ if (!(buffer = OSDEP_MALLOC(j + sizeof(struct sadb_msg)))) {
+ rval = OSDEP_ERROR(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]);
+ }
+
+ if ((rval = OSDEP_DATATOPACKET(buffer + sizeof(struct sadb_msg),
+ j, &packet)) != 0)
+ goto ret;
+
+ 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 = OSDEP_DATATOPACKET(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);
+
+ OSDEP_ZEROPACKET(packet);
+ OSDEP_FREEPACKET(packet);
+ break;
+
+ case PFKEYV2_SENDMESSAGE_REGISTERED:
+ for (s = pfkeyv2_sockets; s; s = s->next)
+ if (s->flags & PFKEYV2_SOCKETFLAGS_REGISTERED)
+ pfkey_sendup(s->socket, packet, 1);
+
+ OSDEP_FREEPACKET(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 = OSDEP_DATATOPACKET(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);
+
+ OSDEP_FREEPACKET(packet);
+ break;
+
+ case PFKEYV2_SENDMESSAGE_BROADCAST:
+ for (s = pfkeyv2_sockets; s; s = s->next)
+ pfkey_sendup(s->socket, packet, 1);
+
+ OSDEP_FREEPACKET(packet);
+ break;
+ }
+
+ret:
+ bzero(buffer, j + sizeof(struct sadb_msg));
+ OSDEP_FREE(buffer);
+ return rval;
+}
+
+extern uint32_t sadb_exts_allowed_out[SADB_MAX+1];
+extern uint32_t sadb_exts_required_out[SADB_MAX+1];
+
+static int
+pfkeyv2_get(struct tdb *sa, void **headers, void **buffer)
+{
+ int rval, i;
+ void *p;
+
+ 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_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_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_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 (!(p = OSDEP_MALLOC(i))) {
+ rval = OSDEP_ERROR(ENOMEM);
+ goto ret;
+ }
+
+ *buffer = p;
+
+ bzero(p, i);
+
+ headers[SADB_EXT_SA] = p;
+ export_sa(&p, sa);
+
+ headers[SADB_EXT_LIFETIME_CURRENT] = p;
+ export_lifetime(&p, sa, 2);
+
+ 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_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);
+ }
+
+ 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);
+
+ 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);
+ }
+
+ if (sa->tdb_dstid_len) {
+ headers[SADB_EXT_IDENTITY_DST] = p;
+ export_identity(&p, sa, 1);
+ }
+
+ rval = 0;
+
+ret:
+ return rval;
+}
+
+struct dump_state {
+ struct sadb_msg *sadb_msg;
+ OSDEP_SOCKET *socket;
+};
+
+#if 0 /* XXX Need to add a tdb_walk routine for this to work */
+static 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;
+
+ 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);
+ OSDEP_FREE(buffer);
+ if (rval)
+ return rval;
+ }
+
+ return 0;
+}
+#endif /* 0 */
+
+static int
+pfkeyv2_send(OSDEP_SOCKET *socket, void *message, int len)
+{
+ void *headers[SADB_EXT_MAX + 1];
+ int i, j, rval = 0, mode = PFKEYV2_SENDMESSAGE_BROADCAST, delflag = 0;
+ struct pfkeyv2_socket *pfkeyv2_socket, *s = NULL;
+ void *freeme = NULL, *bckptr = NULL;
+ struct tdb sa, *sa2 = 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 = OSDEP_ERROR(EINVAL);
+ goto ret;
+ }
+
+ if (npromisc) {
+ OSDEP_PACKET *packet;
+
+ if (!(freeme = OSDEP_MALLOC(sizeof(struct sadb_msg) + len))) {
+ rval = OSDEP_ERROR(ENOMEM);
+ 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 = OSDEP_CURRENTPID;
+
+ bcopy(message, freeme + sizeof(struct sadb_msg), len);
+
+ if ((rval = OSDEP_DATATOPACKET(freeme, sizeof(struct sadb_msg) + len,
+ &packet)) != 0)
+ goto ret;
+
+ for (s = pfkeyv2_sockets; s; s = s->next)
+ if (s->flags & PFKEYV2_SOCKETFLAGS_PROMISC)
+ pfkey_sendup(s->socket, packet, 1);
+
+ OSDEP_ZEROPACKET(packet);
+ OSDEP_FREEPACKET(packet);
+
+ bzero(freeme, sizeof(struct sadb_msg) + len);
+ OSDEP_FREE(freeme);
+ freeme = NULL;
+ }
+
+ if ((rval = pfkeyv2_parsemessage(message, len, headers)) != 0)
+ goto ret;
+
+ switch(((struct sadb_msg *)headers[0])->sadb_msg_type) {
+ case SADB_GETSPI:
+ bzero(&sa, sizeof(struct tdb));
+
+ switch (((struct sadb_msg *)headers[0])->sadb_msg_satype) {
+ case SADB_SATYPE_AH:
+ sa.tdb_sproto = IPPROTO_AH;
+ break;
+
+ case SADB_SATYPE_ESP:
+ sa.tdb_sproto = IPPROTO_ESP;
+ break;
+
+ case SADB_SATYPE_X_AH_OLD:
+ sa.tdb_sproto = IPPROTO_AH;
+ break;
+
+ case SADB_SATYPE_X_ESP_OLD:
+ sa.tdb_sproto = IPPROTO_ESP;
+ break;
+
+ case SADB_SATYPE_X_IPIP:
+ sa.tdb_sproto = IPPROTO_IPIP;
+ break;
+
+ default: /* Nothing else supported */
+ rval = EOPNOTSUPP;
+ 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]);
+
+ 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;
+
+ if (!(freeme = OSDEP_MALLOC(sizeof(struct sadb_sa)))) {
+ rval = OSDEP_ERROR(ENOMEM);
+ goto ret;
+ }
+
+ 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:
+ 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 ret;
+ }
+
+ if (sa2->tdb_flags & TDBF_INVALID) {
+ MALLOC(freeme, struct tdb *, sizeof(struct tdb), M_TDB, M_WAITOK);
+ if (freeme == NULL) {
+ rval = ENOMEM;
+ goto ret;
+ }
+
+ bzero(freeme, sizeof(struct tdb));
+
+ {
+ struct tdb *newsa = (struct tdb *)freeme;
+ struct ipsecinit ii;
+ int alg;
+
+ bzero(&ii, sizeof(struct ipsecinit));
+ switch (((struct sadb_msg *)headers[0])->sadb_msg_satype) {
+ case SADB_SATYPE_AH:
+ newsa->tdb_sproto = IPPROTO_AH;
+ alg = XF_NEW_AH;
+ break;
+
+ case SADB_SATYPE_ESP:
+ newsa->tdb_sproto = IPPROTO_ESP;
+ alg = XF_NEW_ESP;
+ break;
+
+ case SADB_SATYPE_X_AH_OLD:
+ newsa->tdb_sproto = IPPROTO_AH;
+ alg = XF_OLD_AH;
+ break;
+
+ case SADB_SATYPE_X_ESP_OLD:
+ newsa->tdb_sproto = IPPROTO_ESP;
+ alg = XF_OLD_ESP;
+ break;
+
+ case SADB_SATYPE_X_IPIP:
+ newsa->tdb_sproto = IPPROTO_IPIP;
+ alg = XF_IP4;
+ break;
+
+ default: /* Nothing else supported */
+ rval = EOPNOTSUPP;
+ goto ret;
+ }
+
+ 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);
+
+ rval = tdb_init(newsa, alg, &ii);
+ if (rval) {
+ rval = OSDEP_ERROR(EINVAL);
+ tdb_delete(freeme, 0);
+ freeme = NULL;
+ goto ret;
+ }
+ }
+
+ headers[SADB_EXT_KEY_AUTH] = NULL;
+ headers[SADB_EXT_KEY_ENCRYPT] = NULL;
+
+ tdb_delete(sa2, 0);
+ 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 = OSDEP_ERROR(EINVAL);
+ goto ret;
+ }
+
+ 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);
+ }
+ break;
+
+ case SADB_ADD:
+ 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 ret;
+ }
+
+ if (((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_state !=
+ SADB_SASTATE_MATURE) {
+ rval = OSDEP_ERROR(EINVAL);
+ goto ret;
+ }
+
+ MALLOC(freeme, struct tdb *, sizeof(struct tdb), M_TDB, M_WAITOK);
+ if (freeme == NULL) {
+ rval = ENOMEM;
+ goto ret;
+ }
+
+ bzero(freeme, sizeof(struct tdb));
+
+ {
+ struct tdb *newsa = (struct tdb *) freeme;
+ struct ipsecinit ii;
+ int alg;
+
+ bzero(&ii, sizeof(struct ipsecinit));
+ switch (((struct sadb_msg *)headers[0])->sadb_msg_satype) {
+ case SADB_SATYPE_AH:
+ newsa->tdb_sproto = IPPROTO_AH;
+ alg = XF_NEW_AH;
+ break;
+
+ case SADB_SATYPE_ESP:
+ newsa->tdb_sproto = IPPROTO_ESP;
+ alg = XF_NEW_ESP;
+ break;
+
+ case SADB_SATYPE_X_AH_OLD:
+ newsa->tdb_sproto = IPPROTO_AH;
+ alg = XF_OLD_AH;
+ break;
+
+ case SADB_SATYPE_X_ESP_OLD:
+ newsa->tdb_sproto = IPPROTO_ESP;
+ alg = XF_OLD_ESP;
+ break;
+
+ case SADB_SATYPE_X_IPIP:
+ newsa->tdb_sproto = IPPROTO_IPIP;
+ alg = XF_IP4;
+ break;
+
+ default: /* Nothing else supported */
+ rval = EOPNOTSUPP;
+ goto ret;
+ }
+
+ 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);
+
+ rval = tdb_init(newsa, alg, &ii);
+ if (rval) {
+ rval = OSDEP_ERROR(EINVAL);
+ tdb_delete(freeme, 0);
+ freeme = NULL;
+ goto ret;
+ }
+ }
+
+ headers[SADB_EXT_KEY_AUTH] = NULL;
+ headers[SADB_EXT_KEY_ENCRYPT] = NULL;
+
+ puttdb((struct tdb *)freeme);
+ freeme = NULL;
+ break;
+
+ case SADB_DELETE:
+ 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 ret;
+ }
+
+ tdb_delete(sa2, ((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_flags & SADB_SAFLAGS_X_CHAINDEL);
+ sa2 = NULL;
+ break;
+
+ case SADB_GET:
+ 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 ret;
+ }
+
+ rval = pfkeyv2_get(sa2, headers, &freeme);
+ if (rval)
+ mode = PFKEYV2_SENDMESSAGE_UNICAST;
+ break;
+
+ case SADB_REGISTER:
+ pfkeyv2_socket->flags |= PFKEYV2_SOCKETFLAGS_REGISTERED;
+ nregistered++;
+
+ i = sizeof(struct sadb_supported) + sizeof(ealgs) + sizeof(aalgs);
+
+ if (!(freeme = OSDEP_MALLOC(i))) {
+ rval = OSDEP_ERROR(ENOMEM);
+ goto ret;
+ }
+
+ 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);
+
+ {
+ void *p = freeme + sizeof(struct sadb_supported);
+
+ bcopy(&aalgs[0], p, sizeof(aalgs));
+ p += sizeof(aalgs);
+ bcopy(&ealgs[0], p, sizeof(ealgs));
+ }
+
+ headers[SADB_EXT_SUPPORTED] = freeme;
+ break;
+
+ case SADB_ACQUIRE:
+ rval = 0;
+ break;
+
+ case SADB_EXPIRE:
+ rval = 0;
+ break;
+
+ case SADB_FLUSH:
+/* XXX netsec_sadb_flush(((struct sadb_msg *)headers[0])->sadb_msg_satype); */
+ rval = 0;
+ break;
+
+ case SADB_DUMP:
+ {
+ struct dump_state dump_state;
+ dump_state.sadb_msg = (struct sadb_msg *)headers[0];
+ dump_state.socket = socket;
+
+/** XXX
+ if (!(rval = netsec_sadb_walk(pfkeyv2_dump_walker, &dump_state, 1)))
+ goto realret;
+*/
+ if ((rval == OSDEP_ERROR(ENOMEM)) || (rval == OSDEP_ERROR(ENOBUFS)))
+ rval = 0;
+ }
+ 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 *flow = NULL, *flow2 = NULL;
+ union sockaddr_union *src, *dst, *srcmask, *dstmask;
+ union sockaddr_union alts, altm;
+ u_int8_t sproto = 0, local = 0;
+
+ if (!delflag)
+ {
+ 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 ret;
+ }
+ }
+
+ local = ((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_flags &
+ SADB_SAFLAGS_X_LOCALFLOW;
+ bzero(&encapdst, sizeof(struct sockaddr_encap));
+ bzero(&encapnetmask, sizeof(struct sockaddr_encap));
+ bzero(&encapgw, sizeof(struct sockaddr_encap));
+ bzero(&alts, sizeof(alts));
+ bzero(&altm, sizeof(altm));
+
+ src = (union sockaddr_union *) (headers[SADB_EXT_X_SRC_FLOW] + sizeof(struct sadb_address));
+ dst = (union sockaddr_union *) (headers[SADB_EXT_X_DST_FLOW] + sizeof(struct sadb_address));
+ srcmask = (union sockaddr_union *) (headers[SADB_EXT_X_SRC_MASK] + sizeof(struct sadb_address));
+ dstmask = (union sockaddr_union *) (headers[SADB_EXT_X_DST_MASK] + sizeof(struct sadb_address));
+
+ if (headers[SADB_EXT_X_PROTOCOL])
+ sproto = ((struct sadb_protocol *) headers[SADB_EXT_X_PROTOCOL])->sadb_protocol_proto;
+ else
+ sproto = 0;
+
+ src->sin.sin_addr.s_addr &= srcmask->sin.sin_addr.s_addr;
+ dst->sin.sin_addr.s_addr &= dstmask->sin.sin_addr.s_addr;
+
+ flow = find_global_flow(src, srcmask, dst, dstmask, sproto);
+ if ((delflag && (flow == NULL)) ||
+ (!delflag && (flow != NULL)))
+ {
+ rval = EEXIST;
+ goto ret;
+ }
+
+ /* Check for 0.0.0.0/255.255.255.255 if the flow is local */
+ if (local)
+ {
+ alts.sin.sin_family = altm.sin.sin_family = AF_INET;
+ alts.sin.sin_len = altm.sin.sin_len = sizeof(struct sockaddr_in);
+ alts.sin.sin_addr.s_addr = INADDR_ANY;
+ altm.sin.sin_addr.s_addr = INADDR_BROADCAST;
+
+ flow2 = find_global_flow(&alts, &altm, dst, dstmask, sproto);
+ if ((delflag && (flow2 == NULL)) ||
+ (!delflag && (flow2 != NULL)))
+ {
+ rval = EEXIST;
+ goto ret;
+ }
+ }
+
+ if (!delflag)
+ {
+ 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 (local)
+ {
+ flow2 = get_flow();
+ bcopy(&alts, &flow2->flow_src, alts.sa.sa_len);
+ bcopy(dst, &flow2->flow_dst, dst->sa.sa_len);
+ bcopy(&altm, &flow2->flow_srcmask, altm.sa.sa_len);
+ bcopy(dstmask, &flow2->flow_dstmask, dstmask->sa.sa_len);
+ flow2->flow_proto = sproto;
+ put_flow(flow2, sa2);
+ }
+ }
+
+ /* Setup the encap fields */
+ encapdst.sen_len = SENT_IP4_LEN;
+ encapdst.sen_family = PF_KEY;
+ 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;
+
+ if (!delflag)
+ {
+ 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;
+ }
+
+ 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;
+
+ 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;
+ }
+
+ /* 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);
+ ipsec_in_use--;
+ }
+ else
+ {
+ 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 ret;
+ }
+
+ ipsec_in_use++;
+ }
+
+ /* If this is a "local" packet flow */
+ if (local)
+ {
+ encapdst.sen_ip_src.s_addr = INADDR_ANY;
+ encapnetmask.sen_ip_src.s_addr = INADDR_BROADCAST;
+
+ if (delflag)
+ {
+ rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst,
+ (struct sockaddr *) 0,
+ (struct sockaddr *) &encapnetmask, 0,
+ (struct rtentry **) 0);
+
+ delete_flow(flow2, flow2->flow_sa);
+ ipsec_in_use--;
+ }
+ else
+ {
+ 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 the first entry inserted */
+ encapdst.sen_ip_src = flow->flow_src.sin.sin_addr;
+ encapnetmask.sen_ip_src = flow->flow_srcmask.sin.sin_addr;
+
+ rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst,
+ (struct sockaddr *) 0,
+ (struct sockaddr *) &encapnetmask, 0,
+ (struct rtentry **) 0);
+
+ delete_flow(flow, sa2);
+ delete_flow(flow2, sa2);
+ ipsec_in_use--;
+ goto ret;
+ }
+
+ ipsec_in_use++;
+ }
+ }
+ }
+
+ break;
+
+ case SADB_X_GRPSPIS:
+ {
+ struct tdb *tdb1, *tdb2, *tdb3;
+
+ 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 = EEXIST;
+ goto ret;
+ }
+
+ tdb2 = gettdb(((struct sadb_sa *)headers[SADB_EXT_X_SA2])->sadb_sa_spi,
+ (union sockaddr_union *)(headers[SADB_EXT_X_DST2] +
+ sizeof(struct sadb_address)),
+ SADB_GETSPROTO(((struct sadb_protocol *)headers[SADB_EXT_X_PROTOCOL])->sadb_protocol_proto));
+
+ if (tdb2 == NULL) {
+ rval = EEXIST;
+ goto ret;
+ }
+
+ /* Detect cycles */
+ for (tdb3 = tdb2; tdb3; tdb3 = tdb3->tdb_onext)
+ if (tdb3 == tdb1)
+ {
+ rval = EINVAL;
+ goto ret;
+ }
+
+ /* Maintenance */
+ if ((tdb1->tdb_onext) &&
+ (tdb1->tdb_onext->tdb_inext == tdb1))
+ tdb1->tdb_onext->tdb_inext = NULL;
+
+ /* Link them */
+ tdb1->tdb_onext = tdb2;
+ tdb2->tdb_inext = tdb1;
+ }
+
+ break;
+
+ case SADB_X_PROMISC:
+ if (len >= 2 * sizeof(struct sadb_msg)) {
+ OSDEP_PACKET *packet;
+
+ if ((rval = OSDEP_DATATOPACKET(message, len, &packet)) != 0)
+ goto ret;
+
+ for (s = pfkeyv2_sockets; s; s = s->next)
+ if ((s != pfkeyv2_socket) &&
+ (!((struct sadb_msg *)headers[0])->sadb_msg_seq ||
+ (((struct sadb_msg *)headers[0])->sadb_msg_seq ==
+ pfkeyv2_socket->pid)))
+ pfkey_sendup(s->socket, packet, 1);
+
+ OSDEP_FREEPACKET(packet);
+ } else {
+ if (len != sizeof(struct sadb_msg)) {
+ rval = OSDEP_ERROR(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 = OSDEP_ERROR(EINVAL);
+ goto ret;
+ }
+
+ret:
+ if (rval < 0) {
+ if ((rval == OSDEP_ERROR(EINVAL)) || (rval == OSDEP_ERROR(ENOMEM)) ||
+ (rval == OSDEP_ERROR(ENOBUFS)))
+ goto realret;
+ for (i = 1; i <= SADB_EXT_MAX; i++)
+ headers[i] = NULL;
+ ((struct sadb_msg *)headers[0])->sadb_msg_errno = -rval;
+ } else {
+ uint32_t seen = 0;
+
+ for (i = 1; i <= SADB_EXT_MAX; i++)
+ if (headers[i])
+ seen |= (1 << i);
+
+ if ((seen & sadb_exts_allowed_out[((struct sadb_msg *)headers[0])->sadb_msg_type]) != seen) {
+ goto realret;
+ }
+
+ 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;
+ }
+ }
+
+ rval = pfkeyv2_sendmessage(headers, mode, socket);
+
+realret:
+ if (freeme)
+ OSDEP_FREE(freeme);
+ OSDEP_FREE(message);
+
+ return rval;
+}
+
+int
+pfkeyv2_acquire(void *os)
+{
+#if 0
+ int rval = 0;
+ int i, j;
+ void *p, *headers[SADB_EXT_MAX+1], *buffer;
+
+ if (!nregistered) {
+ rval = OSDEP_ERROR(ESRCH);
+ goto ret;
+ }
+
+ i = sizeof(struct sadb_msg) + sizeof(struct sadb_address) +
+ PADUP(SA_LEN(&os->src.sa)) + sizeof(struct sadb_address) +
+ PADUP(SA_LEN(&os->dst.sa)) + sizeof(struct sadb_prop) +
+ os->nproposals * sizeof(struct sadb_comb) +
+ 2 * sizeof(struct sadb_ident);
+
+ if (os->rekeysa)
+ i += PADUP(os->rekeysa->srcident.bytes) +
+ PADUP(os->rekeysa->dstident.bytes);
+
+ if (!(p = OSDEP_MALLOC(i))) {
+ rval = OSDEP_ERROR(ENOMEM);
+ goto ret;
+ }
+
+ bzero(headers, sizeof(headers));
+
+ 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_ACQUIRE;
+ ((struct sadb_msg *)headers[0])->sadb_msg_satype = os->satype;
+ ((struct sadb_msg *)headers[0])->sadb_msg_len = i / sizeof(uint64_t);
+ ((struct sadb_msg *)headers[0])->sadb_msg_seq = pfkeyv2_seq++;
+
+ headers[SADB_EXT_ADDRESS_SRC] = p;
+ p += sizeof(struct sadb_address) + PADUP(SA_LEN(&os->src.sa));
+ ((struct sadb_address *)headers[SADB_EXT_ADDRESS_SRC])->sadb_address_len = (sizeof(struct sadb_address) + SA_LEN(&os->src.sa) + sizeof(uint64_t) - 1) / sizeof(uint64_t);
+ bcopy(&os->src, headers[SADB_EXT_ADDRESS_SRC] + sizeof(struct sadb_address),
+ SA_LEN(&os->src.sa));
+
+ headers[SADB_EXT_ADDRESS_DST] = p;
+ p += sizeof(struct sadb_address) + PADUP(SA_LEN(&os->dst.sa));
+ ((struct sadb_address *)headers[SADB_EXT_ADDRESS_DST])->sadb_address_len = (sizeof(struct sadb_address) + SA_LEN(&os->dst.sa) + sizeof(uint64_t) - 1) / sizeof(uint64_t);
+ bcopy(&os->dst, headers[SADB_EXT_ADDRESS_DST] + sizeof(struct sadb_address),
+ SA_LEN(&os->dst.sa));
+
+ headers[SADB_EXT_IDENTITY_SRC] = p;
+ p += sizeof(struct sadb_ident);
+ ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC])->sadb_ident_type = os->srcidenttype;
+ ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC])->sadb_ident_id = os->srcidentid;
+ if (os->rekeysa) {
+ ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC])->sadb_ident_len = (sizeof(struct sadb_ident) + PADUP(os->rekeysa->srcident.bytes)) / sizeof(uint64_t);
+ bcopy(os->rekeysa->srcident.data, p, os->rekeysa->srcident.bytes);
+ p += PADUP(os->rekeysa->srcident.bytes);
+ } else
+ ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC])->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_SRC])->sadb_ident_type = os->dstidenttype;
+ ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_SRC])->sadb_ident_id = os->dstidentid;
+ if (os->rekeysa) {
+ ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_DST])->sadb_ident_len = (sizeof(struct sadb_ident) + PADUP(os->rekeysa->dstident.bytes)) / sizeof(uint64_t);
+ bcopy(os->rekeysa->dstident.data, p, os->rekeysa->dstident.bytes);
+ p += PADUP(os->rekeysa->srcident.bytes);
+ } else
+ ((struct sadb_ident *)headers[SADB_EXT_IDENTITY_DST])->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) * os->nproposals) / sizeof(uint64_t);
+ ((struct sadb_prop *)headers[SADB_EXT_PROPOSAL])->sadb_prop_num = os->nproposals;
+
+ {
+ struct sadb_comb *sadb_comb = p;
+ struct netsec_sadb_proposal *proposal = os->proposals;
+
+ for (j = 0; j < os->nproposals; j++) {
+ sadb_comb->sadb_comb_auth = proposal->auth;
+ sadb_comb->sadb_comb_encrypt = proposal->encrypt;
+ sadb_comb->sadb_comb_flags = proposal->flags;
+ sadb_comb->sadb_comb_auth_minbits = proposal->auth_minbits;
+ sadb_comb->sadb_comb_auth_maxbits = proposal->auth_maxbits;
+ sadb_comb->sadb_comb_encrypt_minbits = proposal->encrypt_minbits;
+ sadb_comb->sadb_comb_encrypt_maxbits = proposal->encrypt_maxbits;
+ sadb_comb->sadb_comb_soft_allocations = proposal->soft.allocations;
+ sadb_comb->sadb_comb_hard_allocations = proposal->hard.allocations;
+ sadb_comb->sadb_comb_soft_bytes = proposal->soft.bytes;
+ sadb_comb->sadb_comb_hard_bytes = proposal->hard.bytes;
+ sadb_comb->sadb_comb_soft_addtime = proposal->soft.addtime;
+ sadb_comb->sadb_comb_hard_addtime = proposal->hard.addtime;
+ sadb_comb->sadb_comb_soft_usetime = proposal->soft.usetime;
+ sadb_comb->sadb_comb_hard_usetime = proposal->hard.usetime;
+ sadb_comb++;
+ proposal++;
+ }
+ }
+
+ if ((rval = pfkeyv2_sendmessage(headers, PFKEYV2_SENDMESSAGE_REGISTERED,
+ NULL))!= 0)
+ goto ret;
+
+ rval = 0;
+
+ret:
+ return rval;
+#endif
+ return 0;
+}
+
+int
+pfkeyv2_expire(struct tdb *sa)
+{
+ /* XXX missing */
+ return 0;
+}
+
+int
+pfkeyv2_init(void)
+{
+ 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;
+
+ rval = pfkey_register(&pfkeyv2_version);
+ return rval;
+}
+
+int
+pfkeyv2_cleanup(void)
+{
+ pfkey_unregister(&pfkeyv2_version);
+ return 0;
+}
diff --git a/sys/net/pfkeyv2.h b/sys/net/pfkeyv2.h
index 8e6d0ce7d69..2f542ebfb9b 100644
--- a/sys/net/pfkeyv2.h
+++ b/sys/net/pfkeyv2.h
@@ -1,325 +1,248 @@
-/* $OpenBSD: pfkeyv2.h,v 1.4 1997/11/07 08:29:53 niklas Exp $ */
-
/*
- * The author of this code is Angelos D. Keromytis, angelos@openbsd.org
- * (except when noted otherwise).
- *
- * Copyright (C) 1997, 1998, 1999 by John Ioannidis and Angelos D. Keromytis.
- *
- * Permission to use, copy, and modify this software without fee
- * is hereby granted, provided that this entire notice is included in
- * all copies of any software which is or includes a copy or
- * modification of this software.
- *
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTY. IN PARTICULAR, NEITHER AUTHOR MAKES ANY
- * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
- * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
- * PURPOSE.
- */
-
-
-/*
- * PF_KEYv2 definitions
- */
-
-#define PF_KEY_V2 0
-
-struct pfkeycb
-{
- LIST_ENTRY(pfkeycb) pfkey_list;
- struct socket *pfkey_socket;
- struct sockaddr *pfkey_faddr;
- struct sockaddr *pfkey_laddr;
- struct sockproto pfkey_proto;
- u_int32_t pfkey_flags;
-#define PFKEYv2_REGISTERED 0x1
-};
-
-struct sadb_msg
-{
- u_int8_t sadb_msg_version; /* Must be PF_KEY_V2 */
- u_int8_t sadb_msg_type;
- u_int8_t sadb_msg_errno; /* Should be zero for messages to kernel */
- u_int8_t sadb_msg_sa_type;
- u_int16_t sadb_msg_len; /* In 32-bit words, inclusive */
- u_int16_t sadb_msg_reserved; /* Set to zero */
- u_int32_t sadb_msg_seq;
- u_int32_t sadb_msg_pid; /* PID of originating process, 0 if kernel */
-};
-
-
-struct sadb_hdr
-{
- u_int16_t sadb_hdr_len; /* In 32-bit words, inclusive */
- u_int16_t sadb_hdr_hdrtype; /* 0 is reserved */
-};
-
-struct sadb_sa
-{
- u_int16_t sadb_sa_len; /* In 32-bit words, inclusive */
- u_int16_t sadb_sa_hdrtype; /* ASSOCIATION */
- u_int16_t sadb_sa_spi; /* Network byte order */
- u_int8_t sadb_sa_replay_window_len; /* Set to 0 if not in use */
- u_int8_t sadb_sa_state; /* Set to zero by sending process */
- u_int8_t sadb_sa_encrypt; /* Encryption algorithm */
- u_int8_t sadb_sa_auth; /* Authentication algorithm */
- u_int32_t sadb_sa_flags; /* Bitmask */
-};
-
-struct sadb_lifetime
-{
- u_int16_t sadb_lifetime_len; /* In 32-bit words, inclusive */
- u_int16_t sadb_lifetime_hdrtype; /* LIFETIME */
- u_int8_t sadb_lifetime_which; /* Bitmask */
- u_int8_t sadb_lifetime_reserved[3]; /* Padding */
-};
-
-struct sadb_lifetime_val
-{
- u_int8_t sadb_lifetime_val_which; /* Corresponds to lifetime_which */
- u_int8_t sadb_lifetime_val_reserved;
- u_int16_t sadb_lifetime_val_allocations; /* How many "flows" to use for */
- u_int32_t sadb_lifetime_val_bytes; /* Number of bytes before expr */
- time_t sadb_lifetime_val_absolute;
- time_t sadb_lifetime_val_updatetime;
- time_t sadb_lifetime_val_usetime;
-};
-
-struct sadb_address
-{
- u_int16_t sadb_address_len; /* In 32-bit words, inclusive */
- u_int16_t sadb_address_hdrtype; /* ADDRESS */
- u_int8_t sadb_address_which; /* Bitmask */
- u_int8_t sadb_address_reserved[3]; /* Padding */
- /* Followed by one or more sockaddr structures */
-};
-
-struct sadb_keyblk
-{
- u_int16_t sadb_keyblk_len; /* In 32-bit words, inclusive */
- u_int16_t sadb_keyblk_hdrtype; /* KEY */
- u_int8_t sadb_keyblk_which; /* Bitmask */
- u_int8_t sadb_keyblk_reserved[3]; /* Padding */
- /* Followed by sadb_key */
-};
-
-struct sadb_key
-{
- u_int16_t sadb_key_len; /* Length of key in bits */
- u_int16_t sadb_key_which; /* Corresponds to keyblk_which */
- u_int8_t sadb_key_type; /* 3DES, DES, HMAC-MD5, etc. */
- /* Actual key follows */
-};
-
-struct sadb_id
-{
- u_int16_t sadb_id_len; /* In 32-bit words, inclusive */
- u_int16_t sadb_id_hdrtype; /* IDENTITY */
- u_int8_t sadb_id_which; /* Bitmask */
- u_int8_t sadb_id_reserved[3]; /* Padding */
- /* Followed by one or more sadb_certids */
-};
-
-struct sadb_certid
-{
- u_int16_t sadb_certid_len; /* In 32-bit words, inclusive */
- u_int16_t sadb_certid_type;
- /* Cert id. follows */
-};
-
-struct sadb_sens
-{
- u_int16_t sadb_sens_len; /* In 32-bit words, inclusive */
- u_int16_t sadb_sens_hdrtype; /* SENSITIVITY */
- u_int32_t sadb_sens_dpd; /* Protection Domain */
- u_int8_t sadb_sens_level;
- u_int8_t sadb_sens_sens_bitmap_len; /* In 32-bit words */
- u_int8_t sadb_sens_integ_level;
- u_int8_t sadb_sens_integ_bitmap_len; /* In 32-bit words */
- /*
- * Followed by 2 u_int32_t arrays
- * u_int32_t sadb_sens_bitmap[sens_bitmap_len];
- * u_int32_t integ_bitmap[integ_bitmap_len];
- */
-};
-
-struct sadb_prop
-{
- u_int16_t sadb_prop_len; /* In 32-bit words, inclusive */
- u_int16_t sadb_prop_hdrtype; /* PROPOSAL */
- u_int8_t sadb_prop_num;
- u_int8_t sadb_prop_replay; /* Replay window size */
- u_int16_t sadb_prop_reserved;
-};
-
-struct sadb_comb
-{
- u_int8_t sadb_comb_auth;
- u_int8_t sadb_comb_encr;
- u_int16_t sadb_comb_flags;
- u_int16_t sadb_comb_auth_keylen_min;
- u_int16_t sadb_comb_auth_keylen_max;
- u_int16_t sadb_comb_encr_keylen_min;
- u_int16_t sadb_comb_encr_keylen_max;
-};
-
-struct sadb_alg
-{
- u_int16_t sadb_alg_len; /* In 32-bit words, inclusive */
- u_int16_t sadb_alg_hdrtype; /* SUPPORTED */
- u_int8_t sadb_alg_num_auth; /* Number of auth algorithms */
- u_int8_t sadb_alg_num_encrypt;
- /* Followed by one or more sadb_algd */
-};
-
-struct sadb_algd
-{
- u_int8_t sadb_algd_type; /* Algorithm type */
- u_int8_t sadb_algd_ivlen; /* IV len, in bits */
- u_int16_t sadb_algd_minlen; /* Minimum key length, in bits */
- u_int16_t sadb_algd_maxlen; /* Maximum key length, in bits */
- u_int16_t sadb_algd_reserved;
-};
-
-struct sadb_spirange
-{
- u_int16_t sadb_spirage_len; /* In 32-bit words, inclusive */
- u_int16_t sadb_spirage_hdrtype; /* SPI_RANGE */
- u_int32_t sadb_spirange_low;
- u_int32_t sadb_spirange_hi;
-};
-
-/* Message types */
-
-#define SADB_GETSPI 1
-#define SADB_UPDATE 2
-#define SADB_ADD 3
-#define SADB_DELETE 4
-#define SADB_GET 5
-#define SADB_ACQUIRE 6
-#define SADB_REGISTER 7
-#define SADB_EXPIRE 8
-#define SADB_FLUSH 9
-
-#define SADB_DUMP 10 /* Not used normally */
-
-#define SADB_MAX 10
-
-/* Security association flags */
-
-#define SA_USED 0x1 /* SA used/not used */
-#define SA_UNIQUE 0x2 /* SA unique/reusable */
-#define SA_INBOUND 0x4 /* SA for packets destined here */
-#define SA_OUTBOUND 0x8 /* SA for packets sourced here */
-#define SA_FORWARD 0x10 /* SA for packets forwarded through */
-#define SA_PFS 0x20 /* Perfect Forward Secrecy ? */
-#define SA_REPLAY 0x40 /* Replay protection ? */
-
-/* Security association state */
-
-#define SA_STATE_LARVAL 0
-#define SA_STATE_MATURE 1
-#define SA_STATE_DYING 2
-#define SA_STATE_DEAD 3
-
-#define SA_STATE_MAX 3
-
-/* Security association type */
-
-#define SADB_SATYPE_NONE 0
-#define SADB_SATYPE_AH 1 /* RFC-1826 */
-#define SADB_SATYPE_ESP 2 /* RFC-1827 */
-#define SADB_SATYPE_RSVP 3 /* RVSP Authentication */
-#define SADB_SATYPE_OSPFV2 4 /* OSPFv2 Authentication */
-#define SADB_SATYPE_RIPV2 5 /* RIPv2 Authentication */
-#define SADB_SATYPE_MIPV4 6 /* Mobile IPv4 Authentication */
-
-#define SADB_SATYPE_MAX 6
-
-/* Algorithm types */
-
-/* Authentication algorithms */
-
-#define SADB_AALG_NONE 0
-#define SADB_AALG_MD5_HMAC 1
-#define SADB_AALG_SHA1_HMAC 2
-
-#define SADB_AALG_MAX 2
-
-/* Encryption algorithms */
-
-#define SADB_EALG_NONE 0
-#define SADB_EALG_DES_CBC 1
-#define SADB_EALG_3DES 2
-#define SADB_EALG_RC5 3
-
-#define SADB_EALG_MAX 3
-
-/* Extension header values */
-
-#define SA_EXT_ASSOCIATION 1
-#define SA_EXT_LIFETIME 2
-#define SA_EXT_ADDRESS 3
-#define SA_EXT_KEY 4
-#define SA_EXT_IDENTITY 5
-#define SA_EXT_SENSITIVITY 6
-#define SA_EXT_PROPOSAL 7
-#define SA_EXT_SUPPORTED 8
-#define SA_EXT_SPI_RANGE 9
-
-#define SA_EXT_MAX 9
-
-/* Address extension values */
-
-#define SADB_ADDR_SRC 0x1 /* Source */
-#define SADB_ADDR_DST 0x2 /* Destination */
-#define SADB_ADDR_INNER_SRC 0x4 /* Inner-packet src */
-#define SADB_ADDR_INNER_DST 0x8 /* Inner-packet dst */
-#define SADB_ADDR_PROXY 0x10 /* Proxy address */
-
-/* Lifetime extension values */
-
-#define SADB_LIFETIME_HARD 0x1 /* Hard lifetime */
-#define SADB_LIFETIME_SOFT 0x2 /* Soft lifetime */
-#define SADB_LIFETIME_CURRENT 0x4 /* Current lifetime left */
-
-/* Key extension values */
-
-#define SADB_KEYBLK_AUTH 0x1 /* Authentication key */
-#define SADB_KEYBLK_ENCRYPT 0x2 /* Encryption key */
-
-/* Identity extension values */
-
-#define SADB_ID_SRC 0x1
-#define SADB_ID_DST 0x2
-
-/* Identity type */
-
-#define SADB_IDT_IPV4_ADDR 1
-#define SADB_IDT_IPV6_ADDR 2
-#define SADB_IDT_IPV4_RANGE 3
-#define SADB_IDT_IPV6_RANGE 4
-#define SADB_IDT_FQDN 5
-#define SADB_IDT_USER_FQDN 6
-#define SADB_IDT_IPV4_CONNID 7
-#define SADB_IDT_IPV6_CONNID 8
-
-#define SADB_IDT_MAX 8
-
-/* Sensitivity extension values */
-
-#define SADB_DPD_NONE 0
-#define SADB_DPD_DOD_GENSER 1
-#define SADB_DPD_DOD_SCI 2
-#define SADB_DPD_DOE 3
-#define SADB_DPD_NATO 4
-
-#define SADB_DPD_MAX 4
-
-#define sotopfkeycb(so) ((structy pfkeycb *)(so)->so->pcb)
-
-#ifdef _KERNEL
-LIST_HEAD(, pfkeycb) pfkeycb; /* head of list */
-#endif
-
+%%% copyright-nrl-98
+This software is Copyright 1998 by Randall Atkinson, Ronald Lee,
+Daniel McDonald, Bao Phan, and Chris Winters. All Rights Reserved. All
+rights under this copyright have been assigned to the US Naval Research
+Laboratory (NRL). The NRL Copyright Notice and License Agreement Version
+1.1 (January 17, 1995) applies to this software.
+You should have received a copy of the license with this software. If you
+didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
+
+*/
+#ifndef _NET_PFKEY_V2_H
+#define _NET_PFKEY_V2_H 1
+
+#define PF_KEY_V2 2
+
+#define SADB_RESERVED 0
+#define SADB_GETSPI 1
+#define SADB_UPDATE 2
+#define SADB_ADD 3
+#define SADB_DELETE 4
+#define SADB_GET 5
+#define SADB_ACQUIRE 6
+#define SADB_REGISTER 7
+#define SADB_EXPIRE 8
+#define SADB_FLUSH 9
+#define SADB_DUMP 10
+#define SADB_X_PROMISC 11
+#define SADB_X_ADDFLOW 12
+#define SADB_X_DELFLOW 13
+#define SADB_X_GRPSPIS 14
+#define SADB_MAX 14
+
+struct sadb_msg {
+ uint8_t sadb_msg_version;
+ uint8_t sadb_msg_type;
+ uint8_t sadb_msg_errno;
+ uint8_t sadb_msg_satype;
+ uint16_t sadb_msg_len;
+ uint16_t sadb_msg_reserved;
+ uint32_t sadb_msg_seq;
+ uint32_t sadb_msg_pid;
+};
+
+struct sadb_ext {
+ uint16_t sadb_ext_len;
+ uint16_t sadb_ext_type;
+};
+
+struct sadb_sa {
+ uint16_t sadb_sa_len;
+ uint16_t sadb_sa_exttype;
+ uint32_t sadb_sa_spi;
+ uint8_t sadb_sa_replay;
+ uint8_t sadb_sa_state;
+ uint8_t sadb_sa_auth;
+ uint8_t sadb_sa_encrypt;
+ uint32_t sadb_sa_flags;
+};
+
+struct sadb_lifetime {
+ uint16_t sadb_lifetime_len;
+ uint16_t sadb_lifetime_exttype;
+ uint32_t sadb_lifetime_allocations;
+ uint64_t sadb_lifetime_bytes;
+ uint64_t sadb_lifetime_addtime;
+ uint64_t sadb_lifetime_usetime;
+};
+
+struct sadb_address {
+ uint16_t sadb_address_len;
+ uint16_t sadb_address_exttype;
+ uint32_t sadb_address_reserved;
+};
+
+struct sadb_key {
+ uint16_t sadb_key_len;
+ uint16_t sadb_key_exttype;
+ uint16_t sadb_key_bits;
+ uint16_t sadb_key_reserved;
+};
+
+struct sadb_ident {
+ uint16_t sadb_ident_len;
+ uint16_t sadb_ident_exttype;
+ uint16_t sadb_ident_type;
+ uint16_t sadb_ident_reserved;
+ uint64_t sadb_ident_id;
+};
+
+struct sadb_sens {
+ uint16_t sadb_sens_len;
+ uint16_t sadb_sens_exttype;
+ uint32_t sadb_sens_dpd;
+ uint8_t sadb_sens_sens_level;
+ uint8_t sadb_sens_sens_len;
+ uint8_t sadb_sens_integ_level;
+ uint8_t sadb_sens_integ_len;
+ uint32_t sadb_sens_reserved;
+};
+
+struct sadb_prop {
+ uint16_t sadb_prop_len;
+ uint16_t sadb_prop_exttype;
+ uint8_t sadb_prop_num;
+ uint8_t sadb_prop_replay;
+ uint16_t sadb_prop_reserved;
+};
+
+struct sadb_comb {
+ uint8_t sadb_comb_auth;
+ uint8_t sadb_comb_encrypt;
+ uint16_t sadb_comb_flags;
+ uint16_t sadb_comb_auth_minbits;
+ uint16_t sadb_comb_auth_maxbits;
+ uint16_t sadb_comb_encrypt_minbits;
+ uint16_t sadb_comb_encrypt_maxbits;
+ uint32_t sadb_comb_reserved;
+ uint32_t sadb_comb_soft_allocations;
+ uint32_t sadb_comb_hard_allocations;
+ uint64_t sadb_comb_soft_bytes;
+ uint64_t sadb_comb_hard_bytes;
+ uint64_t sadb_comb_soft_addtime;
+ uint64_t sadb_comb_hard_addtime;
+ uint64_t sadb_comb_soft_usetime;
+ uint64_t sadb_comb_hard_usetime;
+};
+
+struct sadb_supported {
+ uint16_t sadb_supported_len;
+ uint16_t sadb_supported_exttype;
+ uint8_t sadb_supported_nauth;
+ uint8_t sadb_supported_nencrypt;
+ uint16_t sadb_supported_reserved;
+};
+
+struct sadb_alg {
+ uint8_t sadb_alg_type;
+ uint8_t sadb_alg_ivlen;
+ uint16_t sadb_alg_minbits;
+ uint16_t sadb_alg_maxbits;
+ uint16_t sadb_alg_reserved;
+};
+
+struct sadb_spirange {
+ uint16_t sadb_spirange_len;
+ uint16_t sadb_spirange_exttype;
+ uint32_t sadb_spirange_min;
+ uint32_t sadb_spirange_max;
+ uint32_t sadb_spirange_reserved;
+};
+
+struct sadb_protocol {
+ uint16_t sadb_protocol_len;
+ uint16_t sadb_protocol_exttype;
+ uint8_t sadb_protocol_proto;
+ uint8_t sadb_protocol_reserved1;
+ uint16_t sadb_protocol_reserved2;
+};
+
+#define SADB_GETSPROTO(x) ( (x) == SADB_SATYPE_AH ? IPPROTO_AH :\
+ (x) == SADB_SATYPE_X_AH_OLD ? IPPROTO_AH :\
+ (x) == SADB_SATYPE_ESP ? IPPROTO_ESP :\
+ (x) == SADB_SATYPE_X_ESP_OLD ? IPPROTO_ESP :\
+ IPPROTO_IPIP )
+
+#define SADB_EXT_RESERVED 0
+#define SADB_EXT_SA 1
+#define SADB_EXT_LIFETIME_CURRENT 2
+#define SADB_EXT_LIFETIME_HARD 3
+#define SADB_EXT_LIFETIME_SOFT 4
+#define SADB_EXT_ADDRESS_SRC 5
+#define SADB_EXT_ADDRESS_DST 6
+#define SADB_EXT_ADDRESS_PROXY 7
+#define SADB_EXT_KEY_AUTH 8
+#define SADB_EXT_KEY_ENCRYPT 9
+#define SADB_EXT_IDENTITY_SRC 10
+#define SADB_EXT_IDENTITY_DST 11
+#define SADB_EXT_SENSITIVITY 12
+#define SADB_EXT_PROPOSAL 13
+#define SADB_EXT_SUPPORTED 14
+#define SADB_EXT_SPIRANGE 15
+#define SADB_EXT_X_SRC_MASK 16
+#define SADB_EXT_X_DST_MASK 17
+#define SADB_EXT_X_PROTOCOL 18
+#define SADB_EXT_X_SA2 19
+#define SADB_EXT_X_SRC_FLOW 20
+#define SADB_EXT_X_DST_FLOW 21
+#define SADB_EXT_X_DST2 22
+#define SADB_EXT_MAX 22
+
+#define SADB_SATYPE_UNSPEC 0
+#define SADB_SATYPE_AH 1
+#define SADB_SATYPE_ESP 2
+#define SADB_SATYPE_RSVP 3
+#define SADB_SATYPE_OSPFV2 4
+#define SADB_SATYPE_RIPV2 5
+#define SADB_SATYPE_MIP 6
+#define SADB_SATYPE_X_AH_OLD 7
+#define SADB_SATYPE_X_ESP_OLD 8
+#define SADB_SATYPE_X_IPIP 9
+#define SADB_SATYPE_MAX 9
+
+#define SADB_SASTATE_LARVAL 0
+#define SADB_SASTATE_MATURE 1
+#define SADB_SASTATE_DYING 2
+#define SADB_SASTATE_DEAD 3
+#define SADB_SASTATE_MAX 3
+
+#define SADB_AALG_NONE 0
+#define SADB_AALG_MD5HMAC 1
+#define SADB_AALG_SHA1HMAC 2
+#define SADB_AALG_MD5HMAC96 3
+#define SADB_AALG_SHA1HMAC96 4
+#define SADB_AALG_X_RIPEMD160HMAC96 5
+#define SADB_AALG_X_MD5 6
+#define SADB_AALG_X_SHA1 7
+#define SADB_AALG_MAX 7
+
+#define SADB_EALG_NONE 0
+#define SADB_EALG_DESCBC 1
+#define SADB_EALG_3DESCBC 2
+#define SADB_EALG_X_BLF 3
+#define SADB_EALG_X_CAST 4
+#define SADB_EALG_X_SKIPJACK 5
+#define SADB_EALG_MAX 5
+
+#define SADB_SAFLAGS_PFS 0x01 /* perfect forward secrecy */
+#define SADB_SAFLAGS_X_HALFIV 0x02 /* Used for ESP-old */
+#define SADB_SAFLAGS_X_TUNNEL 0x04 /* Force tunneling */
+#define SADB_SAFLAGS_X_CHAINDEL 0x08 /* Delete whole SA chain */
+#define SADB_SAFLAGS_X_LOCALFLOW 0x10 /* Delete whole SA chain */
+
+#define SADB_IDENTTYPE_RESERVED 0
+#define SADB_IDENTTYPE_PREFIX 1
+#define SADB_IDENTTYPE_FQDN 2
+#define SADB_IDENTTYPE_MBOX 3
+#define SADB_IDENTTYPE_CONNECTION 4
+#define SADB_IDENTTYPE_MAX 4
+
+#define SADB_KEY_FLAGS_MAX 0
+
+#ifdef KERNEL
+int pfkeyv2_init(void);
+int pfkeyv2_cleanup(void);
+int pfkeyv2_parsemessage(void *p, int len, void **headers);
+#endif /* KERNEL */
+#endif /* _NET_PFKEY_V2_H */
diff --git a/sys/net/pfkeyv2_parsemessage.c b/sys/net/pfkeyv2_parsemessage.c
new file mode 100644
index 00000000000..8424a72b561
--- /dev/null
+++ b/sys/net/pfkeyv2_parsemessage.c
@@ -0,0 +1,550 @@
+/*
+%%% copyright-nrl-97
+This software is Copyright 1997-1998 by Randall Atkinson, Ronald Lee,
+Daniel McDonald, Bao Phan, and Chris Winters. All Rights Reserved. All
+rights under this copyright have been assigned to the US Naval Research
+Laboratory (NRL). The NRL Copyright Notice and License Agreement Version
+1.1 (January 17, 1995) applies to this software.
+You should have received a copy of the license with this software. If you
+didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
+
+%%% copyright-cmetz-97
+This software is Copyright 1997-1998 by Craig Metz, All Rights Reserved.
+The Inner Net License Version 2 applies to this software.
+You should have received a copy of the license with this software. If
+you didn't get a copy, you may request one from <license@inner.net>.
+
+*/
+#include <sys/osdep.h>
+#include <net/pfkeyv2.h>
+
+#define BITMAP_SA (1 << SADB_EXT_SA)
+#define BITMAP_LIFETIME_CURRENT (1 << SADB_EXT_LIFETIME_CURRENT)
+#define BITMAP_LIFETIME_HARD (1 << SADB_EXT_LIFETIME_HARD)
+#define BITMAP_LIFETIME_SOFT (1 << SADB_EXT_LIFETIME_SOFT)
+#define BITMAP_ADDRESS_SRC (1 << SADB_EXT_ADDRESS_SRC)
+#define BITMAP_ADDRESS_DST (1 << SADB_EXT_ADDRESS_DST)
+#define BITMAP_ADDRESS_PROXY (1 << SADB_EXT_ADDRESS_PROXY)
+#define BITMAP_KEY_AUTH (1 << SADB_EXT_KEY_AUTH)
+#define BITMAP_KEY_ENCRYPT (1 << SADB_EXT_KEY_ENCRYPT)
+#define BITMAP_IDENTITY_SRC (1 << SADB_EXT_IDENTITY_SRC)
+#define BITMAP_IDENTITY_DST (1 << SADB_EXT_IDENTITY_DST)
+#define BITMAP_SENSITIVITY (1 << SADB_EXT_SENSITIVITY)
+#define BITMAP_PROPOSAL (1 << SADB_EXT_PROPOSAL)
+#define BITMAP_SUPPORTED (1 << SADB_EXT_SUPPORTED)
+#define BITMAP_SPIRANGE (1 << SADB_EXT_SPIRANGE)
+#define BITMAP_LIFETIME (BITMAP_LIFETIME_CURRENT | BITMAP_LIFETIME_HARD | BITMAP_LIFETIME_SOFT)
+#define BITMAP_ADDRESS (BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_ADDRESS_PROXY)
+#define BITMAP_KEY (BITMAP_KEY_AUTH | BITMAP_KEY_ENCRYPT)
+#define BITMAP_IDENTITY (BITMAP_IDENTITY_SRC | BITMAP_IDENTITY_DST)
+#define BITMAP_MSG 1
+#define BITMAP_X_SRC_MASK (1 << SADB_EXT_X_SRC_MASK)
+#define BITMAP_X_DST_MASK (1 << SADB_EXT_X_DST_MASK)
+#define BITMAP_X_PROTOCOL (1 << SADB_EXT_X_PROTOCOL)
+#define BITMAP_X_SA2 (1 << SADB_EXT_X_SA2)
+#define BITMAP_X_SRC_FLOW (1 << SADB_EXT_X_SRC_FLOW)
+#define BITMAP_X_DST_FLOW (1 << SADB_EXT_X_DST_FLOW)
+#define BITMAP_X_DST2 (1 << SADB_EXT_X_DST2)
+
+uint32_t sadb_exts_allowed_in[SADB_MAX+1] =
+{
+ /* RESERVED */
+ ~0,
+ /* GETSPI */
+ BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_SPIRANGE,
+ /* UPDATE */
+ BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY,
+ /* ADD */
+ BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY,
+ /* DELETE */
+ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
+ /* GET */
+ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
+ /* ACQUIRE */
+ BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_IDENTITY | BITMAP_PROPOSAL,
+ /* REGISTER */
+ 0,
+ /* EXPIRE */
+ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
+ /* FLUSH */
+ 0,
+ /* DUMP */
+ 0,
+ /* X_PROMISC */
+ 0,
+ /* X_ADDFLOW */
+ BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_SA | BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_PROTOCOL | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW,
+ /* X_DELFLOW */
+ BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_PROTOCOL | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW | BITMAP_SA,
+ /* X_GRPSPIS */
+ BITMAP_SA | BITMAP_X_SA2 | BITMAP_X_DST2 | BITMAP_ADDRESS_DST | BITMAP_X_PROTOCOL
+};
+
+uint32_t sadb_exts_required_in[SADB_MAX+1] =
+{
+ /* RESERVED */
+ 0,
+ /* GETSPI */
+ BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_SPIRANGE,
+ /* UPDATE */
+ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
+ /* ADD */
+ BITMAP_SA | BITMAP_ADDRESS_DST,
+ /* DELETE */
+ BITMAP_SA | BITMAP_ADDRESS_DST,
+ /* GET */
+ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
+ /* ACQUIRE */
+ 0,
+ /* REGISTER */
+ 0,
+ /* EXPIRE */
+ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
+ /* FLUSH */
+ 0,
+ /* DUMP */
+ 0,
+ /* X_PROMISC */
+ 0,
+ /* X_ADDFLOW */
+ BITMAP_ADDRESS_DST | BITMAP_SA | BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW,
+ /* X_DELFLOW */
+ BITMAP_SA | BITMAP_X_SRC_MASK | BITMAP_X_DST_MASK | BITMAP_X_SRC_FLOW | BITMAP_X_DST_FLOW,
+ /* X_GRPSPIS */
+ BITMAP_SA | BITMAP_X_SA2 | BITMAP_X_DST2 | BITMAP_ADDRESS_DST | BITMAP_X_PROTOCOL
+};
+
+uint32_t sadb_exts_allowed_out[SADB_MAX+1] =
+{
+ /* RESERVED */
+ ~0,
+ /* GETSPI */
+ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
+ /* UPDATE */
+ BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_IDENTITY,
+ /* ADD */
+ BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_IDENTITY,
+ /* DELETE */
+ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
+ /* GET */
+ BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_KEY | BITMAP_IDENTITY,
+ /* ACQUIRE */
+ BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST | BITMAP_IDENTITY | BITMAP_PROPOSAL,
+ /* REGISTER */
+ BITMAP_SUPPORTED,
+ /* EXPIRE */
+ BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS,
+ /* FLUSH */
+ 0,
+ /* DUMP */
+ BITMAP_SA | BITMAP_LIFETIME | BITMAP_ADDRESS | BITMAP_IDENTITY,
+ /* X_PROMISC */
+ 0,
+ /* X_ADDFLOW */
+ 0,
+ /* X_DELFLOW */
+ 0,
+ /* X_GRPSPIS */
+ 0
+};
+
+uint32_t sadb_exts_required_out[SADB_MAX+1] =
+{
+ /* RESERVED */
+ 0,
+ /* GETSPI */
+ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
+ /* UPDATE */
+ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
+ /* ADD */
+ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
+ /* DELETE */
+ BITMAP_SA | BITMAP_ADDRESS_DST,
+ /* GET */
+ BITMAP_SA | BITMAP_LIFETIME_CURRENT | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
+ /* ACQUIRE */
+ 0,
+ /* REGISTER */
+ BITMAP_SUPPORTED,
+ /* EXPIRE */
+ BITMAP_SA | BITMAP_ADDRESS_SRC | BITMAP_ADDRESS_DST,
+ /* FLUSH */
+ 0,
+ /* DUMP */
+ 0,
+ /* X_PROMISC */
+ 0,
+ /* X_ADDFLOW */
+ 0,
+ /* X_DELFLOW */
+ 0,
+ /* X_GRPSPIS */
+ 0
+};
+
+int pfkeyv2_parsemessage(void *, int, void **);
+
+#define RETURN_EINVAL(line) goto einval;
+
+int
+pfkeyv2_parsemessage(void *p, int len, void **headers)
+{
+ struct sadb_ext *sadb_ext;
+ int i, left = len;
+ uint32_t allow, seen = 1;
+ struct sadb_msg *sadb_msg = (struct sadb_msg *) p;
+
+ bzero(headers, (SADB_EXT_MAX + 1) * sizeof(void *));
+
+ if (left < sizeof(struct sadb_msg))
+ return EINVAL;
+
+ headers[0] = p;
+
+ if (sadb_msg->sadb_msg_len * sizeof(uint64_t) != left)
+ return EINVAL;
+
+ p += sizeof(struct sadb_msg);
+ left -= sizeof(struct sadb_msg);
+
+ if (sadb_msg->sadb_msg_reserved)
+ return EINVAL;
+
+ if (sadb_msg->sadb_msg_type > SADB_MAX)
+ return EINVAL;
+
+ if (!sadb_msg->sadb_msg_type)
+ return EINVAL;
+
+ if (sadb_msg->sadb_msg_pid != OSDEP_CURRENTPID)
+ return EINVAL;
+
+ if (sadb_msg->sadb_msg_errno) {
+ if (left)
+ return EINVAL;
+
+ return 0;
+ }
+
+ if (sadb_msg->sadb_msg_type == SADB_X_PROMISC)
+ return 0;
+
+ allow = sadb_exts_allowed_in[sadb_msg->sadb_msg_type];
+
+ while (left > 0) {
+ sadb_ext = (struct sadb_ext *)p;
+ if (left < sizeof(struct sadb_ext))
+ return EINVAL;
+
+ i = sadb_ext->sadb_ext_len * sizeof(uint64_t);
+ if (left < i)
+ return EINVAL;
+
+ if (sadb_ext->sadb_ext_type > SADB_EXT_MAX)
+ return EINVAL;
+
+ if (!sadb_ext->sadb_ext_type)
+ return EINVAL;
+
+ if (!(allow & (1 << sadb_ext->sadb_ext_type)))
+ return EINVAL;
+
+ if (headers[sadb_ext->sadb_ext_type])
+ return EINVAL;
+
+ seen |= (1 << sadb_ext->sadb_ext_type);
+
+ switch (sadb_ext->sadb_ext_type) {
+ case SADB_EXT_X_SA2:
+ case SADB_EXT_SA:
+ {
+ struct sadb_sa *sadb_sa = (struct sadb_sa *)p;
+
+ if (i != sizeof(struct sadb_sa))
+ return EINVAL;
+
+ if (sadb_sa->sadb_sa_state > SADB_SASTATE_MAX)
+ return EINVAL;
+
+ if (sadb_sa->sadb_sa_state == SADB_SASTATE_DEAD)
+ return EINVAL;
+
+ if (sadb_sa->sadb_sa_encrypt > SADB_EALG_MAX)
+ return EINVAL;
+
+ if (sadb_sa->sadb_sa_auth > SADB_AALG_MAX)
+ return EINVAL;
+ }
+ break;
+ case SADB_EXT_X_PROTOCOL:
+ if (i != sizeof(struct sadb_protocol))
+ return EINVAL;
+ break;
+ case SADB_EXT_LIFETIME_CURRENT:
+ case SADB_EXT_LIFETIME_HARD:
+ case SADB_EXT_LIFETIME_SOFT:
+ {
+ if (i != sizeof(struct sadb_lifetime))
+ return EINVAL;
+ }
+ break;
+ case SADB_EXT_ADDRESS_SRC:
+ case SADB_EXT_ADDRESS_DST:
+ case SADB_EXT_X_DST2:
+ case SADB_EXT_X_SRC_MASK:
+ case SADB_EXT_X_DST_MASK:
+ case SADB_EXT_X_SRC_FLOW:
+ case SADB_EXT_X_DST_FLOW:
+ case SADB_EXT_ADDRESS_PROXY:
+ {
+ struct sadb_address *sadb_address = (struct sadb_address *)p;
+ struct sockaddr *sa = (struct sockaddr *)(p + sizeof(struct sadb_address));
+
+ if (i < sizeof(struct sadb_address) + sizeof(struct sockaddr))
+ return EINVAL;
+
+ if (sadb_address->sadb_address_reserved)
+ return EINVAL;
+
+#if SALEN
+ if (sa->sa_len && (i != sizeof(struct sadb_address) + sa->sa_len))
+ return EINVAL;
+#endif /* SALEN */
+
+ switch(sa->sa_family) {
+ case AF_INET:
+ if (sizeof(struct sadb_address) + sizeof(struct sockaddr_in)
+ != i)
+ return EINVAL;
+#if SALEN
+ if (sa->sa_len != sizeof(struct sockaddr_in))
+ return EINVAL;
+#endif /* SALEN */
+
+ /* Only check the right pieces */
+ switch (sadb_ext->sadb_ext_type)
+ {
+ case SADB_EXT_X_SRC_MASK:
+ case SADB_EXT_X_DST_MASK:
+ case SADB_EXT_X_SRC_FLOW:
+ case SADB_EXT_X_DST_FLOW:
+ break;
+
+ default:
+ if (((struct sockaddr_in *)sa)->sin_port)
+ return EINVAL;
+ break;
+ }
+
+ {
+ char zero[sizeof(((struct sockaddr_in *)sa)->sin_zero)];
+ bzero(zero, sizeof(zero));
+
+ if (bcmp(&((struct sockaddr_in *)sa)->sin_zero, zero,
+ sizeof(zero)))
+ return EINVAL;
+ }
+ break;
+#if INET6
+ case AF_INET6:
+ if (i != sizeof(struct sadb_address) +
+ sizeof(struct sockaddr_in6))
+ return EINVAL;
+
+ if (sa->sa_len != sizeof(struct sockaddr_in6))
+ return EINVAL;
+
+ if (((struct sockaddr_in6 *)sa)->sin6_port)
+ return EINVAL;
+
+ if (((struct sockaddr_in6 *)sa)->sin6_flowinfo)
+ return EINVAL;
+
+ break;
+#endif /* INET6 */
+ default:
+ return EINVAL;
+ }
+ }
+ break;
+ case SADB_EXT_KEY_AUTH:
+ case SADB_EXT_KEY_ENCRYPT:
+ {
+ struct sadb_key *sadb_key = (struct sadb_key *)p;
+
+ if (i < sizeof(struct sadb_key))
+ return EINVAL;
+
+ if (!sadb_key->sadb_key_bits)
+ return EINVAL;
+
+ if (((sadb_key->sadb_key_bits + 63) / 64) * sizeof(uint64_t) !=
+ i - sizeof(struct sadb_key))
+ return EINVAL;
+
+ if (sadb_key->sadb_key_reserved)
+ return EINVAL;
+ }
+ break;
+ case SADB_EXT_IDENTITY_SRC:
+ case SADB_EXT_IDENTITY_DST:
+ {
+ struct sadb_ident *sadb_ident = (struct sadb_ident *)p;
+
+ if (i < sizeof(struct sadb_ident))
+ return EINVAL;
+
+ if (sadb_ident->sadb_ident_type > SADB_IDENTTYPE_MAX)
+ return EINVAL;
+
+ if (sadb_ident->sadb_ident_reserved)
+ return EINVAL;
+
+ if (i > sizeof(struct sadb_ident)) {
+ char *c = (char *)(p + sizeof(struct sadb_ident));
+ int j;
+
+ if (*(char *)(p + i - 1))
+ return EINVAL;
+
+ j = ((strlen(c) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t)-1)) +
+ sizeof(struct sadb_ident);
+
+ if (i != j)
+ return EINVAL;
+ }
+ }
+ break;
+ case SADB_EXT_SENSITIVITY:
+ {
+ struct sadb_sens *sadb_sens = (struct sadb_sens *)p;
+
+ if (i < sizeof(struct sadb_sens))
+ return EINVAL;
+
+ if (i != (sadb_sens->sadb_sens_sens_len +
+ sadb_sens->sadb_sens_integ_len) * sizeof(uint64_t) +
+ sizeof(struct sadb_sens))
+ return EINVAL;
+ }
+ break;
+ case SADB_EXT_PROPOSAL:
+ {
+ struct sadb_prop *sadb_prop = (struct sadb_prop *)p;
+
+ if (i < sizeof(struct sadb_prop))
+ return EINVAL;
+
+ if (sadb_prop->sadb_prop_reserved)
+ return EINVAL;
+
+ if ((i - sizeof(struct sadb_prop)) % sizeof(struct sadb_comb))
+ return EINVAL;
+
+ {
+ struct sadb_comb *sadb_comb = (struct sadb_comb *)(p + sizeof(struct sadb_prop));
+ int j;
+
+ for (j = 0;
+ j < (i - sizeof(struct sadb_prop))/sizeof(struct sadb_comb);
+ j++) {
+ if (sadb_comb->sadb_comb_auth > SADB_AALG_MAX)
+ return EINVAL;
+
+ if (sadb_comb->sadb_comb_encrypt > SADB_EALG_MAX)
+ return EINVAL;
+
+ if (sadb_comb->sadb_comb_reserved)
+ return EINVAL;
+
+ }
+ }
+ }
+ break;
+ case SADB_EXT_SUPPORTED:
+ {
+ struct sadb_supported *sadb_supported = (struct sadb_supported *)p;
+ int j;
+
+ if (i < sizeof(struct sadb_supported))
+ return EINVAL;
+
+ if (sadb_supported->sadb_supported_reserved)
+ return EINVAL;
+
+ if (i != ((sadb_supported->sadb_supported_nauth +
+ sadb_supported->sadb_supported_nencrypt) *
+ sizeof(struct sadb_alg)) + sizeof(struct sadb_supported))
+ return EINVAL;
+
+ {
+ struct sadb_alg *sadb_alg = (struct sadb_alg *)(p + sizeof(struct sadb_supported));
+ for (j = 0; j < sadb_supported->sadb_supported_nauth; j++) {
+ if (sadb_alg->sadb_alg_type > SADB_AALG_MAX)
+ return EINVAL;
+
+ if (sadb_alg->sadb_alg_reserved)
+ return EINVAL;
+
+ sadb_alg++;
+ }
+ for (j = 0; j < sadb_supported->sadb_supported_nencrypt; j++) {
+ if (sadb_alg->sadb_alg_type > SADB_EALG_MAX)
+ return EINVAL;
+
+ if (sadb_alg->sadb_alg_reserved)
+ return EINVAL;
+
+ sadb_alg++;
+ }
+ }
+ }
+ break;
+ case SADB_EXT_SPIRANGE:
+ {
+ struct sadb_spirange *sadb_spirange = (struct sadb_spirange *)p;
+
+ if (i != sizeof(struct sadb_spirange))
+ return EINVAL;
+
+ if (sadb_spirange->sadb_spirange_min >
+ sadb_spirange->sadb_spirange_max)
+ return EINVAL;
+ }
+ break;
+ default:
+ return EINVAL;
+ }
+
+ headers[sadb_ext->sadb_ext_type] = p;
+ p += i;
+ left -= i;
+ }
+
+ if (left)
+ return EINVAL;
+
+ {
+ uint32_t required;
+
+ required = sadb_exts_required_in[sadb_msg->sadb_msg_type];
+
+ if ((seen & required) != required)
+ return EINVAL;
+ }
+
+ switch(((struct sadb_msg *)headers[0])->sadb_msg_type) {
+ case SADB_UPDATE:
+ if (((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_state !=
+ SADB_SASTATE_MATURE)
+ return EINVAL;
+ break;
+ case SADB_ADD:
+ if (((struct sadb_sa *)headers[SADB_EXT_SA])->sadb_sa_state !=
+ SADB_SASTATE_MATURE)
+ return EINVAL;
+ break;
+ }
+
+ return 0;
+}