summaryrefslogtreecommitdiff
path: root/sys/net/pfkey.c
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 /sys/net/pfkey.c
parentac584a07f76e50d29c32c02d92c215beb3185a8a (diff)
PF_KEY_V2, with local extensions for SPD management.
Diffstat (limited to 'sys/net/pfkey.c')
-rw-r--r--sys/net/pfkey.c308
1 files changed, 308 insertions, 0 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 */
+}