summaryrefslogtreecommitdiffstats
path: root/sys/netkey
diff options
context:
space:
mode:
authorwollman <wollman@FreeBSD.org>1996-06-14 17:22:18 +0000
committerwollman <wollman@FreeBSD.org>1996-06-14 17:22:18 +0000
commit845782b7e052a1136c206b3e7ae58942a6a725bd (patch)
tree0dd5de95373d80204fd553830859671bd3bad40f /sys/netkey
parent99066eaf6d9a560cdc3e6b0de8c328e34cb45696 (diff)
downloadFreeBSD-src-845782b7e052a1136c206b3e7ae58942a6a725bd.zip
FreeBSD-src-845782b7e052a1136c206b3e7ae58942a6a725bd.tar.gz
This is the `netkey' kernel key-management service (the PF_KEY analogue
to PF_ROUTE) from NRL's IPv6 distribution, heavily modified by me for better source layout, formatting, and textual conventions. I am told that this code is no longer under active development, but it's a useful hack for those interested in doing work on network security, key management, etc. This code has only been tested twice, so it should be considered highly experimental. Obtained from: ftp.ripe.net
Diffstat (limited to 'sys/netkey')
-rw-r--r--sys/netkey/key.c2270
-rw-r--r--sys/netkey/key.h284
-rw-r--r--sys/netkey/key_debug.c730
-rw-r--r--sys/netkey/key_debug.h151
4 files changed, 3435 insertions, 0 deletions
diff --git a/sys/netkey/key.c b/sys/netkey/key.c
new file mode 100644
index 0000000..2edd29a
--- /dev/null
+++ b/sys/netkey/key.c
@@ -0,0 +1,2270 @@
+/*----------------------------------------------------------------------
+ key.c : Key Management Engine for BSD
+
+ Copyright 1995 by Bao Phan, Randall Atkinson, & Dan McDonald,
+ All Rights Reserved. All Rights have been assigned to the US
+ Naval Research Laboratory (NRL). The NRL Copyright Notice and
+ License governs distribution and use of this software.
+
+ Patents are pending on this technology. NRL grants a license
+ to use this technology at no cost under the terms below with
+ the additional requirement that software, hardware, and
+ documentation relating to use of this technology must include
+ the note that:
+ This product includes technology developed at and
+ licensed from the Information Technology Division,
+ US Naval Research Laboratory.
+
+----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------
+# @(#)COPYRIGHT 1.1a (NRL) 17 August 1995
+
+COPYRIGHT NOTICE
+
+All of the documentation and software included in this software
+distribution from the US Naval Research Laboratory (NRL) are
+copyrighted by their respective developers.
+
+This software and documentation were developed at NRL by various
+people. Those developers have each copyrighted the portions that they
+developed at NRL and have assigned All Rights for those portions to
+NRL. Outside the USA, NRL also has copyright on the software
+developed at NRL. The affected files all contain specific copyright
+notices and those notices must be retained in any derived work.
+
+NRL LICENSE
+
+NRL grants permission for redistribution and use in source and binary
+forms, with or without modification, of the software and documentation
+created at NRL provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+
+ This product includes software developed at the Information
+ Technology Division, US Naval Research Laboratory.
+
+4. Neither the name of the NRL nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
+IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation
+are those of the authors and should not be interpreted as representing
+official policies, either expressed or implied, of the US Naval
+Research Laboratory (NRL).
+
+----------------------------------------------------------------------*/
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/domain.h>
+#include <sys/mbuf.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/time.h>
+
+#include <net/raw_cb.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/if_ether.h>
+
+#ifdef INET6
+#include <netinet6/in6.h>
+#include <netinet6/in6_var.h>
+#endif /* INET6 */
+
+#include <netkey/key.h>
+#include <netkey/key_debug.h>
+
+#define SOCKADDR struct sockaddr
+
+#define KMALLOC(p, t, n) (p = (t) malloc((unsigned long)(n), M_SECA, M_DONTWAIT))
+#define KFREE(p) free((caddr_t)p, M_SECA);
+
+#define CRITICAL_DCL int critical_s;
+#define CRITICAL_START critical_s = splnet()
+#define CRITICAL_END splx(critical_s)
+
+#define TIME_SECONDS time.tv_sec
+#define CURRENT_PID curproc->p_pid
+
+#define DEFARGS(arglist, args) arglist args;
+#define AND ;
+
+#ifdef INET6
+#define MAXHASHKEYLEN (2 * sizeof(int) + 2 * sizeof(struct sockaddr_in6))
+#else
+#define MAXHASHKEYLEN (2 * sizeof(int) + 2 * sizeof(struct sockaddr_in))
+#endif
+
+
+/*
+ * Not clear whether these values should be
+ * tweakable at kernel config time.
+ */
+#define KEYTBLSIZE 61
+#define KEYALLOCTBLSIZE 61
+#define SO2SPITBLSIZE 61
+
+/*
+ * These values should be tweakable...
+ * perhaps by using sysctl
+ */
+
+#define MAXLARVALTIME 240; /* Lifetime of a larval key table entry */
+#define MAXKEYACQUIRE 1; /* Max number of key acquire messages sent */
+ /* per destination address */
+#define MAXACQUIRETIME 15; /* Lifetime of acquire message */
+
+/*
+ * Key engine tables and global variables
+ */
+
+struct key_tblnode keytable[KEYTBLSIZE];
+struct key_allocnode keyalloctbl[KEYALLOCTBLSIZE];
+struct key_so2spinode so2spitbl[SO2SPITBLSIZE];
+
+struct keyso_cb keyso_cb;
+struct key_tblnode nullkeynode;
+struct key_registry *keyregtable;
+struct key_acquirelist *key_acquirelist;
+u_long maxlarvallifetime = MAXLARVALTIME;
+int maxkeyacquire = MAXKEYACQUIRE;
+u_long maxacquiretime = MAXACQUIRETIME;
+
+extern SOCKADDR key_addr;
+
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#define ADVANCE(x, n) \
+ { x += ROUNDUP(n); }
+
+static int my_addr __P((SOCKADDR *));
+static int key_sendup __P((struct socket *, struct key_msghdr *));
+
+/*----------------------------------------------------------------------
+ * key_secassoc2msghdr():
+ * Copy info from a security association into a key message buffer.
+ * Assume message buffer is sufficiently large to hold all security
+ * association information including src, dst, from, key and iv.
+ ----------------------------------------------------------------------*/
+int
+key_secassoc2msghdr(struct key_secassoc *secassoc,
+ struct key_msghdr *km,
+ struct key_msgdata *keyinfo)
+{
+ char *cp;
+ DPRINTF(IDL_FINISHED, ("Entering key_secassoc2msghdr\n"));
+
+ if ((km == 0) || (keyinfo == 0) || (secassoc == 0))
+ return(-1);
+
+ km->type = secassoc->type;
+ km->state = secassoc->state;
+ km->label = secassoc->label;
+ km->spi = secassoc->spi;
+ km->keylen = secassoc->keylen;
+ km->ivlen = secassoc->ivlen;
+ km->algorithm = secassoc->algorithm;
+ km->lifetype = secassoc->lifetype;
+ km->lifetime1 = secassoc->lifetime1;
+ km->lifetime2 = secassoc->lifetime2;
+
+ /*
+ * Stuff src/dst/from/key/iv in buffer after
+ * the message header.
+ */
+ cp = (char *)(km + 1);
+
+ DPRINTF(IDL_FINISHED, ("sa2msghdr: 1\n"));
+ keyinfo->src = (SOCKADDR *)cp;
+ if (secassoc->src->sa_len) {
+ bcopy(secassoc->src, cp, secassoc->src->sa_len);
+ ADVANCE(cp, secassoc->src->sa_len);
+ } else {
+ bzero(cp, MAX_SOCKADDR_SZ);
+ ADVANCE(cp, MAX_SOCKADDR_SZ);
+ }
+
+ DPRINTF(IDL_FINISHED, ("sa2msghdr: 2\n"));
+ keyinfo->dst = (SOCKADDR *)cp;
+ if (secassoc->dst->sa_len) {
+ bcopy(secassoc->dst, cp, secassoc->dst->sa_len);
+ ADVANCE(cp, secassoc->dst->sa_len);
+ } else {
+ bzero(cp, MAX_SOCKADDR_SZ);
+ ADVANCE(cp, MAX_SOCKADDR_SZ);
+ }
+
+ DPRINTF(IDL_FINISHED, ("sa2msghdr: 3\n"));
+ keyinfo->from = (SOCKADDR *)cp;
+ if (secassoc->from->sa_len) {
+ bcopy(secassoc->from, cp, secassoc->from->sa_len);
+ ADVANCE(cp, secassoc->from->sa_len);
+ } else {
+ bzero(cp, MAX_SOCKADDR_SZ);
+ ADVANCE(cp, MAX_SOCKADDR_SZ);
+ }
+
+ DPRINTF(IDL_FINISHED, ("sa2msghdr: 4\n"));
+
+ keyinfo->key = cp;
+ keyinfo->keylen = secassoc->keylen;
+ if (secassoc->keylen) {
+ bcopy((char *)(secassoc->key), cp, secassoc->keylen);
+ ADVANCE(cp, secassoc->keylen);
+ }
+
+ DPRINTF(IDL_FINISHED, ("sa2msghdr: 5\n"));
+ keyinfo->iv = cp;
+ keyinfo->ivlen = secassoc->ivlen;
+ if (secassoc->ivlen) {
+ bcopy((char *)(secassoc->iv), cp, secassoc->ivlen);
+ ADVANCE(cp, secassoc->ivlen);
+ }
+
+ DDO(IDL_FINISHED,printf("msgbuf(len=%d):\n",(char *)cp - (char *)km));
+ DDO(IDL_FINISHED,dump_buf((char *)km, (char *)cp - (char *)km));
+ DPRINTF(IDL_FINISHED, ("sa2msghdr: 6\n"));
+ return(0);
+}
+
+
+/*----------------------------------------------------------------------
+ * key_msghdr2secassoc():
+ * Copy info from a key message buffer into a key_secassoc
+ * structure
+ ----------------------------------------------------------------------*/
+int
+key_msghdr2secassoc(struct key_secassoc *secassoc,
+ struct key_msghdr *km,
+ struct key_msgdata *keyinfo)
+{
+ DPRINTF(IDL_FINISHED, ("Entering key_msghdr2secassoc\n"));
+
+ if ((km == 0) || (keyinfo == 0) || (secassoc == 0))
+ return(-1);
+
+ secassoc->len = sizeof(*secassoc);
+ secassoc->type = km->type;
+ secassoc->state = km->state;
+ secassoc->label = km->label;
+ secassoc->spi = km->spi;
+ secassoc->keylen = km->keylen;
+ secassoc->ivlen = km->ivlen;
+ secassoc->algorithm = km->algorithm;
+ secassoc->lifetype = km->lifetype;
+ secassoc->lifetime1 = km->lifetime1;
+ secassoc->lifetime2 = km->lifetime2;
+
+ if (keyinfo->src) {
+ KMALLOC(secassoc->src, SOCKADDR *, keyinfo->src->sa_len);
+ if (!secassoc->src) {
+ DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for src\n"));
+ return(-1);
+ }
+ bcopy((char *)keyinfo->src, (char *)secassoc->src,
+ keyinfo->src->sa_len);
+ } else
+ secassoc->src = NULL;
+
+ if (keyinfo->dst) {
+ KMALLOC(secassoc->dst, SOCKADDR *, keyinfo->dst->sa_len);
+ if (!secassoc->dst) {
+ DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for dst\n"));
+ return(-1);
+ }
+ bcopy((char *)keyinfo->dst, (char *)secassoc->dst,
+ keyinfo->dst->sa_len);
+ } else
+ secassoc->dst = NULL;
+
+ if (keyinfo->from) {
+ KMALLOC(secassoc->from, SOCKADDR *, keyinfo->from->sa_len);
+ if (!secassoc->from) {
+ DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for from\n"));
+ return(-1);
+ }
+ bcopy((char *)keyinfo->from, (char *)secassoc->from,
+ keyinfo->from->sa_len);
+ } else
+ secassoc->from = NULL;
+
+ /*
+ * Make copies of key and iv
+ */
+ if (secassoc->ivlen) {
+ KMALLOC(secassoc->iv, caddr_t, secassoc->ivlen);
+ if (secassoc->iv == 0) {
+ DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for iv\n"));
+ return(-1);
+ }
+ bcopy((char *)keyinfo->iv, (char *)secassoc->iv, secassoc->ivlen);
+ } else
+ secassoc->iv = NULL;
+
+ if (secassoc->keylen) {
+ KMALLOC(secassoc->key, caddr_t, secassoc->keylen);
+ if (secassoc->key == 0) {
+ DPRINTF(IDL_ERROR,("msghdr2secassoc: can't allocate mem for key\n"));
+ if (secassoc->iv)
+ KFREE(secassoc->iv);
+ return(-1);
+ }
+ bcopy((char *)keyinfo->key, (char *)secassoc->key, secassoc->keylen);
+ } else
+ secassoc->key = NULL;
+ return(0);
+}
+
+
+/*----------------------------------------------------------------------
+ * addrpart_equal():
+ * Determine if the address portion of two sockaddrs are equal.
+ * Currently handles only AF_INET and AF_INET6 address families.
+ ----------------------------------------------------------------------*/
+static int
+addrpart_equal(SOCKADDR *sa1, SOCKADDR *sa2)
+{
+ if ((sa1->sa_family != sa2->sa_family) ||
+ (sa1->sa_len != sa2->sa_len))
+ return 0;
+
+ switch(sa1->sa_family) {
+ case AF_INET:
+ return (((struct sockaddr_in *)sa1)->sin_addr.s_addr ==
+ ((struct sockaddr_in *)sa2)->sin_addr.s_addr);
+#ifdef INET6
+ case AF_INET6:
+ return (IN6_ADDR_EQUAL(((struct sockaddr_in6 *)sa1)->sin6_addr,
+ ((struct sockaddr_in6 *)sa2)->sin6_addr));
+#endif /* INET6 */
+ }
+ return(0);
+}
+
+/*----------------------------------------------------------------------
+ * key_inittables():
+ * Allocate space and initialize key engine tables
+ ----------------------------------------------------------------------*/
+int
+key_inittables(void)
+{
+ int i;
+
+ KMALLOC(keyregtable, struct key_registry *, sizeof(struct key_registry));
+ if (!keyregtable)
+ return -1;
+ bzero((char *)keyregtable, sizeof(struct key_registry));
+ KMALLOC(key_acquirelist, struct key_acquirelist *,
+ sizeof(struct key_acquirelist));
+ if (!key_acquirelist)
+ return -1;
+ bzero((char *)key_acquirelist, sizeof(struct key_acquirelist));
+ for (i = 0; i < KEYTBLSIZE; i++)
+ bzero((char *)&keytable[i], sizeof(struct key_tblnode));
+ for (i = 0; i < KEYALLOCTBLSIZE; i++)
+ bzero((char *)&keyalloctbl[i], sizeof(struct key_allocnode));
+ for (i = 0; i < SO2SPITBLSIZE; i++)
+ bzero((char *)&so2spitbl[i], sizeof(struct key_so2spinode));
+
+ return 0;
+}
+
+static int
+key_freetables(void)
+{
+ KFREE(keyregtable);
+ keyregtable = NULL;
+ KFREE(key_acquirelist);
+ key_acquirelist = NULL;
+ return 0;
+}
+
+/*----------------------------------------------------------------------
+ * key_gethashval():
+ * Determine keytable hash value.
+ ----------------------------------------------------------------------*/
+static int
+key_gethashval(char *buf, int len, int tblsize)
+{
+ int i, j = 0;
+
+ /*
+ * Todo: Use word size xor and check for alignment
+ * and zero pad if necessary. Need to also pick
+ * a good hash function and table size.
+ */
+ if (len <= 0) {
+ DPRINTF(IDL_ERROR,("key_gethashval got bogus len!\n"));
+ return(-1);
+ }
+ for(i = 0; i < len; i++) {
+ j ^= (u_int8_t)(*(buf + i));
+ }
+ return (j % tblsize);
+}
+
+
+/*----------------------------------------------------------------------
+ * key_createkey():
+ * Create hash key for hash function
+ * key is: type+src+dst if keytype = 1
+ * type+src+dst+spi if keytype = 0
+ * Uses only the address portion of the src and dst sockaddrs to
+ * form key. Currently handles only AF_INET and AF_INET6 sockaddrs
+ ----------------------------------------------------------------------*/
+static int
+key_createkey(char *buf, u_int type, SOCKADDR *src, SOCKADDR *dst,
+ u_int32_t spi, u_int keytype)
+{
+ char *cp, *p;
+
+ DPRINTF(IDL_FINISHED,("Entering key_createkey\n"));
+
+ if (!buf || !src || !dst)
+ return(-1);
+
+ cp = buf;
+ bcopy((char *)&type, cp, sizeof(type));
+ cp += sizeof(type);
+
+#ifdef INET6
+ /*
+ * Assume only IPv4 and IPv6 addresses.
+ */
+#define ADDRPART(a) \
+ ((a)->sa_family == AF_INET6) ? \
+ (char *)&(((struct sockaddr_in6 *)(a))->sin6_addr) : \
+ (char *)&(((struct sockaddr_in *)(a))->sin_addr)
+
+#define ADDRSIZE(a) \
+ ((a)->sa_family == AF_INET6) ? sizeof(struct in_addr6) : \
+ sizeof(struct in_addr)
+#else /* INET6 */
+#define ADDRPART(a) (char *)&(((struct sockaddr_in *)(a))->sin_addr)
+#define ADDRSIZE(a) sizeof(struct in_addr)
+#endif /* INET6 */
+
+ DPRINTF(IDL_FINISHED,("src addr:\n"));
+ DDO(IDL_FINISHED,dump_smart_sockaddr(src));
+ DPRINTF(IDL_FINISHED,("dst addr:\n"));
+ DDO(IDL_FINISHED,dump_smart_sockaddr(dst));
+
+ p = ADDRPART(src);
+ bcopy(p, cp, ADDRSIZE(src));
+ cp += ADDRSIZE(src);
+
+ p = ADDRPART(dst);
+ bcopy(p, cp, ADDRSIZE(dst));
+ cp += ADDRSIZE(dst);
+
+#undef ADDRPART
+#undef ADDRSIZE
+
+ if (keytype == 0) {
+ bcopy((char *)&spi, cp, sizeof(spi));
+ cp += sizeof(spi);
+ }
+
+ DPRINTF(IDL_FINISHED,("hash key:\n"));
+ DDO(IDL_FINISHED, dump_buf(buf, cp - buf));
+ return(cp - buf);
+}
+
+
+/*----------------------------------------------------------------------
+ * key_sosearch():
+ * Search the so2spi table for the security association allocated to
+ * the socket. Returns pointer to a struct key_so2spinode which can
+ * be used to locate the security association entry in the keytable.
+ ----------------------------------------------------------------------*/
+static struct key_so2spinode *
+key_sosearch(u_int type, SOCKADDR *src, SOCKADDR *dst, struct socket *so)
+{
+ struct key_so2spinode *np = 0;
+
+ if (!(src && dst)) {
+ DPRINTF(IDL_ERROR,("key_sosearch: got null src or dst pointer!\n"));
+ return(NULL);
+ }
+
+ for (np = so2spitbl[((u_int32_t)so) % SO2SPITBLSIZE].next; np; np = np->next) {
+ if ((so == np->socket) && (type == np->keynode->secassoc->type)
+ && addrpart_equal(src, np->keynode->secassoc->src)
+ && addrpart_equal(dst, np->keynode->secassoc->dst))
+ return(np);
+ }
+ return(NULL);
+}
+
+
+/*----------------------------------------------------------------------
+ * key_sodelete():
+ * Delete entries from the so2spi table.
+ * flag = 1 purge all entries
+ * flag = 0 delete entries with socket pointer matching socket
+ ----------------------------------------------------------------------*/
+static void
+key_sodelete(struct socket *socket, int flag)
+{
+ struct key_so2spinode *prevnp, *np;
+ CRITICAL_DCL
+
+ CRITICAL_START;
+
+ DPRINTF(IDL_EVENT,("Entering keysodelete w/so=0x%x flag=%d\n",
+ (unsigned int)socket,flag));
+
+ if (flag) {
+ int i;
+
+ for (i = 0; i < SO2SPITBLSIZE; i++)
+ for(np = so2spitbl[i].next; np; np = np->next) {
+ KFREE(np);
+ }
+ CRITICAL_END;
+ return;
+ }
+
+ prevnp = &so2spitbl[((u_int32_t)socket) % SO2SPITBLSIZE];
+ for(np = prevnp->next; np; np = np->next) {
+ if (np->socket == socket) {
+ struct socketlist *socklp, *prevsocklp;
+
+ (np->keynode->alloc_count)--;
+
+ /*
+ * If this socket maps to a unique secassoc,
+ * we go ahead and delete the secassoc, since it
+ * can no longer be allocated or used by any other
+ * socket.
+ */
+ if (np->keynode->secassoc->state & K_UNIQUE) {
+ if (key_delete(np->keynode->secassoc) != 0)
+ panic("key_sodelete");
+ np = prevnp;
+ continue;
+ }
+
+ /*
+ * We traverse the socketlist and remove the entry
+ * for this socket
+ */
+ DPRINTF(IDL_FINISHED,("keysodelete: deleting from socklist..."));
+ prevsocklp = np->keynode->solist;
+ for (socklp = prevsocklp->next; socklp; socklp = socklp->next) {
+ if (socklp->socket == socket) {
+ prevsocklp->next = socklp->next;
+ KFREE(socklp);
+ break;
+ }
+ prevsocklp = socklp;
+ }
+ DPRINTF(IDL_FINISHED,("done\n"));
+ prevnp->next = np->next;
+ KFREE(np);
+ np = prevnp;
+ }
+ prevnp = np;
+ }
+ CRITICAL_END;
+}
+
+
+/*----------------------------------------------------------------------
+ * key_deleteacquire():
+ * Delete an entry from the key_acquirelist
+ ----------------------------------------------------------------------*/
+static void
+key_deleteacquire(u_int type, SOCKADDR *target)
+{
+ struct key_acquirelist *ap, *prev;
+
+ prev = key_acquirelist;
+ for(ap = key_acquirelist->next; ap; ap = ap->next) {
+ if (addrpart_equal(target, (SOCKADDR *)&(ap->target)) &&
+ (type == ap->type)) {
+ DPRINTF(IDL_EVENT,("Deleting entry from acquire list!\n"));
+ prev->next = ap->next;
+ KFREE(ap);
+ ap = prev;
+ }
+ prev = ap;
+ }
+}
+
+
+/*----------------------------------------------------------------------
+ * key_search():
+ * Search the key table for an entry with same type, src addr, dest
+ * addr, and spi. Returns a pointer to struct key_tblnode if found
+ * else returns null.
+ ----------------------------------------------------------------------*/
+static struct key_tblnode *
+key_search(u_int type, SOCKADDR *src, SOCKADDR *dst, u_int32_t spi,
+ int indx, struct key_tblnode **prevkeynode)
+{
+ struct key_tblnode *keynode, *prevnode;
+
+ if (indx > KEYTBLSIZE || indx < 0)
+ return (NULL);
+ if (!(&keytable[indx]))
+ return (NULL);
+
+#define sec_type keynode->secassoc->type
+#define sec_spi keynode->secassoc->spi
+#define sec_src keynode->secassoc->src
+#define sec_dst keynode->secassoc->dst
+
+ prevnode = &keytable[indx];
+ for (keynode = keytable[indx].next; keynode; keynode = keynode->next) {
+ if ((type == sec_type) && (spi == sec_spi) &&
+ addrpart_equal(src, sec_src)
+ && addrpart_equal(dst, sec_dst))
+ break;
+ prevnode = keynode;
+ }
+ *prevkeynode = prevnode;
+ return(keynode);
+}
+
+
+/*----------------------------------------------------------------------
+ * key_addnode():
+ * Insert a key_tblnode entry into the key table. Returns a pointer
+ * to the newly created key_tblnode.
+ ----------------------------------------------------------------------*/
+static struct key_tblnode *
+key_addnode(int indx, struct key_secassoc *secassoc)
+{
+ struct key_tblnode *keynode;
+
+ DPRINTF(IDL_FINISHED,("Entering key_addnode w/indx=%d secassoc=0x%x\n",
+ indx, (unsigned int)secassoc));
+
+ if (!(&keytable[indx]))
+ return(NULL);
+ if (!secassoc) {
+ panic("key_addnode: Someone passed in a null secassoc!\n");
+ }
+
+ KMALLOC(keynode, struct key_tblnode *, sizeof(struct key_tblnode));
+ if (keynode == 0)
+ return(NULL);
+ bzero((char *)keynode, sizeof(struct key_tblnode));
+
+ KMALLOC(keynode->solist, struct socketlist *, sizeof(struct socketlist));
+ if (keynode->solist == 0) {
+ KFREE(keynode);
+ return(NULL);
+ }
+ bzero((char *)(keynode->solist), sizeof(struct socketlist));
+
+ keynode->secassoc = secassoc;
+ keynode->solist->next = NULL;
+ keynode->next = keytable[indx].next;
+ keytable[indx].next = keynode;
+ return(keynode);
+}
+
+
+/*----------------------------------------------------------------------
+ * key_add():
+ * Add a new security association to the key table. Caller is
+ * responsible for allocating memory for the key_secassoc as
+ * well as the buffer space for the key, iv. Assumes the security
+ * association passed in is well-formed.
+ ----------------------------------------------------------------------*/
+int
+key_add(struct key_secassoc *secassoc)
+{
+ char buf[MAXHASHKEYLEN];
+ int len, indx;
+ int inbound = 0;
+ int outbound = 0;
+ struct key_tblnode *keynode, *prevkeynode;
+ struct key_allocnode *np = NULL;
+ CRITICAL_DCL
+
+ DPRINTF(IDL_FINISHED, ("Entering key_add w/secassoc=0x%x\n",
+ (unsigned int)secassoc));
+
+ if (!secassoc) {
+ panic("key_add: who the hell is passing me a null pointer");
+ }
+
+ /*
+ * Should we allow a null key to be inserted into the table ?
+ * or can we use null key to indicate some policy action...
+ */
+
+#if 0
+ /*
+ * For esp using des-cbc or tripple-des we call
+ * des_set_odd_parity.
+ */
+ if (secassoc->key && (secassoc->type == KEY_TYPE_ESP) &&
+ ((secassoc->algorithm == IPSEC_ALGTYPE_ESP_DES_CBC) ||
+ (secassoc->algorithm == IPSEC_ALGTYPE_ESP_3DES)))
+ des_set_odd_parity(secassoc->key);
+#endif /* 0 */
+
+ /*
+ * Check if secassoc with same spi exists before adding
+ */
+ bzero((char *)&buf, sizeof(buf));
+ len = key_createkey((char *)&buf, secassoc->type, secassoc->src,
+ secassoc->dst, secassoc->spi, 0);
+ indx = key_gethashval((char *)&buf, len, KEYTBLSIZE);
+ DPRINTF(IDL_FINISHED,("keyadd: keytbl hash position=%d\n", indx));
+ keynode = key_search(secassoc->type, secassoc->src, secassoc->dst,
+ secassoc->spi, indx, &prevkeynode);
+ if (keynode) {
+ DPRINTF(IDL_EVENT,("keyadd: secassoc already exists!\n"));
+ return(-2);
+ }
+
+ inbound = my_addr(secassoc->dst);
+ outbound = my_addr(secassoc->src);
+ DPRINTF(IDL_FINISHED,("inbound=%d outbound=%d\n", inbound, outbound));
+
+ /*
+ * We allocate mem for an allocation entry if needed.
+ * This is done here instead of in the allocaton code
+ * segment so that we can easily recover/cleanup from a
+ * memory allocation error.
+ */
+ if (outbound || (!inbound && !outbound)) {
+ KMALLOC(np, struct key_allocnode *, sizeof(struct key_allocnode));
+ if (np == 0) {
+ DPRINTF(IDL_ERROR,("keyadd: can't allocate allocnode!\n"));
+ return(-1);
+ }
+ }
+
+ CRITICAL_START;
+
+ if ((keynode = key_addnode(indx, secassoc)) == NULL) {
+ DPRINTF(IDL_ERROR,("keyadd: key_addnode failed!\n"));
+ if (np)
+ KFREE(np);
+ CRITICAL_END;
+ return(-1);
+ }
+ DPRINTF(IDL_GROSS_EVENT,("Added new keynode:\n"));
+ DDO(IDL_FINISHED, dump_keytblnode(keynode));
+ DDO(IDL_FINISHED, dump_secassoc(keynode->secassoc));
+
+ /*
+ * We add an entry to the allocation table for
+ * this secassoc if the interfaces are up,
+ * the secassoc is outbound. In the case
+ * where the interfaces are not up, we go ahead
+ * , do it anyways. This wastes an allocation
+ * entry if the secassoc later turned out to be
+ * inbound when the interfaces are ifconfig up.
+ */
+ if (outbound || (!inbound && !outbound)) {
+ len = key_createkey((char *)&buf, secassoc->type, secassoc->src,
+ secassoc->dst, 0, 1);
+ indx = key_gethashval((char *)&buf, len, KEYALLOCTBLSIZE);
+ DPRINTF(IDL_FINISHED,("keyadd: keyalloc hash position=%d\n", indx));
+ np->keynode = keynode;
+ np->next = keyalloctbl[indx].next;
+ keyalloctbl[indx].next = np;
+ }
+ if (inbound)
+ secassoc->state |= K_INBOUND;
+ if (outbound)
+ secassoc->state |= K_OUTBOUND;
+
+ key_deleteacquire(secassoc->type, secassoc->dst);
+
+ CRITICAL_END;
+ return 0;
+}
+
+
+/*----------------------------------------------------------------------
+ * key_get():
+ * Get a security association from the key table.
+ ----------------------------------------------------------------------*/
+int
+key_get(u_int type, SOCKADDR *src, SOCKADDR *dst, u_int32_t spi,
+ struct key_secassoc **secassoc)
+{
+ char buf[MAXHASHKEYLEN];
+ struct key_tblnode *keynode, *prevkeynode;
+ int len, indx;
+
+ bzero(&buf, sizeof(buf));
+ *secassoc = NULL;
+ len = key_createkey((char *)&buf, type, src, dst, spi, 0);
+ indx = key_gethashval((char *)&buf, len, KEYTBLSIZE);
+ DPRINTF(IDL_FINISHED,("keyget: indx=%d\n",indx));
+ keynode = key_search(type, src, dst, spi, indx, &prevkeynode);
+ if (keynode) {
+ DPRINTF(IDL_GROSS_EVENT,("keyget: found it! keynode=0x%x",
+ (unsigned int)keynode));
+ *secassoc = keynode->secassoc;
+ return(0);
+ } else
+ return(-1); /* Not found */
+}
+
+
+/*----------------------------------------------------------------------
+ * key_dump():
+ * Dump all valid entries in the keytable to a pf_key socket. Each
+ * security associaiton is sent one at a time in a pf_key message. A
+ * message with seqno = 0 signifies the end of the dump transaction.
+ ----------------------------------------------------------------------*/
+int
+key_dump(struct socket *so)
+{
+ int len, i;
+ int seq = 1;
+ struct key_msgdata keyinfo;
+ struct key_msghdr *km;
+ struct key_tblnode *keynode;
+
+ /*
+ * Routine to dump the key table to a routing socket
+ * Use for debugging only!
+ */
+
+ KMALLOC(km, struct key_msghdr *, sizeof(struct key_msghdr) +
+ 3 * MAX_SOCKADDR_SZ + MAX_KEY_SZ + MAX_IV_SZ);
+ if (!km)
+ return(ENOBUFS);
+
+ DPRINTF(IDL_FINISHED,("Entering key_dump()"));
+ /*
+ * We need to speed this up later. Fortunately, key_dump
+ * messages are not sent often.
+ */
+ for (i = 0; i < KEYTBLSIZE; i++) {
+ for (keynode = keytable[i].next; keynode; keynode = keynode->next) {
+ /*
+ * We exclude dead/larval/zombie security associations for now
+ * but it may be useful to also send these up for debugging purposes
+ */
+ if (keynode->secassoc->state & (K_DEAD | K_LARVAL | K_ZOMBIE))
+ continue;
+
+ len = (sizeof(struct key_msghdr) +
+ ROUNDUP(keynode->secassoc->src->sa_len) +
+ ROUNDUP(keynode->secassoc->dst->sa_len) +
+ ROUNDUP(keynode->secassoc->from->sa_len) +
+ ROUNDUP(keynode->secassoc->keylen) +
+ ROUNDUP(keynode->secassoc->ivlen));
+
+ if (key_secassoc2msghdr(keynode->secassoc, km, &keyinfo) != 0)
+ panic("key_dump");
+
+ km->key_msglen = len;
+ km->key_msgvers = KEY_VERSION;
+ km->key_msgtype = KEY_DUMP;
+ km->key_pid = CURRENT_PID;
+ km->key_seq = seq++;
+ km->key_errno = 0;
+
+ key_sendup(so, km);
+ }
+ }
+ bzero((char *)km, sizeof(struct key_msghdr));
+ km->key_msglen = sizeof(struct key_msghdr);
+ km->key_msgvers = KEY_VERSION;
+ km->key_msgtype = KEY_DUMP;
+ km->key_pid = CURRENT_PID;
+ km->key_seq = 0;
+ km->key_errno = 0;
+
+ key_sendup(so, km);
+ KFREE(km);
+ DPRINTF(IDL_FINISHED,("Leaving key_dump()\n"));
+ return(0);
+}
+
+/*----------------------------------------------------------------------
+ * key_delete():
+ * Delete a security association from the key table.
+ ----------------------------------------------------------------------*/
+int
+key_delete(struct key_secassoc *secassoc)
+{
+ char buf[MAXHASHKEYLEN];
+ int len, indx;
+ struct key_tblnode *keynode = 0;
+ struct key_tblnode *prevkeynode = 0;
+ struct socketlist *socklp, *deadsocklp;
+ struct key_so2spinode *np, *prevnp;
+ struct key_allocnode *ap, *prevap;
+ CRITICAL_DCL
+
+ DPRINTF(IDL_FINISHED,("Entering key_delete w/secassoc=0x%x\n",
+ (unsigned int)secassoc));
+
+ bzero((char *)&buf, sizeof(buf));
+ len = key_createkey((char *)&buf, secassoc->type, secassoc->src,
+ secassoc->dst, secassoc->spi, 0);
+ indx = key_gethashval((char *)&buf, len, KEYTBLSIZE);
+ DPRINTF(IDL_FINISHED,("keydelete: keytbl hash position=%d\n", indx));
+ keynode = key_search(secassoc->type, secassoc->src, secassoc->dst,
+ secassoc->spi, indx, &prevkeynode);
+
+ if (keynode) {
+ CRITICAL_START;
+ DPRINTF(IDL_GROSS_EVENT,("keydelete: found keynode to delete\n"));
+ keynode->secassoc->state |= K_DEAD;
+
+ if (keynode->ref_count > 0) {
+ DPRINTF(IDL_EVENT,("keydelete: secassoc still held, marking for deletion only!\n"));
+ CRITICAL_END;
+ return(0);
+ }
+
+ prevkeynode->next = keynode->next;
+
+ /*
+ * Walk the socketlist, delete the
+ * entries mapping sockets to this secassoc
+ * from the so2spi table.
+ */
+ DPRINTF(IDL_FINISHED,("keydelete: deleting socklist..."));
+ for(socklp = keynode->solist->next; socklp; ) {
+ prevnp = &so2spitbl[((u_int32_t)(socklp->socket)) % SO2SPITBLSIZE];
+ for(np = prevnp->next; np; np = np->next) {
+ if ((np->socket == socklp->socket) && (np->keynode == keynode)) {
+ prevnp->next = np->next;
+ KFREE(np);
+ break;
+ }
+ prevnp = np;
+ }
+ deadsocklp = socklp;
+ socklp = socklp->next;
+ KFREE(deadsocklp);
+ }
+ DPRINTF(IDL_FINISHED,("done\n"));
+ /*
+ * If an allocation entry exist for this
+ * secassoc, delete it.
+ */
+ bzero((char *)&buf, sizeof(buf));
+ len = key_createkey((char *)&buf, secassoc->type, secassoc->src,
+ secassoc->dst, 0, 1);
+ indx = key_gethashval((char *)&buf, len, KEYALLOCTBLSIZE);
+ DPRINTF(IDL_FINISHED,("keydelete: alloctbl hash position=%d\n", indx));
+ prevap = &keyalloctbl[indx];
+ for (ap = prevap->next; ap; ap = ap->next) {
+ if (ap->keynode == keynode) {
+ prevap->next = ap->next;
+ KFREE(ap);
+ break;
+ }
+ prevap = ap;
+ }
+
+ if (keynode->secassoc->iv)
+ KFREE(keynode->secassoc->iv);
+ if (keynode->secassoc->key)
+ KFREE(keynode->secassoc->key);
+ KFREE(keynode->secassoc);
+ if (keynode->solist)
+ KFREE(keynode->solist);
+ KFREE(keynode);
+ CRITICAL_END;
+ return(0);
+ }
+ return(-1);
+}
+
+
+/*----------------------------------------------------------------------
+ * key_flush():
+ * Delete all entries from the key table.
+ ----------------------------------------------------------------------*/
+void
+key_flush(void)
+{
+ struct key_tblnode *keynode;
+ int i;
+
+ /*
+ * This is slow, but simple.
+ */
+ DPRINTF(IDL_FINISHED,("Flushing key table..."));
+ for (i = 0; i < KEYTBLSIZE; i++) {
+ while ((keynode = keytable[i].next))
+ if (key_delete(keynode->secassoc) != 0)
+ panic("key_flush");
+ }
+ DPRINTF(IDL_FINISHED,("done\n"));
+}
+
+
+/*----------------------------------------------------------------------
+ * key_getspi():
+ * Get a unique spi value for a key management daemon/program. The
+ * spi value, once assigned, cannot be assigned again (as long as the
+ * entry with that same spi value remains in the table).
+ ----------------------------------------------------------------------*/
+int
+key_getspi(u_int type, SOCKADDR *src, SOCKADDR *dst, u_int32_t lowval,
+ u_int32_t highval, u_int32_t *spi)
+{
+ struct key_secassoc *secassoc;
+ struct key_tblnode *keynode, *prevkeynode;
+ int count, done, len, indx;
+ int maxcount = 1000;
+ u_int32_t val;
+ char buf[MAXHASHKEYLEN];
+ CRITICAL_DCL
+
+ DPRINTF(IDL_EVENT,("Entering getspi w/type=%d,low=%u,high=%u\n",
+ type, lowval, highval));
+ if (!(src && dst))
+ return(EINVAL);
+
+ if ((lowval == 0) || (highval == 0))
+ return(EINVAL);
+
+ if (lowval > highval) {
+ u_int32_t temp;
+ temp = lowval;
+ lowval = highval;
+ highval = lowval;
+ }
+
+ done = count = 0;
+ do {
+ count++;
+ /*
+ * This may not be "random enough".
+ */
+ val = lowval + (random() % (highval - lowval + 1));
+
+ if (lowval == highval)
+ count = maxcount;
+ DPRINTF(IDL_FINISHED,("%u ",val));
+ if (val) {
+ DPRINTF(IDL_FINISHED,("\n"));
+ bzero(&buf, sizeof(buf));
+ len = key_createkey((char *)&buf, type, src, dst, val, 0);
+ indx = key_gethashval((char *)&buf, len, KEYTBLSIZE);
+ if (!key_search(type, src, dst, val, indx, &prevkeynode)) {
+ CRITICAL_START;
+ KMALLOC(secassoc, struct key_secassoc *, sizeof(struct key_secassoc));
+ if (secassoc == 0) {
+ DPRINTF(IDL_ERROR,("key_getspi: can't allocate memory\n"));
+ CRITICAL_END;
+ return(ENOBUFS);
+ }
+ bzero((char *)secassoc, sizeof(*secassoc));
+
+ DPRINTF(IDL_FINISHED,("getspi: indx=%d\n",indx));
+ secassoc->len = sizeof(struct key_secassoc);
+ secassoc->type = type;
+ secassoc->spi = val;
+ secassoc->state |= K_LARVAL;
+ if (my_addr(secassoc->dst))
+ secassoc->state |= K_INBOUND;
+ if (my_addr(secassoc->src))
+ secassoc->state |= K_OUTBOUND;
+
+ bcopy((char *)src, (char *)secassoc->src, src->sa_len);
+ bcopy((char *)dst, (char *)secassoc->dst, dst->sa_len);
+
+ /* We fill this in with a plausable value now to insure
+ that other routines don't break. These will get
+ overwritten later with the correct values. */
+#ifdef INET6
+ secassoc->from->sa_family = AF_INET6;
+ secassoc->from->sa_len = sizeof(struct sockaddr_in6);
+#else /* INET6 */
+ secassoc->from->sa_family = AF_INET;
+ secassoc->from->sa_len = sizeof(struct sockaddr_in);
+#endif /* INET6 */
+
+ /*
+ * We need to add code to age these larval key table
+ * entries so they don't linger forever waiting for
+ * a KEY_UPDATE message that may not come for various
+ * reasons. This is another task that key_reaper can
+ * do once we have it coded.
+ */
+ secassoc->lifetime1 += TIME_SECONDS + maxlarvallifetime;
+
+ if (!(keynode = key_addnode(indx, secassoc))) {
+ DPRINTF(IDL_ERROR,("key_getspi: can't add node\n"));
+ CRITICAL_END;
+ return(ENOBUFS);
+ }
+ DPRINTF(IDL_FINISHED,("key_getspi: added node 0x%x\n",
+ (unsigned int)keynode));
+ done++;
+ CRITICAL_END;
+ }
+ }
+ } while ((count < maxcount) && !done);
+ DPRINTF(IDL_EVENT,("getspi returns w/spi=%u,count=%d\n",val,count));
+ if (done) {
+ *spi = val;
+ return(0);
+ } else {
+ *spi = 0;
+ return(EADDRNOTAVAIL);
+ }
+}
+
+
+/*----------------------------------------------------------------------
+ * key_update():
+ * Update a keytable entry that has an spi value assigned but is
+ * incomplete (e.g. no key/iv).
+ ----------------------------------------------------------------------*/
+int
+key_update(struct key_secassoc *secassoc)
+{
+ struct key_tblnode *keynode, *prevkeynode;
+ struct key_allocnode *np = 0;
+ u_int8_t newstate;
+ int len, indx, inbound, outbound;
+ char buf[MAXHASHKEYLEN];
+ CRITICAL_DCL
+
+ bzero(&buf, sizeof(buf));
+ len = key_createkey((char *)&buf, secassoc->type, secassoc->src,
+ secassoc->dst, secassoc->spi, 0);
+ indx = key_gethashval((char *)&buf, len, KEYTBLSIZE);
+ if(!(keynode = key_search(secassoc->type, secassoc->src, secassoc->dst,
+ secassoc->spi, indx, &prevkeynode))) {
+ return(ESRCH);
+ }
+ if (keynode->secassoc->state & K_DEAD)
+ return(ESRCH);
+
+ /* Should we also restrict updating of only LARVAL entries ? */
+
+ CRITICAL_START;
+
+ inbound = my_addr(secassoc->dst);
+ outbound = my_addr(secassoc->src);
+
+ newstate = keynode->secassoc->state;
+ newstate &= ~K_LARVAL;
+
+ if (inbound)
+ newstate |= K_INBOUND;
+ if (outbound)
+ newstate |= K_OUTBOUND;
+
+ if (outbound || (!inbound && !outbound)) {
+ KMALLOC(np, struct key_allocnode *, sizeof(struct key_allocnode));
+ if (np == 0) {
+ DPRINTF(IDL_ERROR,("keyupdate: can't allocate allocnode!\n"));
+ CRITICAL_END;
+ return(ENOBUFS);
+ }
+ }
+
+ /*
+ * Free the old key, iv if they're there.
+ */
+ if (keynode->secassoc->key)
+ KFREE(keynode->secassoc->key);
+ if (keynode->secassoc->iv)
+ KFREE(keynode->secassoc->iv);
+
+ /*
+ * We now copy the secassoc over. We don't need to copy
+ * the key, iv into new buffers since the calling routine
+ * does that already.
+ */
+
+ *(keynode->secassoc) = *secassoc;
+ keynode->secassoc->state = newstate;
+
+ /*
+ * Should we allow a null key to be inserted into the table ?
+ * or can we use null key to indicate some policy action...
+ */
+
+#if 0
+ if (keynode->secassoc->key &&
+ (keynode->secassoc->type == KEY_TYPE_ESP) &&
+ ((keynode->secassoc->algorithm == IPSEC_ALGTYPE_ESP_DES_CBC) ||
+ (keynode->secassoc->algorithm == IPSEC_ALGTYPE_ESP_3DES)))
+ des_set_odd_parity(keynode->secassoc->key);
+#endif /* 0 */
+
+ /*
+ * We now add an entry to the allocation table for this
+ * updated key table entry.
+ */
+ if (outbound || (!inbound && !outbound)) {
+ len = key_createkey((char *)&buf, secassoc->type, secassoc->src,
+ secassoc->dst, 0, 1);
+ indx = key_gethashval((char *)&buf, len, KEYALLOCTBLSIZE);
+ DPRINTF(IDL_FINISHED,("keyupdate: keyalloc hash position=%d\n", indx));
+ np->keynode = keynode;
+ np->next = keyalloctbl[indx].next;
+ keyalloctbl[indx].next = np;
+ }
+
+ key_deleteacquire(secassoc->type, (SOCKADDR *)&(secassoc->dst));
+
+ CRITICAL_END;
+ return(0);
+}
+
+/*----------------------------------------------------------------------
+ * key_register():
+ * Register a socket as one capable of acquiring security associations
+ * for the kernel.
+ ----------------------------------------------------------------------*/
+int
+key_register(struct socket *socket, u_int type)
+{
+ struct key_registry *p, *new;
+ CRITICAL_DCL
+
+ CRITICAL_START;
+
+ DPRINTF(IDL_EVENT,("Entering key_register w/so=0x%x,type=%d\n",
+ (unsigned int)socket,type));
+
+ if (!(keyregtable && socket))
+ panic("key_register");
+
+ /*
+ * Make sure entry is not already in table
+ */
+ for(p = keyregtable->next; p; p = p->next) {
+ if ((p->type == type) && (p->socket == socket)) {
+ CRITICAL_END;
+ return(EEXIST);
+ }
+ }
+
+ KMALLOC(new, struct key_registry *, sizeof(struct key_registry));
+ if (new == 0) {
+ CRITICAL_END;
+ return(ENOBUFS);
+ }
+ new->type = type;
+ new->socket = socket;
+ new->next = keyregtable->next;
+ keyregtable->next = new;
+ CRITICAL_END;
+ return(0);
+}
+
+/*----------------------------------------------------------------------
+ * key_unregister():
+ * Delete entries from the registry list.
+ * allflag = 1 : delete all entries with matching socket
+ * allflag = 0 : delete only the entry matching socket, type
+ ----------------------------------------------------------------------*/
+void
+key_unregister(struct socket *socket, u_int type, int allflag)
+{
+ struct key_registry *p, *prev;
+ CRITICAL_DCL
+
+ CRITICAL_START;
+
+ DPRINTF(IDL_EVENT,("Entering key_unregister w/so=0x%x,type=%d,flag=%d\n",
+ (unsigned int)socket, type, allflag));
+
+ if (!(keyregtable && socket))
+ panic("key_register");
+ prev = keyregtable;
+ for(p = keyregtable->next; p; p = p->next) {
+ if ((allflag && (p->socket == socket)) ||
+ ((p->type == type) && (p->socket == socket))) {
+ prev->next = p->next;
+ KFREE(p);
+ p = prev;
+ }
+ prev = p;
+ }
+ CRITICAL_END;
+}
+
+
+/*----------------------------------------------------------------------
+ * key_acquire():
+ * Send a key_acquire message to all registered key mgnt daemons
+ * capable of acquire security association of type type.
+ *
+ * Return: 0 if succesfully called key mgnt. daemon(s)
+ * -1 if not successfull.
+ ----------------------------------------------------------------------*/
+int
+key_acquire(u_int type, SOCKADDR *src, SOCKADDR *dst)
+{
+ struct key_registry *p;
+ struct key_acquirelist *ap, *prevap;
+ int success = 0, created = 0;
+ u_int etype;
+ struct key_msghdr *km = NULL;
+ int len;
+
+ DPRINTF(IDL_EVENT,("Entering key_acquire()\n"));
+
+ if (!keyregtable || !src || !dst)
+ return (-1);
+
+ /*
+ * We first check the acquirelist to see if a key_acquire
+ * message has been sent for this destination.
+ */
+ etype = type;
+ prevap = key_acquirelist;
+ for(ap = key_acquirelist->next; ap; ap = ap->next) {
+ if (addrpart_equal(dst, ap->target) &&
+ (etype == ap->type)) {
+ DPRINTF(IDL_EVENT,("acquire message previously sent!\n"));
+ if (ap->expiretime < TIME_SECONDS) {
+ DPRINTF(IDL_EVENT,("acquire message has expired!\n"));
+ ap->count = 0;
+ break;
+ }
+ if (ap->count < maxkeyacquire) {
+ DPRINTF(IDL_EVENT,("max acquire messages not yet exceeded!\n"));
+ break;
+ }
+ return(0);
+ } else if (ap->expiretime < TIME_SECONDS) {
+ /*
+ * Since we're already looking at the list, we may as
+ * well delete expired entries as we scan through the list.
+ * This should really be done by a function like key_reaper()
+ * but until we code key_reaper(), this is a quick, dirty
+ * hack.
+ */
+ DPRINTF(IDL_EVENT,("found an expired entry...deleting it!\n"));
+ prevap->next = ap->next;
+ KFREE(ap);
+ ap = prevap;
+ }
+ prevap = ap;
+ }
+
+ /*
+ * Scan registry, send KEY_ACQUIRE message to
+ * appropriate key management daemons.
+ */
+ for(p = keyregtable->next; p; p = p->next) {
+ if (p->type != type)
+ continue;
+
+ if (!created) {
+ len = sizeof(struct key_msghdr) + ROUNDUP(src->sa_len) +
+ ROUNDUP(dst->sa_len);
+ KMALLOC(km, struct key_msghdr *, len);
+ if (!km) {
+ DPRINTF(IDL_ERROR,("key_acquire: no memory\n"));
+ return(-1);
+ }
+ DPRINTF(IDL_FINISHED,("key_acquire/created: 1\n"));
+ bzero((char *)km, len);
+ km->key_msglen = len;
+ km->key_msgvers = KEY_VERSION;
+ km->key_msgtype = KEY_ACQUIRE;
+ km->type = type;
+ DPRINTF(IDL_FINISHED,("key_acquire/created: 2\n"));
+ /*
+ * This is inefficient, slow.
+ */
+
+ /*
+ * We zero out sin_zero here for AF_INET addresses because
+ * ip_output() currently does not do it for performance reasons.
+ */
+ if (src->sa_family == AF_INET)
+ bzero((char *)(((struct sockaddr_in *)src)->sin_zero),
+ sizeof(((struct sockaddr_in *)src)->sin_zero));
+ if (dst->sa_family == AF_INET)
+ bzero((char *)(((struct sockaddr_in *)dst)->sin_zero),
+ sizeof(((struct sockaddr_in *)dst)->sin_zero));
+
+ bcopy((char *)src, (char *)(km + 1), src->sa_len);
+ bcopy((char *)dst, (char *)((int)(km + 1) + ROUNDUP(src->sa_len)),
+ dst->sa_len);
+ DPRINTF(IDL_FINISHED,("key_acquire/created: 3\n"));
+ created++;
+ }
+ if (key_sendup(p->socket, km))
+ success++;
+ }
+
+ if (km)
+ KFREE(km);
+
+ /*
+ * Update the acquirelist
+ */
+ if (success) {
+ if (!ap) {
+ DPRINTF(IDL_EVENT,("Adding new entry in acquirelist\n"));
+ KMALLOC(ap, struct key_acquirelist *, sizeof(struct key_acquirelist));
+ if (ap == 0)
+ return(success ? 0 : -1);
+ bzero((char *)ap, sizeof(struct key_acquirelist));
+ bcopy((char *)dst, (char *)ap->target, dst->sa_len);
+ ap->type = etype;
+ ap->next = key_acquirelist->next;
+ key_acquirelist->next = ap;
+ }
+ DPRINTF(IDL_GROSS_EVENT,("Updating acquire counter, expiration time\n"));
+ ap->count++;
+ ap->expiretime = TIME_SECONDS + maxacquiretime;
+ }
+ DPRINTF(IDL_EVENT,("key_acquire: done! success=%d\n",success));
+ return(success ? 0 : -1);
+}
+
+/*----------------------------------------------------------------------
+ * key_alloc():
+ * Allocate a security association to a socket. A socket requesting
+ * unique keying (per-socket keying) is assigned a security assocation
+ * exclusively for its use. Sockets not requiring unique keying are
+ * assigned the first security association which may or may not be
+ * used by another socket.
+ ----------------------------------------------------------------------*/
+static int
+key_alloc(u_int type, SOCKADDR *src, SOCKADDR *dst, struct socket *socket,
+ u_int unique_key, struct key_tblnode **keynodep)
+{
+ struct key_tblnode *keynode;
+ char buf[MAXHASHKEYLEN];
+ struct key_allocnode *np, *prevnp;
+ struct key_so2spinode *newnp;
+ int len;
+ int indx;
+
+ DPRINTF(IDL_FINISHED,("Entering key_alloc w/type=%u!\n",type));
+ if (!(src && dst)) {
+ DPRINTF(IDL_ERROR,("key_alloc: received null src or dst!\n"));
+ return(-1);
+ }
+
+ /*
+ * Search key allocation table
+ */
+ bzero((char *)&buf, sizeof(buf));
+ len = key_createkey((char *)&buf, type, src, dst, 0, 1);
+ indx = key_gethashval((char *)&buf, len, KEYALLOCTBLSIZE);
+
+#define np_type np->keynode->secassoc->type
+#define np_state np->keynode->secassoc->state
+#define np_src np->keynode->secassoc->src
+#define np_dst np->keynode->secassoc->dst
+
+ prevnp = &keyalloctbl[indx];
+ for (np = keyalloctbl[indx].next; np; np = np->next) {
+ if ((type == np_type) && addrpart_equal(src, np_src) &&
+ addrpart_equal(dst, np_dst) &&
+ !(np_state & (K_LARVAL | K_DEAD | K_UNIQUE))) {
+ if (!(unique_key))
+ break;
+ if (!(np_state & K_USED))
+ break;
+ }
+ prevnp = np;
+ }
+
+ if (np) {
+ struct socketlist *newsp;
+ CRITICAL_DCL
+
+ CRITICAL_START;
+
+ DPRINTF(IDL_EVENT,("key_alloc: found node to allocate\n"));
+ keynode = np->keynode;
+
+ KMALLOC(newnp, struct key_so2spinode *, sizeof(struct key_so2spinode));
+ if (newnp == 0) {
+ DPRINTF(IDL_ERROR,("key_alloc: Can't alloc mem for so2spi node!\n"));
+ CRITICAL_END;
+ return(ENOBUFS);
+ }
+ KMALLOC(newsp, struct socketlist *, sizeof(struct socketlist));
+ if (newsp == 0) {
+ DPRINTF(IDL_ERROR,("key_alloc: Can't alloc mem for socketlist!\n"));
+ if (newnp)
+ KFREE(newnp);
+ CRITICAL_END;
+ return(ENOBUFS);
+ }
+
+ /*
+ * Add a hash entry into the so2spi table to
+ * map socket to allocated secassoc.
+ */
+ DPRINTF(IDL_FINISHED,("key_alloc: adding entry to so2spi table..."));
+ newnp->keynode = keynode;
+ newnp->socket = socket;
+ newnp->next = so2spitbl[((u_int32_t)socket) % SO2SPITBLSIZE].next;
+ so2spitbl[((u_int32_t)socket) % SO2SPITBLSIZE].next = newnp;
+ DPRINTF(IDL_FINISHED,("done\n"));
+
+ if (unique_key) {
+ /*
+ * Need to remove the allocation entry
+ * since the secassoc is now unique,
+ * can't be allocated to any other socket
+ */
+ DPRINTF(IDL_EVENT,("key_alloc: making keynode unique..."));
+ keynode->secassoc->state |= K_UNIQUE;
+ prevnp->next = np->next;
+ KFREE(np);
+ DPRINTF(IDL_EVENT,("done\n"));
+ }
+ keynode->secassoc->state |= K_USED;
+ keynode->secassoc->state |= K_OUTBOUND;
+ keynode->alloc_count++;
+
+ /*
+ * Add socket to list of socket using secassoc.
+ */
+ DPRINTF(IDL_FINISHED,("key_alloc: adding so to solist..."));
+ newsp->socket = socket;
+ newsp->next = keynode->solist->next;
+ keynode->solist->next = newsp;
+ DPRINTF(IDL_FINISHED,("done\n"));
+ *keynodep = keynode;
+ CRITICAL_END;
+ return(0);
+ }
+ *keynodep = NULL;
+ return(0);
+}
+
+
+/*----------------------------------------------------------------------
+ * key_free():
+ * Decrement the refcount for a key table entry. If the entry is
+ * marked dead,, the refcount is zero, we go ahead, delete it.
+ ----------------------------------------------------------------------*/
+void
+key_free(struct key_tblnode *keynode)
+{
+ DPRINTF(IDL_GROSS_EVENT,("Entering key_free w/keynode=0x%x\n",
+ (unsigned int)keynode));
+ if (!keynode) {
+ DPRINTF(IDL_ERROR,("Warning: key_free got null pointer\n"));
+ return;
+ }
+ (keynode->ref_count)--;
+ if (keynode->ref_count < 0) {
+ DPRINTF(IDL_ERROR,("Warning: key_free decremented refcount to %d\n",keynode->ref_count));
+ }
+ if ((keynode->secassoc->state & K_DEAD) && (keynode->ref_count <= 0)) {
+ DPRINTF(IDL_GROSS_EVENT,("key_free: calling key_delete\n"));
+ key_delete(keynode->secassoc);
+ }
+}
+
+/*----------------------------------------------------------------------
+ * getassocbyspi():
+ * Get a security association for a given type, src, dst,, spi.
+ *
+ * Returns: 0 if sucessfull
+ * -1 if error/not found
+ *
+ * Caller must convert spi to host order. Function assumes spi is
+ * in host order!
+ ----------------------------------------------------------------------*/
+int
+getassocbyspi(u_int type, SOCKADDR *src, SOCKADDR *dst, u_int32_t spi,
+ struct key_tblnode **keyentry)
+{
+ char buf[MAXHASHKEYLEN];
+ int len, indx;
+ struct key_tblnode *keynode, *prevkeynode = 0;
+
+ DPRINTF(IDL_FINISHED,("Entering getassocbyspi w/type=%u spi=%u\n",type,spi));
+
+ *keyentry = NULL;
+ bzero(&buf, sizeof(buf));
+ len = key_createkey((char *)&buf, type, src, dst, spi, 0);
+ indx = key_gethashval((char *)&buf, len, KEYTBLSIZE);
+ DPRINTF(IDL_FINISHED,("getassocbyspi: indx=%d\n",indx));
+ DDO(IDL_FINISHED,dump_sockaddr(src);dump_sockaddr(dst));
+ keynode = key_search(type, src, dst, spi, indx, &prevkeynode);
+ DPRINTF(IDL_FINISHED,("getassocbyspi: keysearch ret=0x%x\n",
+ (unsigned int)keynode));
+ if (keynode && !(keynode->secassoc->state & (K_DEAD | K_LARVAL))) {
+ DPRINTF(IDL_GROSS_EVENT,("getassocbyspi: found secassoc!\n"));
+ (keynode->ref_count)++;
+ keynode->secassoc->state |= K_USED;
+ *keyentry = keynode;
+ } else {
+ DPRINTF(IDL_EVENT,("getassocbyspi: secassoc not found!\n"));
+ return (-1);
+ }
+ return(0);
+}
+
+
+/*----------------------------------------------------------------------
+ * getassocbysocket():
+ * Get a security association for a given type, src, dst,, socket.
+ * If not found, try to allocate one.
+ * Returns: 0 if successfull
+ * -1 if error condition/secassoc not found (*keyentry = NULL)
+ * 1 if secassoc temporarily unavailable (*keynetry = NULL)
+ * (e.g., key mgnt. daemon(s) called)
+ ----------------------------------------------------------------------*/
+int
+getassocbysocket(u_int type, SOCKADDR *src, SOCKADDR *dst,
+ struct socket *socket, u_int unique_key,
+ struct key_tblnode **keyentry)
+{
+ struct key_tblnode *keynode = 0;
+ struct key_so2spinode *np;
+ u_int realtype;
+
+ DPRINTF(IDL_FINISHED,("Entering getassocbysocket w/type=%u so=0x%x\n",
+ type,(unsigned int)socket));
+
+ /*
+ * We treat esp-transport mode, esp-tunnel mode
+ * as a single type in the keytable. This has a side
+ * effect that socket using both esp-transport,
+ * esp-tunnel will use the same security association
+ * for both modes. Is this a problem?
+ */
+ realtype = type;
+ if ((np = key_sosearch(type, src, dst, socket))) {
+ if (np->keynode && np->keynode->secassoc &&
+ !(np->keynode->secassoc->state & (K_DEAD | K_LARVAL))) {
+ DPRINTF(IDL_FINISHED,("getassocbysocket: found secassoc!\n"));
+ (np->keynode->ref_count)++;
+ *keyentry = np->keynode;
+ return(0);
+ }
+ }
+
+ /*
+ * No secassoc has been allocated to socket,
+ * so allocate one, if available
+ */
+ DPRINTF(IDL_GROSS_EVENT,("getassocbyso: can't find it, trying to allocate!\n"));
+ if (key_alloc(realtype, src, dst, socket, unique_key, &keynode) == 0) {
+ if (keynode) {
+ DPRINTF(IDL_GROSS_EVENT,("getassocbyso: key_alloc found secassoc!\n"));
+ keynode->ref_count++;
+ *keyentry = keynode;
+ return(0);
+ } else {
+ /*
+ * Kick key mgnt. daemon(s)
+ * (this should be done in ipsec_output_policy() instead or
+ * selectively called based on a flag value)
+ */
+ DPRINTF(IDL_FINISHED,("getassocbyso: calling key mgnt daemons!\n"));
+ *keyentry = NULL;
+ if (key_acquire(realtype, src, dst) == 0)
+ return (1);
+ else
+ return(-1);
+ }
+ }
+ *keyentry = NULL;
+ return(-1);
+}
+
+/*----------------------------------------------------------------------
+ * key_xdata():
+ * Parse message buffer for src/dst/from/iv/key if parseflag = 0
+ * else parse for src/dst only.
+ ----------------------------------------------------------------------*/
+static int
+key_xdata(struct key_msghdr *km, struct key_msgdata *kip, int parseflag)
+{
+ char *cp, *cpmax;
+
+ if (!km || (km->key_msglen <= 0))
+ return (-1);
+
+ cp = (caddr_t)(km + 1);
+ cpmax = (caddr_t)km + km->key_msglen;
+
+ /*
+ * Assumes user process passes message with
+ * correct word alignment.
+ */
+
+ /*
+ * Need to clean up this code later.
+ */
+
+ /* Grab src addr */
+ kip->src = (SOCKADDR *)cp;
+ if (!kip->src->sa_len) {
+ DPRINTF(IDL_MAJOR_EVENT,("key_xdata couldn't parse src addr\n"));
+ return(-1);
+ }
+
+ ADVANCE(cp, kip->src->sa_len);
+
+ /* Grab dest addr */
+ kip->dst = (SOCKADDR *)cp;
+ if (!kip->dst->sa_len) {
+ DPRINTF(IDL_MAJOR_EVENT,("key_xdata couldn't parse dest addr\n"));
+ return(-1);
+ }
+
+ ADVANCE(cp, kip->dst->sa_len);
+ if (parseflag == 1) {
+ kip->from = 0;
+ kip->key = kip->iv = 0;
+ kip->keylen = kip->ivlen = 0;
+ return(0);
+ }
+
+ /* Grab from addr */
+ kip->from = (SOCKADDR *)cp;
+ if (!kip->from->sa_len) {
+ DPRINTF(IDL_MAJOR_EVENT,("key_xdata couldn't parse from addr\n"));
+ return(-1);
+ }
+
+ ADVANCE(cp, kip->from->sa_len);
+
+ /* Grab key */
+ if ((kip->keylen = km->keylen)) {
+ kip->key = cp;
+ ADVANCE(cp, km->keylen);
+ } else
+ kip->key = 0;
+
+ /* Grab iv */
+ if ((kip->ivlen = km->ivlen))
+ kip->iv = cp;
+ else
+ kip->iv = 0;
+
+ return (0);
+}
+
+
+int
+key_parse(struct key_msghdr **kmp, struct socket *so, int *dstfamily)
+{
+ int error = 0, keyerror = 0;
+ struct key_msgdata keyinfo;
+ struct key_secassoc *secassoc = NULL;
+ struct key_msghdr *km = *kmp;
+
+ DPRINTF(IDL_MAJOR_EVENT, ("Entering key_parse\n"));
+
+#define senderr(e) \
+ { error = (e); goto flush; }
+
+ if (km->key_msgvers != KEY_VERSION) {
+ DPRINTF(IDL_CRITICAL,("keyoutput: Unsupported key message version!\n"));
+ senderr(EPROTONOSUPPORT);
+ }
+
+ km->key_pid = CURRENT_PID;
+
+ DDO(IDL_MAJOR_EVENT, printf("keymsghdr:\n"); dump_keymsghdr(km));
+
+ /*
+ * Parse buffer for src addr, dest addr, from addr, key, iv
+ */
+ bzero((char *)&keyinfo, sizeof(keyinfo));
+
+ switch (km->key_msgtype) {
+ case KEY_ADD:
+ DPRINTF(IDL_MAJOR_EVENT,("key_output got KEY_ADD msg\n"));
+
+ if (key_xdata(km, &keyinfo, 0) < 0)
+ goto parsefail;
+
+ /*
+ * Allocate the secassoc structure to insert
+ * into key table here.
+ */
+ KMALLOC(secassoc, struct key_secassoc *, sizeof(struct key_secassoc));
+ if (secassoc == 0) {
+ DPRINTF(IDL_CRITICAL,("keyoutput: No more memory!\n"));
+ senderr(ENOBUFS);
+ }
+
+ if (key_msghdr2secassoc(secassoc, km, &keyinfo) < 0) {
+ DPRINTF(IDL_CRITICAL,("keyoutput: key_msghdr2secassoc failed!\n"));
+ KFREE(secassoc);
+ senderr(EINVAL);
+ }
+ DPRINTF(IDL_MAJOR_EVENT,("secassoc to add:\n"));
+ DDO(IDL_MAJOR_EVENT,dump_secassoc(secassoc));
+
+ if ((keyerror = key_add(secassoc)) != 0) {
+ DPRINTF(IDL_CRITICAL,("keyoutput: key_add failed\n"));
+ if (secassoc->key)
+ KFREE(secassoc->key);
+ if (secassoc->iv)
+ KFREE(secassoc->iv);
+ KFREE(secassoc);
+ if (keyerror == -2) {
+ senderr(EEXIST);
+ } else {
+ senderr(ENOBUFS);
+ }
+ }
+ break;
+ case KEY_DELETE:
+ DPRINTF(IDL_MAJOR_EVENT,("key_output got KEY_DELETE msg\n"));
+
+ if (key_xdata(km, &keyinfo, 1) < 0)
+ goto parsefail;
+
+ KMALLOC(secassoc, struct key_secassoc *, sizeof(struct key_secassoc));
+ if (secassoc == 0) {
+ senderr(ENOBUFS);
+ }
+ if (key_msghdr2secassoc(secassoc, km, &keyinfo) < 0) {
+ KFREE(secassoc);
+ senderr(EINVAL);
+ }
+ if (key_delete(secassoc) != 0) {
+ if (secassoc->iv)
+ KFREE(secassoc->iv);
+ if (secassoc->key)
+ KFREE(secassoc->key);
+ KFREE(secassoc);
+ senderr(ESRCH);
+ }
+ if (secassoc->iv)
+ KFREE(secassoc->iv);
+ if (secassoc->key)
+ KFREE(secassoc->key);
+ KFREE(secassoc);
+ break;
+ case KEY_UPDATE:
+ DPRINTF(IDL_EVENT,("key_output got KEY_UPDATE msg\n"));
+
+ if (key_xdata(km, &keyinfo, 0) < 0)
+ goto parsefail;
+
+ KMALLOC(secassoc, struct key_secassoc *, sizeof(struct key_secassoc));
+ if (secassoc == 0) {
+ senderr(ENOBUFS);
+ }
+ if (key_msghdr2secassoc(secassoc, km, &keyinfo) < 0) {
+ KFREE(secassoc);
+ senderr(EINVAL);
+ }
+ if ((keyerror = key_update(secassoc)) != 0) {
+ DPRINTF(IDL_CRITICAL,("Error updating key entry\n"));
+ if (secassoc->iv)
+ KFREE(secassoc->iv);
+ if (secassoc->key)
+ KFREE(secassoc->key);
+ KFREE(secassoc);
+ senderr(keyerror);
+ }
+ KFREE(secassoc);
+ break;
+ case KEY_GET:
+ DPRINTF(IDL_EVENT,("key_output got KEY_GET msg\n"));
+
+ if (key_xdata(km, &keyinfo, 1) < 0)
+ goto parsefail;
+
+ if (key_get(km->type, (SOCKADDR *)keyinfo.src,
+ (SOCKADDR *)keyinfo.dst,
+ km->spi, &secassoc) != 0) {
+ DPRINTF(IDL_EVENT,("keyoutput: can't get key\n"));
+ senderr(ESRCH);
+ }
+
+ if (secassoc) {
+ int newlen;
+
+ DPRINTF(IDL_EVENT,("keyoutput: Found secassoc!\n"));
+ newlen = sizeof(struct key_msghdr) + ROUNDUP(secassoc->src->sa_len) +
+ ROUNDUP(secassoc->dst->sa_len) + ROUNDUP(secassoc->from->sa_len) +
+ ROUNDUP(secassoc->keylen) + ROUNDUP(secassoc->ivlen);
+ DPRINTF(IDL_EVENT,("keyoutput: newlen=%d\n", newlen));
+ if (newlen > km->key_msglen) {
+ struct key_msghdr *newkm;
+
+ DPRINTF(IDL_EVENT,("keyoutput: Allocating new buffer!\n"));
+ KMALLOC(newkm, struct key_msghdr *, newlen);
+ if (newkm == 0) {
+ senderr(ENOBUFS);
+ }
+ bcopy((char *)km, (char *)newkm, km->key_msglen);
+ DPRINTF(IDL_FINISHED,("keyoutput: 1\n"));
+ KFREE(km);
+ *kmp = km = newkm;
+ DPRINTF(IDL_CRITICAL, ("km->key_msglen = %d, newlen = %d\n",
+ km->key_msglen, newlen));
+ km->key_msglen = newlen;
+ }
+ DPRINTF(IDL_FINISHED,("keyoutput: 2\n"));
+ if (key_secassoc2msghdr(secassoc, km, &keyinfo)) {
+ DPRINTF(IDL_CRITICAL,("keyoutput: Can't create msghdr!\n"));
+ senderr(EINVAL);
+ }
+ DPRINTF(IDL_FINISHED,("keyoutput: 3\n"));
+ }
+ break;
+ case KEY_GETSPI:
+ DPRINTF(IDL_EVENT,("key_output got KEY_GETSPI msg\n"));
+
+ if (key_xdata(km, &keyinfo, 1) < 0)
+ goto parsefail;
+
+ if ((keyerror = key_getspi(km->type, keyinfo.src, keyinfo.dst,
+ km->lifetime1, km->lifetime2,
+ &(km->spi))) != 0) {
+ DPRINTF(IDL_CRITICAL,("keyoutput: getspi failed error=%d\n", keyerror));
+ senderr(keyerror);
+ }
+ break;
+ case KEY_REGISTER:
+ DPRINTF(IDL_EVENT,("key_output got KEY_REGISTER msg\n"));
+ key_register(so, km->type);
+ break;
+ case KEY_DUMP:
+ DPRINTF(IDL_EVENT,("key_output got KEY_DUMP msg\n"));
+ error = key_dump(so);
+ return(error);
+ break;
+ case KEY_FLUSH:
+ DPRINTF(IDL_EVENT,("key_output got KEY_FLUSH msg\n"));
+ key_flush();
+ break;
+ default:
+ DPRINTF(IDL_CRITICAL,("key_output got unsupported msg type=%d\n",
+ km->key_msgtype));
+ senderr(EOPNOTSUPP);
+ }
+
+ goto flush;
+
+parsefail:
+ keyinfo.dst = NULL;
+ error = EINVAL;
+
+flush:
+ if (km)
+ km->key_errno = error;
+
+ if (dstfamily)
+ *dstfamily = keyinfo.dst ? keyinfo.dst->sa_family : 0;
+
+ DPRINTF(IDL_MAJOR_EVENT, ("key_parse exiting with error=%d\n", error));
+ return error;
+}
+
+/*
+ * Definitions of protocols supported in the KEY domain.
+ */
+
+struct sockaddr key_addr = { 2, PF_KEY, };
+struct sockproto key_proto = { PF_KEY, };
+
+#define KEYREAPERINT 120
+
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+
+static int
+key_sendup(s, km)
+ struct socket *s;
+ struct key_msghdr *km;
+{
+ struct mbuf *m;
+ MGETHDR(m, M_WAIT, MT_DATA);
+ m->m_len = m->m_pkthdr.len = 0;
+ m->m_next = 0;
+ m->m_nextpkt = 0;
+ m->m_pkthdr.rcvif = 0;
+ m_copyback(m, 0, km->key_msglen, (caddr_t)km);
+
+ if (sbappendaddr(&(s->so_rcv), &key_addr, m, NULL)) {
+ sorwakeup(s);
+ return 1;
+ } else
+ m_freem(m);
+
+ return(0);
+}
+
+#ifdef notyet
+/*----------------------------------------------------------------------
+ * key_reaper():
+ * Scan key table, nuke unwanted entries
+ ----------------------------------------------------------------------*/
+static void
+key_reaper(whocares)
+ void *whocares;
+{
+ DPRINTF(IDL_GROSS_EVENT,("Entering key_reaper()\n"));
+
+ timeout(key_reaper, NULL, KEYREAPERINT * HZ);
+}
+#endif /* notyet */
+
+/*----------------------------------------------------------------------
+ * key_init():
+ * Init routine for key socket, key engine
+ ----------------------------------------------------------------------*/
+static void
+key_init(void)
+{
+ DPRINTF(IDL_EVENT,("Called key_init().\n"));
+ if (key_inittables())
+ panic("key_inittables failed!\n");
+#ifdef notyet
+ timeout(key_reaper, NULL, HZ);
+#endif /* notyet */
+ bzero((char *)&keyso_cb, sizeof(keyso_cb));
+}
+
+/*----------------------------------------------------------------------
+ * my_addr():
+ * Determine if an address belongs to one of my configured interfaces.
+ * Currently handles only AF_INET, AF_INET6 addresses.
+ ----------------------------------------------------------------------*/
+static int
+my_addr(sa)
+ SOCKADDR *sa;
+{
+ struct in6_ifaddr *i6a = 0;
+ struct in_ifaddr *ia = 0;
+
+ switch(sa->sa_family) {
+#ifdef INET6
+ case AF_INET6:
+ for (i6a = in6_ifaddr; i6a; i6a = i6a->i6a_next) {
+ if (IN6_ADDR_EQUAL(((struct sockaddr_in6 *)sa)->sin6_addr,
+ i6a->i6a_addr.sin6_addr))
+ return(1);
+ }
+ break;
+#endif /* INET6 */
+ case AF_INET:
+ for (ia = in_ifaddr; ia; ia = ia->ia_next) {
+ if (((struct sockaddr_in *)sa)->sin_addr.s_addr ==
+ ia->ia_addr.sin_addr.s_addr)
+ return(1);
+ }
+ break;
+ }
+ return(0);
+}
+
+/*----------------------------------------------------------------------
+ * key_output():
+ * Process outbound pf_key message.
+ ----------------------------------------------------------------------*/
+static int
+key_output(struct mbuf *m, struct socket *so)
+{
+ struct key_msghdr *km = 0;
+ caddr_t cp, cplimit;
+ int len;
+ int error = 0;
+ int dstfamily = 0;
+
+ DPRINTF(IDL_EVENT,("key_output() got a message len=%d.\n", m->m_pkthdr.len));
+
+#undef senderr
+#define senderr(e) \
+ { error = (e); if (km) km->key_errno = error; goto flush; }
+
+ if (m == 0 || ((m->m_len < sizeof(long)) &&
+ (m = m_pullup(m, sizeof(long))) == 0)) {
+ DPRINTF(IDL_CRITICAL,("key_output can't pullup mbuf\n"));
+ return (ENOBUFS);
+ }
+ if ((m->m_flags & M_PKTHDR) == 0)
+ panic("key_output");
+
+ DDO(IDL_FINISHED,dump_mbuf(m));
+
+ len = m->m_pkthdr.len;
+ if (len < sizeof(*km) || len != mtod(m, struct key_msghdr *)->key_msglen) {
+ DPRINTF(IDL_CRITICAL,("keyout: Invalid length field/length mismatch!\n"));
+ senderr(EINVAL);
+ }
+ KMALLOC(km, struct key_msghdr *, len);
+ if (km == 0) {
+ DPRINTF(IDL_CRITICAL,("keyoutput: Can't malloc memory!\n"));
+ senderr(ENOBUFS);
+ }
+
+ m_copydata(m, 0, len, (caddr_t)km);
+
+ km->key_errno = error = key_parse(&km, so, &dstfamily);
+ DPRINTF(IDL_MAJOR_EVENT, ("Back from key_parse\n"));
+flush:
+ key_sendup(so, km);
+#if 0
+ {
+ struct rawcb *rp = 0;
+ struct mbuf *m;
+
+ if ((so->so_options & SO_USELOOPBACK) == 0) {
+ if (keyso_cb.any_count <= 1) {
+ if (km)
+ KFREE(km);
+ return (error);
+ }
+ rp = sotorawcb(so);
+ }
+
+ DPRINTF(IDL_MAJOR_EVENT, ("key_output: foo\n"));
+ key_proto.sp_protocol = dstfamily;
+
+ if (km) {
+ m = m_devget(km, len, 0, NULL, NULL);
+ KFREE(km);
+ }
+
+ DPRINTF(IDL_MAJOR_EVENT, ("key_output: bar\n"));
+ if (rp)
+ rp->rcb_proto.sp_family = 0; /* Prevent us from receiving message */
+
+ raw_input(m, &key_proto, &key_addr, &key_addr);
+
+ if (rp)
+ rp->rcb_proto.sp_family = PF_KEY;
+ }
+ DPRINTF(IDL_MAJOR_EVENT, ("key_output: baz\n"));
+#endif /* 0 */
+ return (error);
+}
+
+
+/*----------------------------------------------------------------------
+ * key_usrreq():
+ * Handles PRU_* for pf_key sockets.
+ ----------------------------------------------------------------------*/
+static int
+key_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
+ struct mbuf *control)
+{
+ register int error = 0;
+ register struct rawcb *rp = sotorawcb(so);
+ int s;
+
+ DPRINTF(IDL_EVENT,("Entering key_usrreq, req = %d.\n",req));
+
+ if (req == PRU_ATTACH) {
+ MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
+ if (so->so_pcb = (caddr_t)rp)
+ bzero(so->so_pcb, sizeof(*rp));
+ }
+
+ if (req == PRU_DETACH && rp) {
+ int af = rp->rcb_proto.sp_protocol;
+ if (af == AF_INET)
+ keyso_cb.ip4_count--;
+#ifdef INET6
+ else if (af == AF_INET6)
+ keyso_cb.ip6_count--;
+#endif /* INET6 */
+ keyso_cb.any_count--;
+ }
+ s = splnet();
+ error = raw_usrreq(so, req, m, nam, control);
+ rp = sotorawcb(so);
+
+ if (req == PRU_ATTACH && rp) {
+ int af = rp->rcb_proto.sp_protocol;
+ if (error) {
+ free((caddr_t)rp, M_PCB);
+ splx(s);
+ return error;
+ }
+ if (af == AF_INET)
+ keyso_cb.ip4_count++;
+#ifdef INET6
+ else if (af == AF_INET6)
+ keyso_cb.ip6_count++;
+#endif /* INET6 */
+ keyso_cb.any_count++;
+ rp->rcb_faddr = &key_addr;
+ soisconnected(so); /* Key socket, like routing socket, must be
+ connected. */
+
+ /* Possibly set other needed flags/options at creation time in here. */
+ so->so_options |= SO_USELOOPBACK; /* Like routing socket, we turn this */
+ /* on by default */
+ }
+ splx(s);
+ return error;
+}
+
+/*----------------------------------------------------------------------
+ * key_cbinit():
+ * Control block init routine for key socket
+ ----------------------------------------------------------------------*/
+static void
+key_cbinit(void)
+{
+ /*
+ * This is equivalent to raw_init for the routing socket.
+ * The key socket uses the same control block as the routing
+ * socket.
+ */
+ DPRINTF(IDL_EVENT,("Called key_cbinit().\n"));
+}
+
+/*
+ * Protoswitch entry for pf_key
+ */
+
+extern struct domain keydomain; /* or at least forward */
+
+struct protosw keysw[] = {
+{ SOCK_RAW, &keydomain, 0, PR_ATOMIC|PR_ADDR,
+ raw_input, key_output, raw_ctlinput, 0,
+ key_usrreq,
+ key_cbinit
+}
+};
+
+struct domain keydomain =
+ { PF_KEY, "key", key_init, 0, 0,
+ keysw, &keysw[sizeof(keysw)/sizeof(keysw[0])] };
+
+DOMAIN_SET(key)
diff --git a/sys/netkey/key.h b/sys/netkey/key.h
new file mode 100644
index 0000000..920f9c4
--- /dev/null
+++ b/sys/netkey/key.h
@@ -0,0 +1,284 @@
+/*----------------------------------------------------------------------
+ * key.h : Declarations and Definitions for Key Engine for BSD.
+ *
+ * Copyright 1995 by Bao Phan, Randall Atkinson, & Dan McDonald,
+ * All Rights Reserved. All rights have been assigned to the US
+ * Naval Research Laboratory (NRL). The NRL Copyright Notice and
+ * License Agreement governs distribution and use of this software.
+ *
+ * Patents are pending on this technology. NRL grants a license
+ * to use this technology at no cost under the terms below with
+ * the additional requirement that software, hardware, and
+ * documentation relating to use of this technology must include
+ * the note that:
+ * This product includes technology developed at and
+ * licensed from the Information Technology Division,
+ * US Naval Research Laboratory.
+ *
+ ----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------
+# @(#)COPYRIGHT 1.1a (NRL) 17 August 1995
+
+COPYRIGHT NOTICE
+
+All of the documentation and software included in this software
+distribution from the US Naval Research Laboratory (NRL) are
+copyrighted by their respective developers.
+
+This software and documentation were developed at NRL by various
+people. Those developers have each copyrighted the portions that they
+developed at NRL and have assigned All Rights for those portions to
+NRL. Outside the USA, NRL also has copyright on the software
+developed at NRL. The affected files all contain specific copyright
+notices and those notices must be retained in any derived work.
+
+NRL LICENSE
+
+NRL grants permission for redistribution and use in source and binary
+forms, with or without modification, of the software and documentation
+created at NRL provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+
+ This product includes software developed at the Information
+ Technology Division, US Naval Research Laboratory.
+
+4. Neither the name of the NRL nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
+IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation
+are those of the authors and should not be interpreted as representing
+official policies, either expressed or implied, of the US Naval
+Research Laboratory (NRL).
+
+----------------------------------------------------------------------*/
+
+#ifndef _netkey_key_h
+#define _netkey_key_h 1
+
+/*
+ * PF_KEY messages
+ */
+
+#define KEY_ADD 1
+#define KEY_DELETE 2
+#define KEY_UPDATE 3
+#define KEY_GET 4
+#define KEY_ACQUIRE 5
+#define KEY_GETSPI 6
+#define KEY_REGISTER 7
+#define KEY_EXPIRE 8
+#define KEY_DUMP 9
+#define KEY_FLUSH 10
+
+#define KEY_VERSION 1
+#define POLICY_VERSION 1
+
+#define SECURITY_TYPE_NONE 0
+
+#define KEY_TYPE_AH 1
+#define KEY_TYPE_ESP 2
+#define KEY_TYPE_RSVP 3
+#define KEY_TYPE_OSPF 4
+#define KEY_TYPE_RIPV2 5
+#define KEY_TYPE_MIPV4 6
+#define KEY_TYPE_MIPV6 7
+#define KEY_TYPE_MAX 7
+
+/*
+ * Security association state
+ */
+
+#define K_USED 0x1 /* Key used/not used */
+#define K_UNIQUE 0x2 /* Key unique/reusable */
+#define K_LARVAL 0x4 /* SPI assigned, but sa incomplete */
+#define K_ZOMBIE 0x8 /* sa expired but still useable */
+#define K_DEAD 0x10 /* sa marked for deletion, ready for reaping */
+#define K_INBOUND 0x20 /* sa for inbound packets, ie. dst=myhost */
+#define K_OUTBOUND 0x40 /* sa for outbound packets, ie. src=myhost */
+
+
+#ifndef MAX_SOCKADDR_SZ
+#ifdef INET6
+#define MAX_SOCKADDR_SZ (sizeof(struct sockaddr_in6))
+#else /* INET6 */
+#define MAX_SOCKADDR_SZ (sizeof(struct sockaddr_in))
+#endif /* INET6 */
+#endif /* MAX_SOCKADDR_SZ */
+
+#ifndef MAX_KEY_SZ
+#define MAX_KEY_SZ 16
+#endif /* MAX_KEY_SZ */
+
+#ifndef MAX_IV_SZ
+#define MAX_IV_SZ 16
+#endif /* MAX_IV_SZ */
+
+/* Security association data for IP Security */
+struct key_secassoc {
+ u_int8_t len; /* Length of the data (for radix) */
+ u_int8_t type; /* Type of association */
+ u_int8_t state; /* State of the association */
+ u_int8_t label; /* Sensitivity label (unused) */
+ u_int32_t spi; /* SPI */
+ u_int8_t keylen; /* Key length */
+ u_int8_t ivlen; /* Initialization vector length */
+ u_int8_t algorithm; /* Algorithm switch index */
+ u_int8_t lifetype; /* Type of lifetime */
+ caddr_t iv; /* Initialization vector */
+ caddr_t key; /* Key */
+ u_int32_t lifetime1; /* Lifetime value 1 */
+ u_int32_t lifetime2; /* Lifetime value 2 */
+ struct sockaddr *src; /* Source host address */
+ struct sockaddr *dst; /* Destination host address */
+ struct sockaddr *from; /* Originator of association */
+};
+
+/*
+ * Structure for key message header. PF_KEY message consists of key_msghdr
+ * followed by src struct sockaddr, dest struct sockaddr, from struct
+ * sockaddr, key, and iv. Assumes size of key message header less than MHLEN.
+ */
+
+struct key_msghdr {
+ u_short key_msglen; /* length of message including
+ * src/dst/from/key/iv */
+ u_char key_msgvers; /* key version number */
+ u_char key_msgtype; /* key message type, eg. KEY_ADD */
+ pid_t key_pid;/* process id of message sender */
+ int key_seq;/* message sequence number */
+ int key_errno; /* error code */
+ u_int8_t type; /* type of security association */
+ u_int8_t state; /* state of security association */
+ u_int8_t label; /* sensitivity level */
+ u_int8_t pad; /* padding for allignment */
+ u_int32_t spi; /* spi value */
+ u_int8_t keylen; /* key length */
+ u_int8_t ivlen; /* iv length */
+ u_int8_t algorithm; /* algorithm identifier */
+ u_int8_t lifetype; /* type of lifetime */
+ u_int32_t lifetime1; /* lifetime value 1 */
+ u_int32_t lifetime2; /* lifetime value 2 */
+};
+
+struct key_msgdata {
+ struct sockaddr *src; /* source host address */
+ struct sockaddr *dst; /* destination host address */
+ struct sockaddr *from; /* originator of security association */
+ caddr_t iv; /* initialization vector */
+ caddr_t key; /* key */
+ int ivlen; /* key length */
+ int keylen; /* iv length */
+};
+
+struct policy_msghdr {
+ u_short policy_msglen; /* message length */
+ u_char policy_msgvers; /* message version */
+ u_char policy_msgtype; /* message type */
+ int policy_seq; /* message sequence number */
+ int policy_errno; /* error code */
+};
+
+/*
+ * Key engine table structures
+ */
+
+struct socketlist {
+ struct socket *socket; /* pointer to socket */
+ struct socketlist *next;/* next */
+};
+
+struct key_tblnode {
+ int alloc_count; /* number of sockets allocated to
+ * secassoc */
+ int ref_count; /* number of sockets referencing
+ * secassoc */
+ struct socketlist *solist; /* list of sockets allocated to
+ * secassoc */
+ struct key_secassoc *secassoc; /* security association */
+ struct key_tblnode *next; /* next node */
+};
+
+struct key_allocnode {
+ struct key_tblnode *keynode;
+ struct key_allocnode *next;
+};
+
+struct key_so2spinode {
+ struct socket *socket; /* socket pointer */
+ struct key_tblnode *keynode; /* pointer to tblnode containing
+ * secassoc */
+ /* info for socket */
+ struct key_so2spinode *next;
+};
+
+struct key_registry {
+ u_int8_t type; /* secassoc type that key mgnt. daemon can
+ * acquire */
+ struct socket *socket; /* key management daemon socket pointer */
+ struct key_registry *next;
+};
+
+struct key_acquirelist {
+ u_int8_t type; /* secassoc type to acquire */
+ struct sockaddr *target;/* destination address of secassoc */
+ u_int32_t count; /* number of acquire messages sent */
+ u_long expiretime; /* expiration time for acquire
+ * message */
+ struct key_acquirelist *next;
+};
+
+struct keyso_cb {
+ int ip4_count; /* IPv4 */
+#ifdef INET6
+ int ip6_count; /* IPv6 */
+#endif /* INET6 */
+ int any_count; /* Sum of above counters */
+};
+
+#ifdef KERNEL
+int key_inittables __P((void));
+int key_secassoc2msghdr __P((struct key_secassoc *, struct key_msghdr *,
+ struct key_msgdata *));
+int key_msghdr2secassoc __P((struct key_secassoc *, struct key_msghdr *,
+ struct key_msgdata *));
+int key_add __P((struct key_secassoc *));
+int key_delete __P((struct key_secassoc *));
+int key_get __P((u_int, struct sockaddr *, struct sockaddr *, u_int32_t,
+ struct key_secassoc **));
+void key_flush __P((void));
+int key_dump __P((struct socket *));
+int key_getspi __P((u_int, struct sockaddr *, struct sockaddr *, u_int32_t,
+ u_int32_t, u_int32_t *));
+int key_update __P((struct key_secassoc *));
+int key_register __P((struct socket *, u_int));
+void key_unregister __P((struct socket *, u_int, int));
+int key_acquire __P((u_int, struct sockaddr *, struct sockaddr *));
+int getassocbyspi __P((u_int, struct sockaddr *, struct sockaddr *, u_int32_t,
+ struct key_tblnode **));
+int getassocbysocket __P((u_int, struct sockaddr *, struct sockaddr *,
+ struct socket *, u_int, struct key_tblnode **));
+void key_free __P((struct key_tblnode *));
+int key_parse __P((struct key_msghdr ** km, struct socket * so, int *));
+#endif /* KERNEL */
+
+#endif /* _netkey_key_h */
diff --git a/sys/netkey/key_debug.c b/sys/netkey/key_debug.c
new file mode 100644
index 0000000..c928c84
--- /dev/null
+++ b/sys/netkey/key_debug.c
@@ -0,0 +1,730 @@
+/*
+ * in6_debug.c -- Insipired by Craig Metz's Net/2 in6_debug.c, but
+ * not quite as heavyweight (initially, anyway).
+ *
+ * The idea is to have globals here, and dump netinet6/ data structures.
+ *
+ * Copyright 1995 by Dan McDonald, Bao Phan, and Randall Atkinson,
+ * All Rights Reserved.
+ * All Rights under this copyright have been assigned to NRL.
+ */
+
+/*----------------------------------------------------------------------
+# @(#)COPYRIGHT 1.1a (NRL) 17 August 1995
+
+COPYRIGHT NOTICE
+
+All of the documentation and software included in this software
+distribution from the US Naval Research Laboratory (NRL) are
+copyrighted by their respective developers.
+
+This software and documentation were developed at NRL by various
+people. Those developers have each copyrighted the portions that they
+developed at NRL and have assigned All Rights for those portions to
+NRL. Outside the USA, NRL also has copyright on the software
+developed at NRL. The affected files all contain specific copyright
+notices and those notices must be retained in any derived work.
+
+NRL LICENSE
+
+NRL grants permission for redistribution and use in source and binary
+forms, with or without modification, of the software and documentation
+created at NRL provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+
+ This product includes software developed at the Information
+ Technology Division, US Naval Research Laboratory.
+
+4. Neither the name of the NRL nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
+IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation
+are those of the authors and should not be interpreted as representing
+official policies, either expressed or implied, of the US Naval
+Research Laboratory (NRL).
+
+----------------------------------------------------------------------*/
+
+
+#define INET6_DEBUG_C
+
+#include <netkey/osdep_44bsd.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/mbuf.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+
+#ifdef INET6
+#include <netinet6/in6.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/ipv6.h>
+#include <netinet6/ipv6_var.h>
+#include <netinet6/ipv6_icmp.h>
+#else /* INET6 */
+#if 0
+#include "in6_types.h"
+#endif
+#endif /* INET6 */
+
+#define SA_LEN 1
+#define SIN_LEN 1
+
+#ifdef KEY_DEBUG
+#include <netkey/key.h>
+#endif /* KEY_DEBUG */
+#ifdef IPSEC_DEBUG
+#include <netsec/ipsec.h>
+#endif /* IPSEC_DEBUG */
+
+#if 0
+#include <netinet6/in6_debug.h>
+#endif
+
+#ifndef DEFARGS
+#define DEFARGS(arglist, args) arglist args;
+#define AND ;
+#endif /* DEFARGS */
+
+/*
+ * Globals
+ */
+
+/* The following should be sysctl-tweakable. */
+
+unsigned int in6_debug_level = IDL_FINISHED + 1; /* 0 is no debugging */
+
+/*
+ * Functions and macros.
+ */
+
+void in6_debug_init DEFARGS((), void)
+{
+ /* For now, nothing. */
+}
+
+/*----------------------------------------------------------------------
+ * dump_* dumps various data structures. These should be called within
+ * the context of a DDO() macro. They assume address and port fields
+ * are in network order.
+ ----------------------------------------------------------------------*/
+
+#ifdef INET6
+/*----------------------------------------------------------------------
+ * Dump an IPv6 address. Don't compress 0's out because of debugging.
+ ----------------------------------------------------------------------*/
+void dump_in_addr6 DEFARGS((in_addr6),
+ struct in_addr6 *in_addr6)
+{
+ u_short *shorts = (u_short *)in_addr6;
+ int i = 0;
+
+ if (!in_addr6) {
+ printf("Dereference a NULL in_addr6? I don't think so.\n");
+ return;
+ }
+
+ printf("(conv. for printing) ");
+ while (i < 7)
+ printf("%4x:",htons(shorts[i++]));
+ printf("%4x\n",htons(shorts[7]));
+}
+#endif /* INET6 */
+
+/*----------------------------------------------------------------------
+ * Dump and IPv4 address in x.x.x.x form.
+ ----------------------------------------------------------------------*/
+void dump_in_addr DEFARGS((in_addr),
+ struct in_addr *in_addr)
+{
+ u_char *chars = (u_char *)in_addr;
+ int i = 0;
+
+ if (!in_addr) {
+ printf("Dereference a NULL in_addr? I don't think so.\n");
+ return;
+ }
+
+ while (i < 3)
+ printf("%d.",chars[i++]);
+ printf("%d\n",chars[3]);
+}
+
+#ifdef INET6
+/*----------------------------------------------------------------------
+ * Dump an IPv6 socket address.
+ ----------------------------------------------------------------------*/
+void dump_sockaddr_in6 DEFARGS((sin6),
+ struct sockaddr_in6 *sin6)
+{
+ if (!sin6) {
+ printf("Dereference a NULL sockaddr_in6? I don't think so.\n");
+ return;
+ }
+
+ printf("sin6_len = %d, sin6_family = %d, sin6_port = %d (0x%x)\n",
+ sin6->sin6_len,sin6->sin6_family, htons(sin6->sin6_port),
+ htons(sin6->sin6_port));
+ printf("sin6_flowinfo = 0x%x\n",sin6->sin6_flowinfo);
+ printf("sin6_addr = ");
+ dump_in_addr6(&sin6->sin6_addr);
+}
+#endif /* INET6 */
+
+/*----------------------------------------------------------------------
+ * Dump an IPv4 socket address.
+ ----------------------------------------------------------------------*/
+void dump_sockaddr_in DEFARGS((sin),
+ struct sockaddr_in *sin)
+{
+ int i;
+
+ if (!sin) {
+ printf("Dereference a NULL sockaddr_in? I don't think so.\n");
+ return;
+ }
+
+#ifdef SIN_LEN
+ printf("sin_len = %d, ", sin->sin_len);
+#endif /* SIN_LEN */
+ printf("sin_family = %d, sin_port (conv.) = %d (0x%x)\n",
+ sin->sin_family, htons(sin->sin_port),
+ htons(sin->sin_port));
+ printf("sin_addr = ");
+ dump_in_addr(&sin->sin_addr);
+ printf("sin_zero == ");
+ for(i=0;i<8;i++)
+ printf("0x%2x ",sin->sin_zero[i]);
+ printf("\n");
+}
+
+/*----------------------------------------------------------------------
+ * Dump a generic socket address. Use if no family-specific routine is
+ * available.
+ ----------------------------------------------------------------------*/
+void dump_sockaddr DEFARGS((sa),
+SOCKADDR *sa)
+{
+ if (!sa) {
+ printf("Dereference a NULL sockaddr? I don't think so.\n");
+ return;
+ }
+
+#ifdef SA_LEN
+ printf("sa_len = %d, ", sa->sa_len);
+#endif /* SA_LEN */
+ printf("sa_family = %d", sa->sa_family);
+#ifdef SA_LEN
+ printf(", remaining bytes are:\n");
+ {
+ int i;
+ for (i = 0; i <sa->sa_len - 2; i++)
+ printf("0x%2x ",(unsigned char)sa->sa_data[i]);
+ }
+#endif /* SA_LEN */
+ printf("\n");
+}
+
+/*----------------------------------------------------------------------
+ * Dump a link-layer socket address. (Not that there are user-level link
+ * layer sockets, but there are plenty of link-layer addresses in the kernel.)
+ ----------------------------------------------------------------------*/
+void dump_sockaddr_dl DEFARGS((sdl),
+ struct sockaddr_dl *sdl)
+{
+ char buf[256];
+
+ if (!sdl) {
+ printf("Dereference a NULL sockaddr_dl? I don't think so.\n");
+ return;
+ }
+
+ printf("sdl_len = %d, sdl_family = %d, sdl_index = %d, sdl_type = %d,\n",
+ sdl->sdl_len, sdl->sdl_family, sdl->sdl_index, sdl->sdl_type);
+ buf[sdl->sdl_nlen] = 0;
+ if (sdl->sdl_nlen)
+ bcopy(sdl->sdl_data,buf,sdl->sdl_nlen);
+ printf("sdl_nlen = %d, (name = '%s'\n",sdl->sdl_nlen,buf);
+ printf("sdl_alen = %d, ",sdl->sdl_alen);
+ if (sdl->sdl_alen)
+ {
+ int i;
+
+ printf("(addr = ");
+ for (i = 0; i<sdl->sdl_alen; i++)
+ printf("0x%2x ",(unsigned char)sdl->sdl_data[i+sdl->sdl_nlen]);
+ }
+ printf("\n");
+ printf("sdl_slen = %d, ",sdl->sdl_slen);
+ if (sdl->sdl_slen)
+ {
+ int i;
+
+ printf("(addr = ");
+ for (i = 0; i<sdl->sdl_slen; i++)
+ printf("0x%2x ",
+ (unsigned char)sdl->sdl_data[i+sdl->sdl_nlen+sdl->sdl_alen]);
+ }
+ printf("\n");
+}
+
+/*----------------------------------------------------------------------
+ * Dump a socket address, calling a family-specific routine if available.
+ ----------------------------------------------------------------------*/
+void dump_smart_sockaddr DEFARGS((sa),
+SOCKADDR *sa)
+{
+ DPRINTF(IDL_MAJOR_EVENT, ("Entering dump_smart_sockaddr\n"));
+ if (!sa) {
+ printf("Dereference a NULL sockaddr? I don't think so.\n");
+ return;
+ }
+
+ switch (sa->sa_family)
+ {
+#ifdef INET6
+ case AF_INET6:
+ dump_sockaddr_in6((struct sockaddr_in6 *)sa);
+ break;
+#endif /* INET6 */
+ case AF_INET:
+ dump_sockaddr_in((struct sockaddr_in *)sa);
+ break;
+ case AF_LINK:
+ dump_sockaddr_dl((struct sockaddr_dl *)sa);
+ break;
+ default:
+ dump_sockaddr(sa);
+ break;
+ }
+}
+
+#ifdef INET6
+/*----------------------------------------------------------------------
+ * Dump an IPv6 header.
+ ----------------------------------------------------------------------*/
+void dump_ipv6 DEFARGS((ipv6),
+ struct ipv6 *ipv6)
+{
+ if (!ipv6) {
+ printf("Dereference a NULL ipv6? I don't think so.\n");
+ return;
+ }
+
+ printf("Vers & flow label (conv to host order) 0x%x\n",
+ htonl(ipv6->ipv6_versfl));
+ printf("Length (conv) = %d, nexthdr = %d, hoplimit = %d.\n",
+ htons(ipv6->ipv6_length),ipv6->ipv6_nexthdr,ipv6->ipv6_hoplimit);
+ printf("Src: ");
+ dump_in_addr6(&ipv6->ipv6_src);
+ printf("Dst: ");
+ dump_in_addr6(&ipv6->ipv6_dst);
+}
+
+/*----------------------------------------------------------------------
+ * Dump an ICMPv6 header. This function is not very smart beyond the
+ * type, code, and checksum.
+ ----------------------------------------------------------------------*/
+dump_ipv6_icmp DEFARGS((icp),
+ struct ipv6_icmp *icp)
+{
+ int i;
+
+ if (!icp) {
+ printf("Dereference a NULL ipv6_icmp? I don't think so.\n");
+ return;
+ }
+
+ printf("type %d, code %d, cksum (conv) = 0x%x\n",icp->icmp_type,
+ icp->icmp_code,htons(icp->icmp_cksum));
+ printf("First four bytes: 0x%x",htonl(icp->icmp_unused));
+ printf("Next four bytes: 0x");
+ for (i=0;i<4;i++)
+ printf("%x",icp->icmp_echodata[i]);
+ printf("\n");
+}
+#endif /* INET6 */
+
+/*----------------------------------------------------------------------
+ * Dump only the header fields of a single mbuf.
+ ----------------------------------------------------------------------*/
+void dump_mbuf_hdr DEFARGS((m),
+ struct mbuf *m)
+{
+ if (!m) {
+ printf("Dereference a NULL mbuf? I don't think so.\n");
+ return;
+ }
+
+ printf("Single mbuf at %08x\n", m);
+ printf("m_len = %d, m_data = 0x%x, m_type = %d\n",m->m_len,
+ m->m_data, m->m_type);
+ printf("m_flags = 0x%x ",m->m_flags);
+ if (m->m_flags & M_PKTHDR)
+ printf("m_pkthdr.len = %d, m_pkthdr.rcvif = 0x%x",m->m_pkthdr.len,
+ m->m_pkthdr.rcvif);
+ if (m->m_flags & M_EXT)
+ printf(" (IS CLUSTER MBUF)");
+ printf("\nm_next = 0x%x m_nextpkt = 0x%x\n",m->m_next, m->m_nextpkt);
+}
+
+/*----------------------------------------------------------------------
+ * Dump the entire contents of a single mbuf.
+ ----------------------------------------------------------------------*/
+void dump_mbuf DEFARGS((m),
+ struct mbuf *m)
+{
+ int i;
+
+ dump_mbuf_hdr(m);
+ printf("m_data:\n");
+ for (i = 0; i < m->m_len; i++)
+ printf("0x%2x%s",(unsigned char)m->m_data[i] , ((i+1) % 16)?" ":"\n");
+ printf((i % 16)?"\n":"");
+}
+
+/*----------------------------------------------------------------------
+ * Dump the contents of an mbuf chain. (WARNING: Lots of text may
+ * result.
+ ----------------------------------------------------------------------*/
+void dump_mchain DEFARGS((m),
+ struct mbuf *m)
+{
+ struct mbuf *walker;
+ int i;
+
+ for (walker = m, i = 0; walker != NULL && (i < 10);
+ walker = walker->m_next, i++)
+ dump_mbuf(walker);
+}
+
+/*----------------------------------------------------------------------
+ * Dump an mbuf chain's data in a format similar to tcpdump(8).
+ ----------------------------------------------------------------------*/
+void dump_tcpdump DEFARGS((m),
+ struct mbuf *m)
+{
+ struct mbuf *walker;
+ int i, j, count;
+
+ for (i = count = 0; m && (i < 10); m = m->m_next, i++) {
+ for (j = 0; j < m->m_len; j++, count++) {
+ if (!(count % (2 * 8)))
+ printf("\n\t\t\t");
+ if (!(count % 2))
+ printf(" ");
+ printf("%02x", (u_int8)(m->m_data[j]));
+ }
+ }
+}
+
+#ifdef INET6
+/*----------------------------------------------------------------------
+ * Dump an IPv6 header index table, which is terminated by an entry with
+ * a NULL mbuf pointer.
+ ----------------------------------------------------------------------*/
+void dump_ihitab DEFARGS((ihi),
+ struct in6_hdrindex *ihi)
+{
+ int i=0;
+
+ if (!ihi) {
+ printf("Dereference a NULL hdrindex/ihi? I don't think so.\n");
+ return;
+ }
+
+ /* This is dangerous, make sure ihitab was bzeroed. */
+ while (ihi[i].ihi_mbuf)
+ {
+ printf("ihi_nexthdr = %d, ihi_mbuf = 0x%x.\n",ihi[i].ihi_nexthdr,
+ ihi[i].ihi_mbuf);
+ i++;
+ }
+}
+#endif /* INET6 */
+
+/*----------------------------------------------------------------------
+ * Dump an interface address.
+ ----------------------------------------------------------------------*/
+void dump_ifa DEFARGS((ifa),
+ struct ifaddr *ifa)
+{
+ if (ifa == NULL)
+ {
+ printf("ifa of NULL.\n");
+ return;
+ }
+
+ printf("ifa_addr: ");
+ dump_smart_sockaddr(ifa->ifa_addr);
+ printf("ifa_netmask: ");
+ dump_smart_sockaddr(ifa->ifa_netmask);
+}
+
+/*----------------------------------------------------------------------
+ * Dump an interface structure.
+ ----------------------------------------------------------------------*/
+void dump_ifp DEFARGS((ifp),
+ struct ifnet *ifp)
+{
+ if (!ifp) {
+ printf("Dereference a NULL ifnet/ifp? I don't think so.\n");
+ return;
+ }
+
+ printf("Interface name: %s.\n",ifp->if_name);
+ printf("Interface type: %d. ",ifp->if_type);
+ printf("MTU: %d.\n",ifp->if_mtu);
+}
+
+/*----------------------------------------------------------------------
+ * Dump a route structure (sockaddr/rtentry pair).
+ ----------------------------------------------------------------------*/
+void dump_route DEFARGS((ro),
+ struct route *ro)
+{
+ if (!ro) {
+ printf("Dereference a NULL route? I don't think so.\n");
+ return;
+ }
+
+ printf("ro_rt = 0x%x, ro_dst is:\n",ro->ro_rt);
+ dump_smart_sockaddr(&ro->ro_dst);
+}
+
+/*----------------------------------------------------------------------
+ * Dump a routing entry.
+ ----------------------------------------------------------------------*/
+void dump_rtentry DEFARGS((rt),
+ struct rtentry *rt)
+{
+ if (!rt) {
+ printf("Dereference a NULL rtentry? I don't think so.\n");
+ return;
+ }
+
+ printf("rt_key is:\n");
+ dump_smart_sockaddr(rt_key(rt));
+ printf("rt_mask is:\n");
+ dump_smart_sockaddr(rt_mask(rt));
+ printf("rt_llinfo = 0x%x ",rt->rt_llinfo);
+ printf("rt_rmx.rmx_mtu = %d ",rt->rt_rmx.rmx_mtu);
+ printf("rt_refcnt = %d ",rt->rt_refcnt);
+ printf("rt_flags = 0x%x\n",rt->rt_flags);
+ printf("rt_ifp is:\n");
+ dump_ifp(rt->rt_ifp);
+ printf("rt_ifa is:\n");
+ dump_ifa(rt->rt_ifa);
+}
+
+/*----------------------------------------------------------------------
+ * Dump an Internet (v4/v6) protocol control block.
+ ----------------------------------------------------------------------*/
+void dump_inpcb DEFARGS((inp),
+ struct inpcb *inp)
+{
+ if (!inp) {
+ printf("Dereference a NULL inpcb? I don't think so.\n");
+ return;
+ }
+
+ printf("inp_next = 0x%x, inp_prev = 0x%x, inp_head = 0x%x.\n",inp->inp_next,
+ inp->inp_prev, inp->inp_head);
+ printf("inp_socket = 0x%x, inp_ppcb\n",inp->inp_socket,inp->inp_ppcb);
+#ifdef INET6
+ printf("faddr, faddr6:\n");
+ dump_in_addr(&inp->inp_faddr); dump_in_addr6(&inp->inp_faddr6);
+ printf("laddr, laddr6:\n");
+ dump_in_addr(&inp->inp_laddr); dump_in_addr6(&inp->inp_laddr6);
+#else /* INET6 */
+ printf("faddr:\n");
+ dump_in_addr(&inp->inp_faddr);
+ printf("laddr:\n");
+ dump_in_addr(&inp->inp_laddr);
+#endif /* INET6 */
+ printf("inp_route: ");
+ dump_route(&inp->inp_route);
+#ifdef INET6
+ printf("inp_ipv6:");
+ dump_ipv6(&inp->inp_ipv6);
+#endif /* INET6 */
+ printf("inp_ip:");
+ printf("<Coming soon.>\n");
+ printf("inp_options = 0x%x, inp_moptions{6,} = 0x%x,\n",inp->inp_options,
+ inp->inp_moptions);
+ printf("inp_flags = 0x%x, inp_fport = %d, inp_lport = %d.\n",
+ (unsigned)inp->inp_flags,inp->inp_fport, inp->inp_lport);
+}
+
+#ifdef INET6
+/*----------------------------------------------------------------------
+ * Dump an IPv6 discovery queue structure.
+ ----------------------------------------------------------------------*/
+void dump_discq DEFARGS((dq),
+ struct discq *dq)
+{
+ if (!dq) {
+ printf("Dereference a NULL discq? I don't think so.\n");
+ return;
+ }
+
+ printf("dq_next = 0x%x, dq_prev = 0x%x, dq_rt = 0x%x,\n",dq->dq_next,
+ dq->dq_prev, dq->dq_rt);
+ printf("dq_queue = 0x%x.\n",dq->dq_queue);
+ /* Dump first mbuf chain? */
+ /*printf("dq_expire = %d (0x%x).\n",dq->dq_expire,dq->dq_expire);*/
+}
+#endif /* INET6 */
+
+/*----------------------------------------------------------------------
+ * Dump a data buffer
+ ----------------------------------------------------------------------*/
+void dump_buf DEFARGS((buf, len),
+ char *buf AND
+ int len)
+{
+ int i;
+
+ printf("buf=0x%x len=%d:\n", (unsigned int)buf, len);
+ for (i = 0; i < len; i++) {
+ printf("0x%x ", (u_int8)*(buf+i));
+ }
+ printf("\n");
+}
+
+
+/*----------------------------------------------------------------------
+ * Dump a key_tblnode structrue
+ ----------------------------------------------------------------------*/
+void dump_keytblnode DEFARGS((ktblnode),
+ struct key_tblnode *ktblnode)
+{
+ if (!ktblnode) {
+ printf("NULL key table node pointer!\n");
+ return;
+ }
+ printf("solist=0x%x ", (unsigned int)ktblnode->solist);
+ printf("secassoc=0x%x ", (unsigned int)ktblnode->secassoc);
+ printf("next=0x%x\n", (unsigned int)ktblnode->next);
+}
+
+/*----------------------------------------------------------------------
+ * Dump an ipsec_assoc structure
+ ----------------------------------------------------------------------*/
+void dump_secassoc DEFARGS((seca),
+struct key_secassoc *seca)
+{
+ u_int8 *p;
+ int i;
+
+ if (seca) {
+ printf("secassoc_len=%u ", seca->len);
+ printf("secassoc_type=%d ", seca->type);
+ printf("secassoc_state=0x%x\n", seca->state);
+ printf("secassoc_label=%u ", seca->label);
+ printf("secassoc_spi=0x%x ", (unsigned int)seca->spi);
+ printf("secassoc_keylen=%u\n", seca->keylen);
+ printf("secassoc_ivlen=%u ", seca->ivlen);
+ printf("secassoc_algorithm=%u ", seca->algorithm);
+ printf("secassoc_lifetype=%u\n", seca->lifetype);
+ printf("secassoc_iv=0x%x:\n", (unsigned int)seca->iv);
+ p = (u_int8 *)(seca->iv);
+ for (i = 0 ; i < seca->ivlen; i++)
+ printf("0x%x ", *(p + i));
+ printf("secassoc_key=0x%x:\n", (unsigned int)seca->key);
+ p = (u_int8 *)(seca->key);
+ for (i = 0 ; i < seca->keylen; i++)
+ printf("0x%x ", *(p + i));
+ printf("secassoc_lifetime1=%u ", (unsigned int)seca->lifetime1);
+ printf("secassoc_lifetime2=%u\n", (unsigned int)seca->lifetime2);
+ dump_smart_sockaddr(seca->src);
+ dump_smart_sockaddr(seca->dst);
+ dump_smart_sockaddr(seca->from);
+ } else
+ printf("can't dump null secassoc pointer!\n");
+}
+
+
+/*----------------------------------------------------------------------
+ * Dump a key_msghdr structure
+ ----------------------------------------------------------------------*/
+void dump_keymsghdr DEFARGS((km),
+ struct key_msghdr *km)
+{
+ if (km) {
+ printf("key_msglen=%d\n", km->key_msglen);
+ printf("key_msgvers=%d\n", km->key_msgvers);
+ printf("key_msgtype=%d\n", km->key_msgtype);
+ printf("key_pid=%d\n", km->key_pid);
+ printf("key_seq=%d\n", km->key_seq);
+ printf("key_errno=%d\n", km->key_errno);
+ printf("type=0x%x\n", (unsigned int)km->type);
+ printf("state=0x%x\n", (unsigned int)km->state);
+ printf("label=0x%x\n", (unsigned int)km->label);
+ printf("spi=0x%x\n", (unsigned int)km->spi);
+ printf("keylen=%d\n", km->keylen);
+ printf("ivlen=%d\n", km->ivlen);
+ printf("algorithm=%d\n", km->algorithm);
+ printf("lifetype=0x%x\n", (unsigned int)km->lifetype);
+ printf("lifetime1=%u\n", (unsigned int)km->lifetime1);
+ printf("lifetime2=%u\n", (unsigned int)km->lifetime2);
+ } else
+ printf("key_msghdr pointer is NULL!\n");
+}
+
+
+/*----------------------------------------------------------------------
+ * Dump a key_msgdata structure
+ ----------------------------------------------------------------------*/
+void dump_keymsginfo DEFARGS((kp),
+ struct key_msgdata *kp)
+{
+ int i;
+
+ if (kp) {
+ printf("src addr:\n");
+ dump_smart_sockaddr(kp->src);
+ printf("dest addr:\n");
+ dump_smart_sockaddr(kp->dst);
+ printf("from addr:\n");
+ dump_smart_sockaddr(kp->from);
+#define dumpbuf(a, b) \
+ { for (i= 0; i < (b); i++) \
+ printf("0x%2x%s", (unsigned char)(*((caddr_t)a+i)),((i+1)%16)?" ":"\n");\
+ printf("\n"); }
+ printf("iv is:\n");
+ dumpbuf(kp->iv, kp->ivlen);
+ printf("key is:\n");
+ dumpbuf(kp->key, kp->keylen);
+#undef dumpbuf
+ } else
+ printf("key_msgdata point is NULL!\n");
+}
diff --git a/sys/netkey/key_debug.h b/sys/netkey/key_debug.h
new file mode 100644
index 0000000..05f1bc8
--- /dev/null
+++ b/sys/netkey/key_debug.h
@@ -0,0 +1,151 @@
+/*
+ * in6_debug.h -- Insipired by Craig Metz's Net/2 in6_debug.h, but
+ * not quite as heavyweight (initially, anyway).
+ *
+ * In particular, if function exit-entries are to be
+ * documented, do them in a lightweight fashion.
+ *
+ * Copyright 1995 by Dan McDonald, Bao Phan, and Randall Atkinson,
+ * All Rights Reserved.
+ * All Rights under this copyright have been assigned to NRL.
+ */
+
+/*----------------------------------------------------------------------
+# @(#)COPYRIGHT 1.1a (NRL) 17 August 1995
+
+COPYRIGHT NOTICE
+
+All of the documentation and software included in this software
+distribution from the US Naval Research Laboratory (NRL) are
+copyrighted by their respective developers.
+
+This software and documentation were developed at NRL by various
+people. Those developers have each copyrighted the portions that they
+developed at NRL and have assigned All Rights for those portions to
+NRL. Outside the USA, NRL also has copyright on the software
+developed at NRL. The affected files all contain specific copyright
+notices and those notices must be retained in any derived work.
+
+NRL LICENSE
+
+NRL grants permission for redistribution and use in source and binary
+forms, with or without modification, of the software and documentation
+created at NRL provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+
+ This product includes software developed at the Information
+ Technology Division, US Naval Research Laboratory.
+
+4. Neither the name of the NRL nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
+IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation
+are those of the authors and should not be interpreted as representing
+official policies, either expressed or implied, of the US Naval
+Research Laboratory (NRL).
+
+----------------------------------------------------------------------*/
+
+/* IDL_* is IPv6 Debug Level */
+
+#define IDL_ALL 0xFFFFFFFE /* Report all messages. */
+#define IDL_NONE 0 /* Report no messages. */
+
+#define IDL_CRITICAL 3
+#define IDL_ERROR 7
+#define IDL_MAJOR_EVENT 10
+#define IDL_EVENT 15
+#define IDL_GROSS_EVENT 20
+#define IDL_FINISHED 0xFFFFFFF0
+
+/*
+ * Make sure argument for DPRINTF is in parentheses.
+ *
+ * For both DPRINTF and DDO, and attempt was made to make both macros
+ * be usable as normal C statments. There is a small amount of compiler
+ * trickery (if-else clauses with effectively null statements), which may
+ * cause a few compilers to complain.
+ */
+
+#ifdef INET6_DEBUG
+
+/*
+ * DPRINTF() is a general printf statement. The "arg" is literally what
+ * would follow the function name printf, which means it has to be in
+ * parenthesis. Unlimited arguments can be used this way.
+ *
+ * EXAMPLE:
+ * DPRINTF(IDL_MAJOR_EVENT,("Hello, world. IP version %d.\n",vers));
+ */
+#define DPRINTF(lev,arg) if ((lev) < in6_debug_level) { \
+ printf arg; \
+ } \
+ else in6_debug_level = in6_debug_level
+
+/*
+ * DDO() executes a series of statements at a certain debug level. The
+ * "stmt" argument is a statement in the sense of a "statement list" in a
+ * C grammar. "stmt" does not have to end with a semicolon.
+ *
+ * EXAMPLE:
+ * DDO(IDL_CRITICAL,dump_ipv6(header), dump_inpcb(inp));
+ */
+#define DDO(lev,stmt) if ((lev) < in6_debug_level) { stmt ; } \
+ else in6_debug_level = in6_debug_level
+
+/*
+ * DP() is a shortcut for DPRINTF(). Basically:
+ *
+ * DP(lev, var, fmt) == DPRINTF(IDL_lev, ("var = %fmt\n", var))
+ *
+ * It is handy for printing single variables without a lot of typing.
+ *
+ * EXAMPLE:
+ *
+ * DP(CRITICAL,length,d);
+ * same as DPRINTF(IDL_CRITICAL, ("length = %d\n", length))
+ */
+#define DP(lev, var, fmt) DPRINTF(IDL_ ## lev, (#var " = %" #fmt "\n", var))
+
+#ifndef SOCKADDR
+#define SOCKADDR struct sockaddr
+#endif /* SOCKADDR */
+
+void dump_buf __P((char *, int));
+void dump_sockaddr __P((SOCKADDR *));
+void dump_smart_sockaddr __P((SOCKADDR *));
+void dump_keytblnode __P((struct key_tblnode *));
+void dump_secassoc __P((struct key_secassoc *));
+void dump_keymsghdr __P((struct key_msghdr *));
+
+#else /* ! INET6_DEBUG */
+
+#define DPRINTF(lev,arg)
+#define DDO(lev, stmt)
+#define DP(x, y, z)
+
+#endif /* INET6_DEBUG */
+
+#ifndef INET6_DEBUG_C
+extern unsigned int in6_debug_level;
+#endif
OpenPOWER on IntegriCloud