Convert socket options code to use a sockopt structure trunk
authorplunky <plunky@NetBSD.org>
Wed, 06 Aug 2008 15:01:23 +0000
branchtrunk
changeset 172240 b3f1b9a84a51
parent 172239 5f58a4adec94
child 172241 c461fba41ccd
Convert socket options code to use a sockopt structure instead of laying everything into an mbuf. approved by core
sys/compat/linux/common/linux_socket.c
sys/dev/bluetooth/bthidev.c
sys/dev/bluetooth/btsco.c
sys/kern/uipc_accf.c
sys/kern/uipc_socket.c
sys/kern/uipc_syscalls.c
sys/kern/uipc_usrreq.c
sys/net/if_gre.c
sys/netbt/hci.h
sys/netbt/hci_socket.c
sys/netbt/l2cap.h
sys/netbt/l2cap_socket.c
sys/netbt/l2cap_upper.c
sys/netbt/rfcomm.h
sys/netbt/rfcomm_dlc.c
sys/netbt/rfcomm_session.c
sys/netbt/rfcomm_socket.c
sys/netbt/rfcomm_upper.c
sys/netbt/sco.h
sys/netbt/sco_socket.c
sys/netbt/sco_upper.c
sys/netinet/ip_mroute.c
sys/netinet/ip_mroute.h
sys/netinet/ip_output.c
sys/netinet/ip_var.h
sys/netinet/raw_ip.c
sys/netinet/tcp_usrreq.c
sys/netinet/tcp_var.h
sys/netinet/udp_usrreq.c
sys/netinet/udp_var.h
sys/netinet6/icmp6.c
sys/netinet6/ip6_mroute.c
sys/netinet6/ip6_mroute.h
sys/netinet6/ip6_output.c
sys/netinet6/ip6_var.h
sys/netinet6/ip6protosw.h
sys/netinet6/raw_ip6.c
sys/netiso/clnp.h
sys/netiso/clnp_raw.c
sys/netiso/tp_output.c
sys/netiso/tp_usrreq.c
sys/netiso/tp_var.h
sys/netsmb/smb_trantcp.c
sys/nfs/nfs_boot.c
sys/nfs/nfs_bootdhcp.c
sys/nfs/nfs_socket.c
sys/nfs/nfs_syscalls.c
sys/sys/protosw.h
sys/sys/socketvar.h
sys/sys/un.h
--- a/sys/compat/linux/common/linux_socket.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/compat/linux/common/linux_socket.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: linux_socket.c,v 1.97 2008/07/03 14:07:09 njoly Exp $	*/
+/*	$NetBSD: linux_socket.c,v 1.98 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*-
  * Copyright (c) 1995, 1998, 2008 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.97 2008/07/03 14:07:09 njoly Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.98 2008/08/06 15:01:23 plunky Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -315,14 +315,11 @@
 		struct socket *so;
 
 		if (fd_getsock(*retval, &so) == 0) {
-			struct mbuf *m;
-
-			m = m_get(M_WAIT, MT_SOOPTS);
-			m->m_len = sizeof(int);
-			*mtod(m, int *) = 0;
+			int val = 0;
 
 			/* ignore error */
-			(void) sosetopt(so, IPPROTO_IPV6, IPV6_V6ONLY, m);
+			(void)so_setsockopt(l, so, IPPROTO_IPV6, IPV6_V6ONLY,
+			    &val, sizeof(val));
 
 			fd_putfile(*retval);
 		}
--- a/sys/dev/bluetooth/bthidev.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/dev/bluetooth/bthidev.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: bthidev.c,v 1.15 2008/04/24 11:38:36 ad Exp $	*/
+/*	$NetBSD: bthidev.c,v 1.16 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bthidev.c,v 1.15 2008/04/24 11:38:36 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bthidev.c,v 1.16 2008/08/06 15:01:23 plunky Exp $");
 
 #include <sys/param.h>
 #include <sys/conf.h>
@@ -43,6 +43,7 @@
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/proc.h>
+#include <sys/socketvar.h>
 #include <sys/systm.h>
 
 #include <prop/proplib.h>
@@ -72,7 +73,7 @@
 
 	bdaddr_t		sc_laddr;	/* local address */
 	bdaddr_t		sc_raddr;	/* remote address */
-	int			sc_mode;	/* link mode */
+	struct sockopt		sc_mode;	/* link mode sockopt */
 
 	uint16_t		sc_ctlpsm;	/* control PSM */
 	struct l2cap_channel	*sc_ctl;	/* control channel */
@@ -193,6 +194,8 @@
 	sc->sc_ctlpsm = L2CAP_PSM_HID_CNTL;
 	sc->sc_intpsm = L2CAP_PSM_HID_INTR;
 
+	sockopt_init(&sc->sc_mode, BTPROTO_L2CAP, SO_L2CAP_LM, 0);
+
 	/*
 	 * extract config from proplist
 	 */
@@ -205,11 +208,11 @@
 	obj = prop_dictionary_get(dict, BTDEVmode);
 	if (prop_object_type(obj) == PROP_TYPE_STRING) {
 		if (prop_string_equals_cstring(obj, BTDEVauth))
-			sc->sc_mode = L2CAP_LM_AUTH;
+			sockopt_setint(&sc->sc_mode, L2CAP_LM_AUTH);
 		else if (prop_string_equals_cstring(obj, BTDEVencrypt))
-			sc->sc_mode = L2CAP_LM_ENCRYPT;
+			sockopt_setint(&sc->sc_mode, L2CAP_LM_ENCRYPT);
 		else if (prop_string_equals_cstring(obj, BTDEVsecure))
-			sc->sc_mode = L2CAP_LM_SECURE;
+			sockopt_setint(&sc->sc_mode, L2CAP_LM_SECURE);
 		else  {
 			aprint_error(" unknown %s\n", BTDEVmode);
 			return;
@@ -356,6 +359,8 @@
 		config_detach(hidev->sc_dev, flags);
 	}
 
+	sockopt_destroy(&sc->sc_mode);
+
 	return 0;
 }
 
@@ -449,7 +454,7 @@
 	if (err)
 		return err;
 
-	err = l2cap_setopt(sc->sc_ctl_l, SO_L2CAP_LM, &sc->sc_mode);
+	err = l2cap_setopt(sc->sc_ctl_l, &sc->sc_mode);
 	if (err)
 		return err;
 
@@ -469,7 +474,7 @@
 	if (err)
 		return err;
 
-	err = l2cap_setopt(sc->sc_int_l, SO_L2CAP_LM, &sc->sc_mode);
+	err = l2cap_setopt(sc->sc_int_l, &sc->sc_mode);
 	if (err)
 		return err;
 
@@ -508,7 +513,7 @@
 		return err;
 	}
 
-	err = l2cap_setopt(sc->sc_ctl, SO_L2CAP_LM, &sc->sc_mode);
+	err = l2cap_setopt(sc->sc_ctl, &sc->sc_mode);
 	if (err)
 		return err;
 
@@ -565,7 +570,7 @@
 		if (err)
 			goto fail;
 
-		err = l2cap_setopt(sc->sc_int, SO_L2CAP_LM, &sc->sc_mode);
+		err = l2cap_setopt(sc->sc_int, &sc->sc_mode);
 		if (err)
 			goto fail;
 
@@ -734,12 +739,15 @@
 bthidev_linkmode(void *arg, int new)
 {
 	struct bthidev_softc *sc = arg;
+	int mode;
 
-	if ((sc->sc_mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
+	(void)sockopt_getint(&sc->sc_mode, &mode);
+
+	if ((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
 		aprint_error_dev(sc->sc_dev, "auth failed\n");
-	else if ((sc->sc_mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
+	else if ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
 		aprint_error_dev(sc->sc_dev, "encrypt off\n");
-	else if ((sc->sc_mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE))
+	else if ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE))
 		aprint_error_dev(sc->sc_dev, "insecure\n");
 	else
 		return;
--- a/sys/dev/bluetooth/btsco.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/dev/bluetooth/btsco.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: btsco.c,v 1.21 2008/06/23 12:34:38 plunky Exp $	*/
+/*	$NetBSD: btsco.c,v 1.22 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: btsco.c,v 1.21 2008/06/23 12:34:38 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: btsco.c,v 1.22 2008/08/06 15:01:23 plunky Exp $");
 
 #include <sys/param.h>
 #include <sys/audioio.h>
@@ -44,6 +44,7 @@
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/proc.h>
+#include <sys/socketvar.h>
 #include <sys/systm.h>
 #include <sys/intr.h>
 
@@ -560,6 +561,7 @@
 {
 	struct sockaddr_bt sa;
 	struct btsco_softc *sc = hdl;
+	struct sockopt sopt;
 	int err, timo;
 
 	DPRINTF("%s flags 0x%x\n", sc->sc_name, flags);
@@ -633,7 +635,10 @@
 		break;
 
 	case BTSCO_OPEN:		/* hurrah */
-		sco_getopt(sc->sc_sco, SO_SCO_MTU, &sc->sc_mtu);
+		sockopt_init(&sopt, BTPROTO_SCO, SO_SCO_MTU, 0);
+		(void)sco_getopt(sc->sc_sco, &sopt);
+		(void)sockopt_get(&sopt, &sc->sc_mtu, sizeof(sc->sc_mtu));
+		sockopt_destroy(&sopt);
 		break;
 
 	default:
--- a/sys/kern/uipc_accf.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/kern/uipc_accf.c	Wed Aug 06 15:01:23 2008 +0000
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_accf.c,v 1.1 2008/08/04 03:55:47 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_accf.c,v 1.2 2008/08/06 15:01:23 plunky Exp $");
 
 #define ACCEPT_FILTER_MOD
 
@@ -221,11 +221,11 @@
 }
 
 int
-do_getopt_accept_filter(struct socket *so, struct mbuf *m)
+do_getopt_accept_filter(struct socket *so, struct sockopt *sopt)
 {
+	struct accept_filter_arg afa;
 	int error;
 
-	error = 0;
 	SOCK_LOCK(so);
 	if ((so->so_options & SO_ACCEPTCONN) == 0) {
 		error = EINVAL;
@@ -235,27 +235,29 @@
 		error = EINVAL;
 		goto out;
 	}
-	m->m_len = sizeof(struct accept_filter_arg);
-	strcpy(mtod(m, struct accept_filter_arg *)->af_name, so->so_accf->so_accept_filter->accf_name);
+
+	memset(&afa, 0, sizeof(afa));
+	strcpy(afa.af_name, so->so_accf->so_accept_filter->accf_name);
 	if (so->so_accf->so_accept_filter_str != NULL)
-		strcpy(mtod(m, struct accept_filter_arg *)->af_arg, so->so_accf->so_accept_filter_str);
+		strcpy(afa.af_arg, so->so_accf->so_accept_filter_str);
+	error = sockopt_set(sopt, &afa, sizeof(afa));
 out:
 	SOCK_UNLOCK(so);
 	return (error);
 }
 
 int
-do_setopt_accept_filter(struct socket *so, struct mbuf *m)
+do_setopt_accept_filter(struct socket *so, const struct sockopt *sopt)
 {
-	struct accept_filter_arg *afap;
+	struct accept_filter_arg afa;
 	struct accept_filter *afp;
 	struct so_accf *newaf;
-	int error = 0;
+	int error;
 
 	/*
 	 * Handle the simple delete case first.
 	 */
-	if (m == NULL || mtod(m, struct accept_filter_arg *) == NULL) {
+	if (sopt == NULL || sopt->sopt_size == 0) {
 		SOCK_LOCK(so);
 		if ((so->so_options & SO_ACCEPTCONN) == 0) {
 			SOCK_UNLOCK(so);
@@ -281,13 +283,13 @@
 	 * Pre-allocate any memory we may need later to avoid blocking at
 	 * untimely moments.  This does not optimize for invalid arguments.
 	 */
-	if (m->m_len != sizeof(struct accept_filter_arg)) {
-		return (EINVAL);
+	error = sockopt_get(sopt, &afa, sizeof(afa));
+	if (error) {
+		return (error);
 	}
-	afap = mtod(m, struct accept_filter_arg *);
-	afap->af_name[sizeof(afap->af_name)-1] = '\0';
-	afap->af_arg[sizeof(afap->af_arg)-1] = '\0';
-	afp = accept_filt_get(afap->af_name);
+	afa.af_name[sizeof(afa.af_name)-1] = '\0';
+	afa.af_arg[sizeof(afa.af_arg)-1] = '\0';
+	afp = accept_filt_get(afa.af_name);
 	if (afp == NULL) {
 		return (ENOENT);
 	}
@@ -299,11 +301,11 @@
 	 */
 	MALLOC(newaf, struct so_accf *, sizeof(*newaf), M_ACCF, M_WAITOK |
 	    M_ZERO);
-	if (afp->accf_create != NULL && afap->af_name[0] != '\0') {
-		int len = strlen(afap->af_name) + 1;
+	if (afp->accf_create != NULL && afa.af_name[0] != '\0') {
+		int len = strlen(afa.af_name) + 1;
 		MALLOC(newaf->so_accept_filter_str, char *, len, M_ACCF,
 		    M_WAITOK);
-		strcpy(newaf->so_accept_filter_str, afap->af_name);
+		strcpy(newaf->so_accept_filter_str, afa.af_name);
 	}
 
 	/*
@@ -324,7 +326,7 @@
 	 */
 	if (afp->accf_create != NULL) {
 		newaf->so_accept_filter_arg =
-		    afp->accf_create(so, afap->af_arg);
+		    afp->accf_create(so, afa.af_arg);
 		if (newaf->so_accept_filter_arg == NULL) {
 			error = EINVAL;
 			goto out;
--- a/sys/kern/uipc_socket.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/kern/uipc_socket.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: uipc_socket.c,v 1.170 2008/08/04 03:55:47 tls Exp $	*/
+/*	$NetBSD: uipc_socket.c,v 1.171 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2002, 2007, 2008 The NetBSD Foundation, Inc.
@@ -63,7 +63,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.170 2008/08/04 03:55:47 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.171 2008/08/06 15:01:23 plunky Exp $");
 
 #include "opt_inet.h"
 #include "opt_sock_counters.h"
@@ -419,17 +419,6 @@
 	return m;
 }
 
-struct mbuf *
-m_intopt(struct socket *so, int val)
-{
-	struct mbuf *m;
-
-	m = getsombuf(so, MT_SOOPTS);
-	m->m_len = sizeof(int);
-	*mtod(m, int *) = val;
-	return m;
-}
-
 void
 soinit(void)
 {
@@ -1575,41 +1564,41 @@
 	sbrelease(&asb, so);
 }
 
+/*
+ * internal set SOL_SOCKET options
+ */
 static int
-sosetopt1(struct socket *so, int level, int optname, struct mbuf *m)
+sosetopt1(struct socket *so, const struct sockopt *sopt)
 {
-#ifdef INET
-	int error, optval, val;
-#else
-	int optval, val;
-#endif
-	struct linger	*l;
-	struct sockbuf	*sb;
-	struct timeval *tv;
+	int error, optval;
+	struct linger l;
+	struct timeval tv;
 
-	switch (optname) {
+	switch (sopt->sopt_name) {
 
 #ifdef INET
 	case SO_ACCEPTFILTER:
-		error = do_setopt_accept_filter(so, m);
+		error = do_setopt_accept_filter(so, sopt);
 		if (error)
 			return error;
 		break;
 #endif
 
-	case SO_LINGER:
-		if (m == NULL || m->m_len != sizeof(struct linger))
-			return EINVAL;
-		l = mtod(m, struct linger *);
-		if (l->l_linger < 0 || l->l_linger > USHRT_MAX ||
-		    l->l_linger > (INT_MAX / hz))
+  	case SO_LINGER:
+ 		error = sockopt_get(sopt, &l, sizeof(l));
+ 		if (error)
+ 			return (error);
+ 
+ 		if (l.l_linger < 0 || l.l_linger > USHRT_MAX ||
+ 		    l.l_linger > (INT_MAX / hz))
 			return EDOM;
-		so->so_linger = l->l_linger;
-		if (l->l_onoff)
-			so->so_options |= SO_LINGER;
-		else
-			so->so_options &= ~SO_LINGER;
-		break;
+ 		so->so_linger = l.l_linger;
+ 		if (l.l_onoff)
+ 			so->so_options |= SO_LINGER;
+ 		else
+ 			so->so_options &= ~SO_LINGER;
+ 
+  		break;
 
 	case SO_DEBUG:
 	case SO_KEEPALIVE:
@@ -1620,38 +1609,44 @@
 	case SO_REUSEPORT:
 	case SO_OOBINLINE:
 	case SO_TIMESTAMP:
-		if (m == NULL || m->m_len < sizeof(int))
-			return EINVAL;
-		if (*mtod(m, int *))
-			so->so_options |= optname;
+		error = sockopt_getint(sopt, &optval);
+		if (error)
+			return (error);
+
+		if (optval)
+			so->so_options |= sopt->sopt_name;
 		else
-			so->so_options &= ~optname;
+			so->so_options &= ~sopt->sopt_name;
 		break;
 
 	case SO_SNDBUF:
 	case SO_RCVBUF:
 	case SO_SNDLOWAT:
 	case SO_RCVLOWAT:
-		if (m == NULL || m->m_len < sizeof(int))
-			return EINVAL;
+		error = sockopt_getint(sopt, &optval);
+		if (error)
+			return (error);
 
 		/*
 		 * Values < 1 make no sense for any of these
 		 * options, so disallow them.
 		 */
-		optval = *mtod(m, int *);
 		if (optval < 1)
 			return EINVAL;
 
-		switch (optname) {
+		switch (sopt->sopt_name) {
+		case SO_SNDBUF:
+			if (sbreserve(&so->so_snd, (u_long)optval, so) == 0)
+				return ENOBUFS;
 
-		case SO_SNDBUF:
+			so->so_snd.sb_flags &= ~SB_AUTOSIZE;
+			break;
+
 		case SO_RCVBUF:
-			sb = (optname == SO_SNDBUF) ?
-			    &so->so_snd : &so->so_rcv;
-			if (sbreserve(sb, (u_long)optval, so) == 0)
+			if (sbreserve(&so->so_rcv, (u_long)optval, so) == 0)
 				return ENOBUFS;
-			sb->sb_flags &= ~SB_AUTOSIZE;
+
+			so->so_rcv.sb_flags &= ~SB_AUTOSIZE;
 			break;
 
 		/*
@@ -1659,36 +1654,40 @@
 		 * the high-water.
 		 */
 		case SO_SNDLOWAT:
-			so->so_snd.sb_lowat =
-			    (optval > so->so_snd.sb_hiwat) ?
-			    so->so_snd.sb_hiwat : optval;
+			if (optval > so->so_snd.sb_hiwat)
+				optval = so->so_snd.sb_hiwat;
+
+			so->so_snd.sb_lowat = optval;
 			break;
+
 		case SO_RCVLOWAT:
-			so->so_rcv.sb_lowat =
-			    (optval > so->so_rcv.sb_hiwat) ?
-			    so->so_rcv.sb_hiwat : optval;
+			if (optval > so->so_rcv.sb_hiwat)
+				optval = so->so_rcv.sb_hiwat;
+
+			so->so_rcv.sb_lowat = optval;
 			break;
 		}
 		break;
 
 	case SO_SNDTIMEO:
 	case SO_RCVTIMEO:
-		if (m == NULL || m->m_len < sizeof(*tv))
-			return EINVAL;
-		tv = mtod(m, struct timeval *);
-		if (tv->tv_sec > (INT_MAX - tv->tv_usec / tick) / hz)
+		error = sockopt_get(sopt, &tv, sizeof(tv));
+		if (error)
+			return (error);
+
+		if (tv.tv_sec > (INT_MAX - tv.tv_usec / tick) / hz)
 			return EDOM;
-		val = tv->tv_sec * hz + tv->tv_usec / tick;
-		if (val == 0 && tv->tv_usec != 0)
-			val = 1;
 
-		switch (optname) {
+		optval = tv.tv_sec * hz + tv.tv_usec / tick;
+		if (optval == 0 && tv.tv_usec != 0)
+			optval = 1;
 
+		switch (sopt->sopt_name) {
 		case SO_SNDTIMEO:
-			so->so_snd.sb_timeo = val;
+			so->so_snd.sb_timeo = optval;
 			break;
 		case SO_RCVTIMEO:
-			so->so_rcv.sb_timeo = val;
+			so->so_rcv.sb_timeo = optval;
 			break;
 		}
 		break;
@@ -1700,130 +1699,301 @@
 }
 
 int
-sosetopt(struct socket *so, int level, int optname, struct mbuf *m)
+sosetopt(struct socket *so, struct sockopt *sopt)
 {
 	int error, prerr;
 
 	solock(so);
-	if (level == SOL_SOCKET)
-		error = sosetopt1(so, level, optname, m);
+	if (sopt->sopt_level == SOL_SOCKET)
+		error = sosetopt1(so, sopt);
 	else
 		error = ENOPROTOOPT;
 
 	if ((error == 0 || error == ENOPROTOOPT) &&
 	    so->so_proto != NULL && so->so_proto->pr_ctloutput != NULL) {
 		/* give the protocol stack a shot */
-		prerr = (*so->so_proto->pr_ctloutput)(PRCO_SETOPT, so, level,
-		    optname, &m);
+		prerr = (*so->so_proto->pr_ctloutput)(PRCO_SETOPT, so, sopt);
 		if (prerr == 0)
 			error = 0;
 		else if (prerr != ENOPROTOOPT)
 			error = prerr;
-	} else if (m != NULL)
-		(void)m_free(m);
+	}
 	sounlock(so);
 	return error;
 }
 
+/*
+ * so_setsockopt() is a wrapper providing a sockopt structure for sosetopt()
+ */
 int
-sogetopt(struct socket *so, int level, int optname, struct mbuf **mp)
+so_setsockopt(struct lwp *l, struct socket *so, int level, int name,
+    const void *val, size_t valsize)
+{
+	struct sockopt sopt;
+	int error;
+
+	KASSERT(valsize == 0 || val != NULL);
+
+	sockopt_init(&sopt, level, name, valsize);
+	sockopt_set(&sopt, val, valsize);
+
+	error = sosetopt(so, &sopt);
+
+	sockopt_destroy(&sopt);
+
+	return error;
+}
+ 
+/*
+ * internal get SOL_SOCKET options
+ */
+static int
+sogetopt1(struct socket *so, struct sockopt *sopt)
 {
-	struct mbuf	*m;
+	int error, optval;
+	struct linger l;
+	struct timeval tv;
+
+	switch (sopt->sopt_name) {
+
+#ifdef INET
+	case SO_ACCEPTFILTER:
+		error = do_getopt_accept_filter(so, sopt);
+		break;
+#endif
+
+	case SO_LINGER:
+		l.l_onoff = (so->so_options & SO_LINGER) ? 1 : 0;
+		l.l_linger = so->so_linger;
+
+		error = sockopt_set(sopt, &l, sizeof(l));
+		break;
+
+	case SO_USELOOPBACK:
+	case SO_DONTROUTE:
+	case SO_DEBUG:
+	case SO_KEEPALIVE:
+	case SO_REUSEADDR:
+	case SO_REUSEPORT:
+	case SO_BROADCAST:
+	case SO_OOBINLINE:
+	case SO_TIMESTAMP:
+		error = sockopt_setint(sopt,
+		    (so->so_options & sopt->sopt_name) ? 1 : 0);
+		break;
+
+	case SO_TYPE:
+		error = sockopt_setint(sopt, so->so_type);
+		break;
+
+	case SO_ERROR:
+		error = sockopt_setint(sopt, so->so_error);
+		so->so_error = 0;
+		break;
+
+	case SO_SNDBUF:
+		error = sockopt_setint(sopt, so->so_snd.sb_hiwat);
+		break;
+
+	case SO_RCVBUF:
+		error = sockopt_setint(sopt, so->so_rcv.sb_hiwat);
+		break;
+
+	case SO_SNDLOWAT:
+		error = sockopt_setint(sopt, so->so_snd.sb_lowat);
+		break;
+
+	case SO_RCVLOWAT:
+		error = sockopt_setint(sopt, so->so_rcv.sb_lowat);
+		break;
+
+	case SO_SNDTIMEO:
+	case SO_RCVTIMEO:
+		optval = (sopt->sopt_name == SO_SNDTIMEO ?
+		     so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
+
+		tv.tv_sec = optval / hz;
+		tv.tv_usec = (optval % hz) * tick;
+
+		error = sockopt_set(sopt, &tv, sizeof(tv));
+		break;
+
+	case SO_OVERFLOWED:
+		error = sockopt_setint(sopt, so->so_rcv.sb_overflowed);
+		break;
+
+	default:
+		error = ENOPROTOOPT;
+		break;
+	}
+
+	return (error);
+}
+
+int
+sogetopt(struct socket *so, struct sockopt *sopt)
+{
 	int		error;
 
 	solock(so);
-	if (level != SOL_SOCKET) {
+	if (sopt->sopt_level != SOL_SOCKET) {
 		if (so->so_proto && so->so_proto->pr_ctloutput) {
 			error = ((*so->so_proto->pr_ctloutput)
-				  (PRCO_GETOPT, so, level, optname, mp));
+			    (PRCO_GETOPT, so, sopt));
 		} else
 			error = (ENOPROTOOPT);
 	} else {
-		m = m_get(M_WAIT, MT_SOOPTS);
-		m->m_len = sizeof(int);
-
-		switch (optname) {
-
-#ifdef INET
-		case SO_ACCEPTFILTER:
-			error = do_getopt_accept_filter(so, m);
-			break;
-#endif
-
-		case SO_LINGER:
-			m->m_len = sizeof(struct linger);
-			mtod(m, struct linger *)->l_onoff =
-			    (so->so_options & SO_LINGER) ? 1 : 0;
-			mtod(m, struct linger *)->l_linger = so->so_linger;
-			break;
-
-		case SO_USELOOPBACK:
-		case SO_DONTROUTE:
-		case SO_DEBUG:
-		case SO_KEEPALIVE:
-		case SO_REUSEADDR:
-		case SO_REUSEPORT:
-		case SO_BROADCAST:
-		case SO_OOBINLINE:
-		case SO_TIMESTAMP:
-			*mtod(m, int *) = (so->so_options & optname) ? 1 : 0;
-			break;
-
-		case SO_TYPE:
-			*mtod(m, int *) = so->so_type;
-			break;
-
-		case SO_ERROR:
-			*mtod(m, int *) = so->so_error;
-			so->so_error = 0;
-			break;
-
-		case SO_SNDBUF:
-			*mtod(m, int *) = so->so_snd.sb_hiwat;
-			break;
-
-		case SO_RCVBUF:
-			*mtod(m, int *) = so->so_rcv.sb_hiwat;
-			break;
-
-		case SO_SNDLOWAT:
-			*mtod(m, int *) = so->so_snd.sb_lowat;
-			break;
-
-		case SO_RCVLOWAT:
-			*mtod(m, int *) = so->so_rcv.sb_lowat;
-			break;
-
-		case SO_SNDTIMEO:
-		case SO_RCVTIMEO:
-		    {
-			int val = (optname == SO_SNDTIMEO ?
-			     so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
-
-			m->m_len = sizeof(struct timeval);
-			mtod(m, struct timeval *)->tv_sec = val / hz;
-			mtod(m, struct timeval *)->tv_usec =
-			    (val % hz) * tick;
-			break;
-		    }
-
-		case SO_OVERFLOWED:
-			*mtod(m, int *) = so->so_rcv.sb_overflowed;
-			break;
-
-		default:
-			sounlock(so);
-			(void)m_free(m);
-			return (ENOPROTOOPT);
-		}
-		*mp = m;
-		error = 0;
+		error = sogetopt1(so, sopt);
 	}
-
 	sounlock(so);
 	return (error);
 }
 
+/*
+ * alloc sockopt data buffer buffer
+ *	- will be released at destroy
+ */
+static void
+sockopt_alloc(struct sockopt *sopt, size_t len)
+{
+
+	KASSERT(sopt->sopt_size == 0);
+
+	if (len > sizeof(sopt->sopt_buf))
+		sopt->sopt_data = malloc(len, M_SOOPTS, M_WAITOK | M_ZERO);
+	else
+		sopt->sopt_data = sopt->sopt_buf;
+
+	sopt->sopt_size = len;
+}
+
+/*
+ * initialise sockopt storage
+ */
+void
+sockopt_init(struct sockopt *sopt, int level, int name, size_t size)
+{
+
+	memset(sopt, 0, sizeof(*sopt));
+
+	sopt->sopt_level = level;
+	sopt->sopt_name = name;
+	sockopt_alloc(sopt, size);
+}
+
+/*
+ * destroy sockopt storage
+ *	- will release any held memory references
+ */
+void
+sockopt_destroy(struct sockopt *sopt)
+{
+
+	if (sopt->sopt_data != sopt->sopt_buf)
+		free(sopt->sopt_data, M_SOOPTS);
+
+	memset(sopt, 0, sizeof(*sopt));
+}
+
+/*
+ * set sockopt value
+ *	- value is copied into sockopt
+ * 	- memory is allocated when necessary
+ */
+int
+sockopt_set(struct sockopt *sopt, const void *buf, size_t len)
+{
+
+	if (sopt->sopt_size == 0)
+		sockopt_alloc(sopt, len);
+
+	KASSERT(sopt->sopt_size == len);
+	memcpy(sopt->sopt_data, buf, len);
+	return 0;
+}
+
+/*
+ * common case of set sockopt integer value
+ */
+int
+sockopt_setint(struct sockopt *sopt, int val)
+{
+
+	return sockopt_set(sopt, &val, sizeof(int));
+}
+
+/*
+ * get sockopt value
+ *	- correct size must be given
+ */
+int
+sockopt_get(const struct sockopt *sopt, void *buf, size_t len)
+{
+
+	if (sopt->sopt_size != len)
+		return EINVAL;
+
+	memcpy(buf, sopt->sopt_data, len);
+	return 0;
+}
+
+/*
+ * common case of get sockopt integer value
+ */
+int
+sockopt_getint(const struct sockopt *sopt, int *valp)
+{
+
+	return sockopt_get(sopt, valp, sizeof(int));
+}
+
+/*
+ * set sockopt value from mbuf
+ *	- ONLY for legacy code
+ *	- mbuf is released by sockopt
+ */
+int
+sockopt_setmbuf(struct sockopt *sopt, struct mbuf *m)
+{
+	size_t len;
+
+	len = m_length(m);
+
+	if (sopt->sopt_size == 0)
+		sockopt_alloc(sopt, len);
+
+	KASSERT(sopt->sopt_size == len);
+	m_copydata(m, 0, len, sopt->sopt_data);
+	m_freem(m);
+
+	return 0;
+}
+
+/*
+ * get sockopt value into mbuf
+ *	- ONLY for legacy code
+ *	- mbuf to be released by the caller
+ */
+struct mbuf *
+sockopt_getmbuf(const struct sockopt *sopt)
+{
+	struct mbuf *m;
+
+	m = m_get(M_WAIT, MT_SOOPTS);
+	if (m == NULL)
+		return NULL;
+
+	m->m_len = MLEN;
+	m_copyback(m, 0, sopt->sopt_size, sopt->sopt_data);
+	if (m_length(m) != max(sopt->sopt_size, MLEN)) {
+		m_freem(m);
+		return NULL;
+	}
+	m->m_len = min(sopt->sopt_size, MLEN);
+
+	return m;
+}
+
 void
 sohasoutofband(struct socket *so)
 {
--- a/sys/kern/uipc_syscalls.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/kern/uipc_syscalls.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: uipc_syscalls.c,v 1.133 2008/06/24 11:21:46 ad Exp $	*/
+/*	$NetBSD: uipc_syscalls.c,v 1.134 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -58,7 +58,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_syscalls.c,v 1.133 2008/06/24 11:21:46 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_syscalls.c,v 1.134 2008/08/06 15:01:23 plunky Exp $");
 
 #include "opt_pipe.h"
 
@@ -887,34 +887,33 @@
 		syscallarg(const void *)	val;
 		syscallarg(unsigned int)	valsize;
 	} */
-	struct proc	*p;
-	struct mbuf	*m;
+	struct sockopt	sopt;
 	struct socket	*so;
 	int		error;
 	unsigned int	len;
 
-	p = l->l_proc;
-	m = NULL;
+	len = SCARG(uap, valsize);
+	if (len > 0 && SCARG(uap, val) == NULL)
+		return (EINVAL);
+
+	if (len > MCLBYTES)
+		return (EINVAL);
+
 	if ((error = fd_getsock(SCARG(uap, s), &so)) != 0)
 		return (error);
-	len = SCARG(uap, valsize);
-	if (len > MCLBYTES) {
-		error = EINVAL;
-		goto out;
+
+	sockopt_init(&sopt, SCARG(uap, level), SCARG(uap, name), len);
+
+	if (len > 0) {
+		error = copyin(SCARG(uap, val), sopt.sopt_data, len);
+		if (error)
+			goto out;
 	}
-	if (SCARG(uap, val)) {
-		m = getsombuf(so, MT_SOOPTS);
-		if (len > MLEN)
-			m_clget(m, M_WAIT);
-		error = copyin(SCARG(uap, val), mtod(m, void *), len);
-		if (error) {
-			(void) m_free(m);
-			goto out;
-		}
-		m->m_len = SCARG(uap, valsize);
-	}
-	error = sosetopt(so, SCARG(uap, level), SCARG(uap, name), m);
+
+	error = sosetopt(so, &sopt);
+
  out:
+	sockopt_destroy(&sopt);
  	fd_putfile(SCARG(uap, s));
 	return (error);
 }
@@ -930,40 +929,40 @@
 		syscallarg(void *)		val;
 		syscallarg(unsigned int *)	avalsize;
 	} */
+	struct sockopt	sopt;
 	struct socket	*so;
-	struct mbuf	*m;
-	unsigned int	op, i, valsize;
+	unsigned int	valsize, len;
 	int		error;
-	char *val = SCARG(uap, val);
 
-	m = NULL;
-	if ((error = fd_getsock(SCARG(uap, s), &so)) != 0)
-		return (error);
-	if (val != NULL) {
-		error = copyin(SCARG(uap, avalsize),
-			       &valsize, sizeof(valsize));
+	if (SCARG(uap, val) != NULL) {
+		error = copyin(SCARG(uap, avalsize), &valsize, sizeof(valsize));
 		if (error)
-			goto out;
+			return (error);
 	} else
 		valsize = 0;
-	error = sogetopt(so, SCARG(uap, level), SCARG(uap, name), &m);
-	if (error == 0 && val != NULL && valsize && m != NULL) {
-		op = 0;
-		while (m && !error && op < valsize) {
-			i = min(m->m_len, (valsize - op));
-			error = copyout(mtod(m, void *), val, i);
-			op += i;
-			val += i;
-			m = m_free(m);
-		}
-		valsize = op;
-		if (error == 0)
-			error = copyout(&valsize,
-					SCARG(uap, avalsize), sizeof(valsize));
+
+	if ((error = fd_getsock(SCARG(uap, s), &so)) != 0)
+		return (error);
+
+	sockopt_init(&sopt, SCARG(uap, level), SCARG(uap, name), 0);
+
+	error = sogetopt(so, &sopt);
+	if (error)
+		goto out;
+
+	if (valsize > 0) {
+		len = min(valsize, sopt.sopt_size);
+		error = copyout(sopt.sopt_data, SCARG(uap, val), len);
+		if (error)
+			goto out;
+
+		error = copyout(&len, SCARG(uap, avalsize), sizeof(len));
+		if (error)
+			goto out;
 	}
-	if (m != NULL)
-		(void) m_freem(m);
+
  out:
+	sockopt_destroy(&sopt);
  	fd_putfile(SCARG(uap, s));
 	return (error);
 }
--- a/sys/kern/uipc_usrreq.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/kern/uipc_usrreq.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: uipc_usrreq.c,v 1.117 2008/06/20 15:27:50 christos Exp $	*/
+/*	$NetBSD: uipc_usrreq.c,v 1.118 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2004, 2008 The NetBSD Foundation, Inc.
@@ -96,7 +96,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_usrreq.c,v 1.117 2008/06/20 15:27:50 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_usrreq.c,v 1.118 2008/08/06 15:01:23 plunky Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -639,43 +639,37 @@
  * Unix domain socket option processing.
  */
 int
-uipc_ctloutput(int op, struct socket *so, int level, int optname,
-	struct mbuf **mp)
+uipc_ctloutput(int op, struct socket *so, struct sockopt *sopt)
 {
 	struct unpcb *unp = sotounpcb(so);
-	struct mbuf *m = *mp;
 	int optval = 0, error = 0;
 
 	KASSERT(solocked(so));
 
-	if (level != 0) {
+	if (sopt->sopt_level != 0) {
 		error = ENOPROTOOPT;
-		if (op == PRCO_SETOPT && m)
-			(void) m_free(m);
 	} else switch (op) {
 
 	case PRCO_SETOPT:
-		switch (optname) {
+		switch (sopt->sopt_name) {
 		case LOCAL_CREDS:
 		case LOCAL_CONNWAIT:
-			if (m == NULL || m->m_len != sizeof(int))
-				error = EINVAL;
-			else {
-				optval = *mtod(m, int *);
-				switch (optname) {
+			error = sockopt_getint(sopt, &optval);
+			if (error)
+				break;
+			switch (sopt->sopt_name) {
 #define	OPTSET(bit) \
 	if (optval) \
 		unp->unp_flags |= (bit); \
 	else \
 		unp->unp_flags &= ~(bit);
 
-				case LOCAL_CREDS:
-					OPTSET(UNP_WANTCRED);
-					break;
-				case LOCAL_CONNWAIT:
-					OPTSET(UNP_CONNWAIT);
-					break;
-				}
+			case LOCAL_CREDS:
+				OPTSET(UNP_WANTCRED);
+				break;
+			case LOCAL_CONNWAIT:
+				OPTSET(UNP_CONNWAIT);
+				break;
 			}
 			break;
 #undef OPTSET
@@ -684,30 +678,24 @@
 			error = ENOPROTOOPT;
 			break;
 		}
-		if (m)
-			(void) m_free(m);
 		break;
 
 	case PRCO_GETOPT:
 		sounlock(so);
-		switch (optname) {
+		switch (sopt->sopt_name) {
 		case LOCAL_PEEREID:
 			if (unp->unp_flags & UNP_EIDSVALID) {
-				*mp = m = m_get(M_WAIT, MT_SOOPTS);
-				m->m_len = sizeof(struct unpcbid);
-				*mtod(m, struct unpcbid *) = unp->unp_connid;
+				error = sockopt_set(sopt,
+				    &unp->unp_connid, sizeof(unp->unp_connid));
 			} else {
 				error = EINVAL;
 			}
 			break;
 		case LOCAL_CREDS:
-			*mp = m = m_get(M_WAIT, MT_SOOPTS);
-			m->m_len = sizeof(int);
-
 #define	OPTBIT(bit)	(unp->unp_flags & (bit) ? 1 : 0)
 
 			optval = OPTBIT(UNP_WANTCRED);
-			*mtod(m, int *) = optval;
+			error = sockopt_setint(sopt, optval);
 			break;
 #undef OPTBIT
 
--- a/sys/net/if_gre.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/net/if_gre.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_gre.c,v 1.137 2008/06/24 11:18:14 ad Exp $ */
+/*	$NetBSD: if_gre.c,v 1.138 2008/08/06 15:01:23 plunky Exp $ */
 
 /*
  * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
@@ -45,7 +45,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_gre.c,v 1.137 2008/06/24 11:18:14 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_gre.c,v 1.138 2008/08/06 15:01:23 plunky Exp $");
 
 #include "opt_gre.h"
 #include "opt_inet.h"
@@ -482,6 +482,7 @@
 	struct sockaddr *sa;
 	struct socket *so;
 	sa_family_t af;
+	int val;
 
 	GRE_DPRINTF(sc, "enter\n");
 
@@ -519,20 +520,22 @@
 	}
 	sounlock(so);
 
+	m = NULL;
+
 	/* XXX convert to a (new) SOL_SOCKET call */
-	*mtod(m, int *) = ip_gre_ttl;
-	m->m_len = sizeof(int);
-	pr = so->so_proto;
-	KASSERT(pr != NULL);
-	rc = sosetopt(so, IPPROTO_IP, IP_TTL, m);
-	m = NULL;
-	if (rc != 0) {
-		GRE_DPRINTF(sc, "sosetopt ttl failed\n");
-		rc = 0;
-	}
-	rc = sosetopt(so, SOL_SOCKET, SO_NOHEADER, m_intopt(so, 1));
-	if (rc != 0) {
-		GRE_DPRINTF(sc, "sosetopt SO_NOHEADER failed\n");
+  	pr = so->so_proto;
+  	KASSERT(pr != NULL);
+ 	rc = so_setsockopt(curlwp, so, IPPROTO_IP, IP_TTL,
+	    &ip_gre_ttl, sizeof(ip_gre_ttl));
+  	if (rc != 0) {
+ 		GRE_DPRINTF(sc, "so_setsockopt ttl failed\n");
+  		rc = 0;
+  	}
+ 	val = 1;
+ 	rc = so_setsockopt(curlwp, so, SOL_SOCKET, SO_NOHEADER,
+	    &val, sizeof(val));
+  	if (rc != 0) {
+ 		GRE_DPRINTF(sc, "so_setsockopt SO_NOHEADER failed\n");
 		rc = 0;
 	}
 out:
--- a/sys/netbt/hci.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netbt/hci.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: hci.h,v 1.26 2008/04/24 11:38:37 ad Exp $	*/
+/*	$NetBSD: hci.h,v 1.27 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -54,7 +54,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: hci.h,v 1.26 2008/04/24 11:38:37 ad Exp $
+ * $Id: hci.h,v 1.27 2008/08/06 15:01:24 plunky Exp $
  * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_hci.h,v 1.6 2005/01/07 01:45:43 imp Exp $
  */
 
@@ -2367,6 +2367,7 @@
 struct mbuf;
 struct sco_pcb;
 struct socket;
+struct sockopt;
 
 /* global HCI kernel variables */
 
@@ -2543,7 +2544,7 @@
 /* hci_socket.c */
 void hci_drop(void *);
 int hci_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct lwp *);
-int hci_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int hci_ctloutput(int, struct socket *, struct sockopt *);
 void hci_mtap(struct mbuf *, struct hci_unit *);
 
 /* hci_unit.c */
--- a/sys/netbt/hci_socket.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netbt/hci_socket.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: hci_socket.c,v 1.16 2008/04/29 18:41:06 ad Exp $	*/
+/*	$NetBSD: hci_socket.c,v 1.17 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hci_socket.c,v 1.16 2008/04/29 18:41:06 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hci_socket.c,v 1.17 2008/08/06 15:01:24 plunky Exp $");
 
 /* load symbolic names */
 #ifdef BLUETOOTH_DEBUG
@@ -751,67 +751,66 @@
  * get/set socket options
  */
 int
-hci_ctloutput(int req, struct socket *so, int level,
-		int optname, struct mbuf **opt)
+hci_ctloutput(int req, struct socket *so, struct sockopt *sopt)
 {
 	struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
-	struct mbuf *m;
-	int err = 0;
+	int optval, err = 0;
 
 	DPRINTFN(2, "req %s\n", prcorequests[req]);
 
 	if (pcb == NULL)
 		return EINVAL;
 
-	if (level != BTPROTO_HCI)
+	if (sopt->sopt_level != BTPROTO_HCI)
 		return ENOPROTOOPT;
 
 	switch(req) {
 	case PRCO_GETOPT:
-		m = m_get(M_WAIT, MT_SOOPTS);
-		switch (optname) {
+		switch (sopt->sopt_name) {
 		case SO_HCI_EVT_FILTER:
-			m->m_len = sizeof(struct hci_filter);
-			memcpy(mtod(m, void *), &pcb->hp_efilter, m->m_len);
+			err = sockopt_set(sopt, &pcb->hp_efilter,
+			    sizeof(struct hci_filter));
+
 			break;
 
 		case SO_HCI_PKT_FILTER:
-			m->m_len = sizeof(struct hci_filter);
-			memcpy(mtod(m, void *), &pcb->hp_pfilter, m->m_len);
+			err = sockopt_set(sopt, &pcb->hp_pfilter,
+			    sizeof(struct hci_filter));
+
 			break;
 
 		case SO_HCI_DIRECTION:
-			m->m_len = sizeof(int);
-			if (pcb->hp_flags & HCI_DIRECTION)
-				*mtod(m, int *) = 1;
-			else
-				*mtod(m, int *) = 0;
+			err = sockopt_setint(sopt,
+			    (pcb->hp_flags & HCI_DIRECTION ? 1 : 0));
+
 			break;
 
 		default:
 			err = ENOPROTOOPT;
-			m_freem(m);
-			m = NULL;
 			break;
 		}
-		*opt = m;
 		break;
 
 	case PRCO_SETOPT:
-		m = *opt;
-		if (m) switch (optname) {
+		switch (sopt->sopt_name) {
 		case SO_HCI_EVT_FILTER:	/* set event filter */
-			m->m_len = min(m->m_len, sizeof(struct hci_filter));
-			memcpy(&pcb->hp_efilter, mtod(m, void *), m->m_len);
+			err = sockopt_get(sopt, &pcb->hp_efilter,
+			    sizeof(pcb->hp_efilter));
+
 			break;
 
 		case SO_HCI_PKT_FILTER:	/* set packet filter */
-			m->m_len = min(m->m_len, sizeof(struct hci_filter));
-			memcpy(&pcb->hp_pfilter, mtod(m, void *), m->m_len);
+			err = sockopt_get(sopt, &pcb->hp_pfilter,
+			    sizeof(pcb->hp_pfilter));
+
 			break;
 
 		case SO_HCI_DIRECTION:	/* request direction ctl messages */
-			if (*mtod(m, int *))
+			err = sockopt_getint(sopt, &optval);
+			if (err)
+				break;
+
+			if (optval)
 				pcb->hp_flags |= HCI_DIRECTION;
 			else
 				pcb->hp_flags &= ~HCI_DIRECTION;
@@ -821,7 +820,6 @@
 			err = ENOPROTOOPT;
 			break;
 		}
-		m_freem(m);
 		break;
 
 	default:
--- a/sys/netbt/l2cap.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netbt/l2cap.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: l2cap.h,v 1.6 2007/11/03 17:20:17 plunky Exp $	*/
+/*	$NetBSD: l2cap.h,v 1.7 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -54,7 +54,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: l2cap.h,v 1.6 2007/11/03 17:20:17 plunky Exp $
+ * $Id: l2cap.h,v 1.7 2008/08/06 15:01:24 plunky Exp $
  * $FreeBSD: src/sys/netgraph/bluetooth/include/l2cap.h,v 1.4 2005/08/31 18:13:23 emax Exp $
  */
 
@@ -439,6 +439,7 @@
  */
 
 struct socket;
+struct sockopt;
 struct mbuf;
 
 /* l2cap_lower.c */
@@ -464,7 +465,7 @@
 
 /* l2cap_socket.c */
 int l2cap_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct lwp *);
-int l2cap_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int l2cap_ctloutput(int, struct socket *, struct sockopt *);
 
 /* l2cap_upper.c */
 int l2cap_attach(struct l2cap_channel **, const struct btproto *, void *);
@@ -476,8 +477,8 @@
 int l2cap_detach(struct l2cap_channel **);
 int l2cap_listen(struct l2cap_channel *);
 int l2cap_send(struct l2cap_channel *, struct mbuf *);
-int l2cap_setopt(struct l2cap_channel *, int, void *);
-int l2cap_getopt(struct l2cap_channel *, int, void *);
+int l2cap_setopt(struct l2cap_channel *, const struct sockopt *);
+int l2cap_getopt(struct l2cap_channel *, struct sockopt *);
 
 #endif	/* _KERNEL */
 
--- a/sys/netbt/l2cap_socket.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netbt/l2cap_socket.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: l2cap_socket.c,v 1.8 2008/04/24 11:38:37 ad Exp $	*/
+/*	$NetBSD: l2cap_socket.c,v 1.9 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: l2cap_socket.c,v 1.8 2008/04/24 11:38:37 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: l2cap_socket.c,v 1.9 2008/08/06 15:01:24 plunky Exp $");
 
 /* load symbolic names */
 #ifdef BLUETOOTH_DEBUG
@@ -258,17 +258,15 @@
 }
 
 /*
- * l2cap_ctloutput(request, socket, level, optname, opt)
+ * l2cap_ctloutput(req, socket, sockopt)
  *
  *	Apply configuration commands to channel. This corresponds to
  *	"Reconfigure Channel Request" in the L2CAP specification.
  */
 int
-l2cap_ctloutput(int req, struct socket *so, int level,
-		int optname, struct mbuf **opt)
+l2cap_ctloutput(int req, struct socket *so, struct sockopt *sopt)
 {
 	struct l2cap_channel *pcb = so->so_pcb;
-	struct mbuf *m;
 	int err = 0;
 
 	DPRINTFN(2, "%s\n", prcorequests[req]);
@@ -276,26 +274,16 @@
 	if (pcb == NULL)
 		return EINVAL;
 
-	if (level != BTPROTO_L2CAP)
+	if (sopt->sopt_level != BTPROTO_L2CAP)
 		return ENOPROTOOPT;
 
 	switch(req) {
 	case PRCO_GETOPT:
-		m = m_get(M_WAIT, MT_SOOPTS);
-		m->m_len = l2cap_getopt(pcb, optname, mtod(m, void *));
-		if (m->m_len == 0) {
-			m_freem(m);
-			m = NULL;
-			err = ENOPROTOOPT;
-		}
-		*opt = m;
+		err = l2cap_getopt(pcb, sopt);
 		break;
 
 	case PRCO_SETOPT:
-		m = *opt;
-		KASSERT(m != NULL);
-		err = l2cap_setopt(pcb, optname, mtod(m, void *));
-		m_freem(m);
+		err = l2cap_setopt(pcb, sopt);
 		break;
 
 	default:
@@ -372,6 +360,7 @@
 l2cap_linkmode(void *arg, int new)
 {
 	struct socket *so = arg;
+	struct sockopt sopt;
 	int mode;
 
 	DPRINTF("auth %s, encrypt %s, secure %s\n",
@@ -379,7 +368,11 @@
 		(new & L2CAP_LM_ENCRYPT ? "on" : "off"),
 		(new & L2CAP_LM_SECURE ? "on" : "off"));
 
-	(void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode);
+	sockopt_init(&sopt, BTPROTO_L2CAP, SO_L2CAP_LM, 0);
+	(void)l2cap_getopt(so->so_pcb, &sopt);
+	(void)sockopt_getint(&sopt, &mode);
+	sockopt_destroy(&sopt);
+
 	if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
 	    || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
 	    || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
--- a/sys/netbt/l2cap_upper.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netbt/l2cap_upper.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: l2cap_upper.c,v 1.8 2007/04/29 20:23:36 msaitoh Exp $	*/
+/*	$NetBSD: l2cap_upper.c,v 1.9 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.8 2007/04/29 20:23:36 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.9 2008/08/06 15:01:24 plunky Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -407,7 +407,7 @@
 }
 
 /*
- * l2cap_setopt(l2cap_channel, opt, addr)
+ * l2cap_setopt(l2cap_channel, sopt)
  *
  *	Apply configuration options to channel. This corresponds to
  *	"Configure Channel Request" in the L2CAP specification.
@@ -420,14 +420,17 @@
  *	will be made when the change is complete.
  */
 int
-l2cap_setopt(struct l2cap_channel *chan, int opt, void *addr)
+l2cap_setopt(struct l2cap_channel *chan, const struct sockopt *sopt)
 {
 	int mode, err = 0;
 	uint16_t mtu;
 
-	switch (opt) {
+	switch (sopt->sopt_name) {
 	case SO_L2CAP_IMTU:	/* set Incoming MTU */
-		mtu = *(uint16_t *)addr;
+		err = sockopt_get(sopt, &mtu, sizeof(mtu));
+		if (err)
+			break;
+
 		if (mtu < L2CAP_MTU_MINIMUM)
 			err = EINVAL;
 		else if (chan->lc_state == L2CAP_CLOSED)
@@ -438,7 +441,10 @@
 		break;
 
 	case SO_L2CAP_LM:	/* set link mode */
-		mode = *(int *)addr;
+		err = sockopt_getint(sopt, &mode);
+		if (err)
+			break;
+
 		mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH);
 
 		if (mode & L2CAP_LM_SECURE)
@@ -465,42 +471,36 @@
 }
 
 /*
- * l2cap_getopt(l2cap_channel, opt, addr)
+ * l2cap_getopt(l2cap_channel, sopt)
  *
  *	Return configuration parameters.
  */
 int
-l2cap_getopt(struct l2cap_channel *chan, int opt, void *addr)
+l2cap_getopt(struct l2cap_channel *chan, struct sockopt *sopt)
 {
 
-	switch (opt) {
+	switch (sopt->sopt_name) {
 	case SO_L2CAP_IMTU:	/* get Incoming MTU */
-		*(uint16_t *)addr = chan->lc_imtu;
-		return sizeof(uint16_t);
+		return sockopt_set(sopt, &chan->lc_imtu, sizeof(uint16_t));
 
 	case SO_L2CAP_OMTU:	/* get Outgoing MTU */
-		*(uint16_t *)addr = chan->lc_omtu;
-		return sizeof(uint16_t);
+		return sockopt_set(sopt, &chan->lc_omtu, sizeof(uint16_t));
 
 	case SO_L2CAP_IQOS:	/* get Incoming QoS flow spec */
-		memcpy(addr, &chan->lc_iqos, sizeof(l2cap_qos_t));
-		return sizeof(l2cap_qos_t);
+		return sockopt_set(sopt, &chan->lc_iqos, sizeof(l2cap_qos_t));
 
 	case SO_L2CAP_OQOS:	/* get Outgoing QoS flow spec */
-		memcpy(addr, &chan->lc_oqos, sizeof(l2cap_qos_t));
-		return sizeof(l2cap_qos_t);
+		return sockopt_set(sopt, &chan->lc_oqos, sizeof(l2cap_qos_t));
 
 	case SO_L2CAP_FLUSH:	/* get Flush Timeout */
-		*(uint16_t *)addr = chan->lc_flush;
-		return sizeof(uint16_t);
+		return sockopt_set(sopt, &chan->lc_flush, sizeof(uint16_t));
 
 	case SO_L2CAP_LM:	/* get link mode */
-		*(int *)addr = chan->lc_mode;
-		return sizeof(int);
+		return sockopt_setint(sopt, chan->lc_mode);
 
 	default:
 		break;
 	}
 
-	return 0;
+	return ENOPROTOOPT;
 }
--- a/sys/netbt/rfcomm.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netbt/rfcomm.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: rfcomm.h,v 1.6 2007/11/20 20:25:58 plunky Exp $	*/
+/*	$NetBSD: rfcomm.h,v 1.7 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -55,7 +55,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: rfcomm.h,v 1.6 2007/11/20 20:25:58 plunky Exp $
+ * $Id: rfcomm.h,v 1.7 2008/08/06 15:01:24 plunky Exp $
  * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h,v 1.4 2005/01/11 01:39:53 emax Exp $
  */
 
@@ -382,6 +382,7 @@
  */
 
 struct socket;
+struct sockopt;
 
 /* rfcomm_dlc.c */
 struct rfcomm_dlc *rfcomm_dlc_lookup(struct rfcomm_session *, int);
@@ -403,7 +404,7 @@
 
 /* rfcomm_socket.c */
 int rfcomm_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct lwp *);
-int rfcomm_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int rfcomm_ctloutput(int, struct socket *, struct sockopt *);
 
 /* rfcomm_upper.c */
 int rfcomm_attach(struct rfcomm_dlc **, const struct btproto *, void *);
@@ -416,8 +417,8 @@
 int rfcomm_listen(struct rfcomm_dlc *);
 int rfcomm_send(struct rfcomm_dlc *, struct mbuf *);
 int rfcomm_rcvd(struct rfcomm_dlc *, size_t);
-int rfcomm_setopt(struct rfcomm_dlc *, int, void *);
-int rfcomm_getopt(struct rfcomm_dlc *, int, void *);
+int rfcomm_setopt(struct rfcomm_dlc *, const struct sockopt *);
+int rfcomm_getopt(struct rfcomm_dlc *, struct sockopt *);
 
 #endif /* _KERNEL */
 
--- a/sys/netbt/rfcomm_dlc.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netbt/rfcomm_dlc.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: rfcomm_dlc.c,v 1.5 2008/04/24 11:38:37 ad Exp $	*/
+/*	$NetBSD: rfcomm_dlc.c,v 1.6 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -32,12 +32,13 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rfcomm_dlc.c,v 1.5 2008/04/24 11:38:37 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rfcomm_dlc.c,v 1.6 2008/08/06 15:01:24 plunky Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/mbuf.h>
 #include <sys/proc.h>
+#include <sys/socketvar.h>
 #include <sys/systm.h>
 
 #include <netbt/bluetooth.h>
@@ -219,7 +220,8 @@
 int
 rfcomm_dlc_setmode(struct rfcomm_dlc *dlc)
 {
-	int mode = 0;
+	struct sockopt sopt;
+	int mode = 0, err;
 
 	KASSERT(dlc->rd_session != NULL);
 	KASSERT(dlc->rd_session->rs_state == RFCOMM_SESSION_OPEN);
@@ -238,7 +240,12 @@
 	if (dlc->rd_mode & RFCOMM_LM_SECURE)
 		mode |= L2CAP_LM_SECURE;
 
-	return l2cap_setopt(dlc->rd_session->rs_l2cap, SO_L2CAP_LM, &mode);
+	sockopt_init(&sopt, BTPROTO_L2CAP, SO_L2CAP_LM, 0);
+	sockopt_setint(&sopt, mode);
+	err = l2cap_setopt(dlc->rd_session->rs_l2cap, &sopt);
+	sockopt_destroy(&sopt);
+
+	return err;
 }
 
 /*
--- a/sys/netbt/rfcomm_session.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netbt/rfcomm_session.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: rfcomm_session.c,v 1.13 2008/04/24 11:38:37 ad Exp $	*/
+/*	$NetBSD: rfcomm_session.c,v 1.14 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -32,12 +32,13 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rfcomm_session.c,v 1.13 2008/04/24 11:38:37 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rfcomm_session.c,v 1.14 2008/08/06 15:01:24 plunky Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/mbuf.h>
 #include <sys/proc.h>
+#include <sys/socketvar.h>
 #include <sys/systm.h>
 #include <sys/types.h>
 
@@ -162,6 +163,7 @@
 			struct sockaddr_bt *laddr)
 {
 	struct rfcomm_session *rs;
+	struct sockopt sopt;
 	int err;
 
 	rs = malloc(sizeof(*rs), M_BLUETOOTH, M_NOWAIT | M_ZERO);
@@ -182,7 +184,10 @@
 		return NULL;
 	}
 
-	(void)l2cap_getopt(rs->rs_l2cap, SO_L2CAP_OMTU, &rs->rs_mtu);
+	sockopt_init(&sopt, BTPROTO_L2CAP, SO_L2CAP_OMTU, 0);
+	(void)l2cap_getopt(rs->rs_l2cap, &sopt);
+	(void)sockopt_get(&sopt, &rs->rs_mtu, sizeof(rs->rs_mtu));
+	sockopt_destroy(&sopt);
 
 	if (laddr->bt_psm == L2CAP_PSM_ANY)
 		laddr->bt_psm = L2CAP_PSM_RFCOMM;
@@ -334,6 +339,7 @@
 rfcomm_session_connected(void *arg)
 {
 	struct rfcomm_session *rs = arg;
+	struct sockopt sopt;
 
 	DPRINTF("Connected\n");
 
@@ -346,7 +352,10 @@
 	 * We must take note of the L2CAP MTU because currently
 	 * the L2CAP implementation can only do Basic Mode.
 	 */
-	l2cap_getopt(rs->rs_l2cap, SO_L2CAP_OMTU, &rs->rs_mtu);
+	sockopt_init(&sopt, BTPROTO_L2CAP, SO_L2CAP_OMTU, 0);
+	(void)l2cap_getopt(rs->rs_l2cap, &sopt);
+	(void)sockopt_get(&sopt, &rs->rs_mtu, sizeof(rs->rs_mtu));
+	sockopt_destroy(&sopt);
 
 	rs->rs_mtu -= 6; /* (RFCOMM overhead could be this big) */
 	if (rs->rs_mtu < RFCOMM_MTU_MIN) {
--- a/sys/netbt/rfcomm_socket.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netbt/rfcomm_socket.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: rfcomm_socket.c,v 1.9 2008/04/24 11:38:37 ad Exp $	*/
+/*	$NetBSD: rfcomm_socket.c,v 1.10 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rfcomm_socket.c,v 1.9 2008/04/24 11:38:37 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rfcomm_socket.c,v 1.10 2008/08/06 15:01:24 plunky Exp $");
 
 /* load symbolic names */
 #ifdef BLUETOOTH_DEBUG
@@ -261,15 +261,13 @@
 }
 
 /*
- * rfcomm_ctloutput(request, socket, level, optname, opt)
+ * rfcomm_ctloutput(req, socket, sockopt)
  *
  */
 int
-rfcomm_ctloutput(int req, struct socket *so, int level,
-		int optname, struct mbuf **opt)
+rfcomm_ctloutput(int req, struct socket *so, struct sockopt *sopt)
 {
 	struct rfcomm_dlc *pcb = so->so_pcb;
-	struct mbuf *m;
 	int err = 0;
 
 	DPRINTFN(2, "%s\n", prcorequests[req]);
@@ -277,26 +275,16 @@
 	if (pcb == NULL)
 		return EINVAL;
 
-	if (level != BTPROTO_RFCOMM)
+	if (sopt->sopt_level != BTPROTO_RFCOMM)
 		return ENOPROTOOPT;
 
 	switch(req) {
 	case PRCO_GETOPT:
-		m = m_get(M_WAIT, MT_SOOPTS);
-		m->m_len = rfcomm_getopt(pcb, optname, mtod(m, void *));
-		if (m->m_len == 0) {
-			m_freem(m);
-			m = NULL;
-			err = ENOPROTOOPT;
-		}
-		*opt = m;
+		err = rfcomm_getopt(pcb, sopt);
 		break;
 
 	case PRCO_SETOPT:
-		m = *opt;
-		KASSERT(m != NULL);
-		err = rfcomm_setopt(pcb, optname, mtod(m, void *));
-		m_freem(m);
+		err = rfcomm_setopt(pcb, sopt);
 		break;
 
 	default:
@@ -382,6 +370,7 @@
 rfcomm_linkmode(void *arg, int new)
 {
 	struct socket *so = arg;
+	struct sockopt sopt;
 	int mode;
 
 	DPRINTF("auth %s, encrypt %s, secure %s\n",
@@ -389,7 +378,11 @@
 		(new & RFCOMM_LM_ENCRYPT ? "on" : "off"),
 		(new & RFCOMM_LM_SECURE ? "on" : "off"));
 
-	(void)rfcomm_getopt(so->so_pcb, SO_RFCOMM_LM, &mode);
+	sockopt_init(&sopt, BTPROTO_RFCOMM, SO_RFCOMM_LM, 0);
+	(void)rfcomm_getopt(so->so_pcb, &sopt);
+	(void)sockopt_getint(&sopt, &mode);
+	sockopt_destroy(&sopt);
+
 	if (((mode & RFCOMM_LM_AUTH) && !(new & RFCOMM_LM_AUTH))
 	    || ((mode & RFCOMM_LM_ENCRYPT) && !(new & RFCOMM_LM_ENCRYPT))
 	    || ((mode & RFCOMM_LM_SECURE) && !(new & RFCOMM_LM_SECURE)))
--- a/sys/netbt/rfcomm_upper.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netbt/rfcomm_upper.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: rfcomm_upper.c,v 1.10 2007/11/20 20:25:57 plunky Exp $	*/
+/*	$NetBSD: rfcomm_upper.c,v 1.11 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -32,12 +32,13 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rfcomm_upper.c,v 1.10 2007/11/20 20:25:57 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rfcomm_upper.c,v 1.11 2008/08/06 15:01:24 plunky Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/mbuf.h>
 #include <sys/proc.h>
+#include <sys/socketvar.h>
 #include <sys/systm.h>
 
 #include <netbt/bluetooth.h>
@@ -434,19 +435,22 @@
 }
 
 /*
- * rfcomm_setopt(dlc, option, addr)
+ * rfcomm_setopt(dlc, sopt)
  *
  * set DLC options
  */
 int
-rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, void *addr)
+rfcomm_setopt(struct rfcomm_dlc *dlc, const struct sockopt *sopt)
 {
 	int mode, err = 0;
 	uint16_t mtu;
 
-	switch (opt) {
+	switch (sopt->sopt_name) {
 	case SO_RFCOMM_MTU:
-		mtu = *(uint16_t *)addr;
+		err = sockopt_get(sopt, &mtu, sizeof(mtu));
+		if (err)
+			break;
+
 		if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
 			err = EINVAL;
 		else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
@@ -457,7 +461,10 @@
 		break;
 
 	case SO_RFCOMM_LM:
-		mode = *(int *)addr;
+		err = sockopt_getint(sopt, &mode);
+		if (err)
+			break;
+
 		mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
 
 		if (mode & RFCOMM_LM_SECURE)
@@ -481,40 +488,37 @@
 }
 
 /*
- * rfcomm_getopt(dlc, option, addr)
+ * rfcomm_getopt(dlc, sopt)
  *
  * get DLC options
  */
 int
-rfcomm_getopt(struct rfcomm_dlc *dlc, int opt, void *addr)
+rfcomm_getopt(struct rfcomm_dlc *dlc, struct sockopt *sopt)
 {
-	struct rfcomm_fc_info *fc;
+	struct rfcomm_fc_info fc;
 
-	switch (opt) {
+	switch (sopt->sopt_name) {
 	case SO_RFCOMM_MTU:
-		*(uint16_t *)addr = dlc->rd_mtu;
-		return sizeof(uint16_t);
+		return sockopt_set(sopt, &dlc->rd_mtu, sizeof(uint16_t));
 
 	case SO_RFCOMM_FC_INFO:
-		fc = addr;
-		memset(fc, 0, sizeof(*fc));
-		fc->lmodem = dlc->rd_lmodem;
-		fc->rmodem = dlc->rd_rmodem;
-		fc->tx_cred = max(dlc->rd_txcred, 0xff);
-		fc->rx_cred = max(dlc->rd_rxcred, 0xff);
+		memset(&fc, 0, sizeof(fc));
+		fc.lmodem = dlc->rd_lmodem;
+		fc.rmodem = dlc->rd_rmodem;
+		fc.tx_cred = max(dlc->rd_txcred, 0xff);
+		fc.rx_cred = max(dlc->rd_rxcred, 0xff);
 		if (dlc->rd_session
 		    && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
-			fc->cfc = 1;
+			fc.cfc = 1;
 
-		return sizeof(*fc);
+		return sockopt_set(sopt, &fc, sizeof(fc));
 
 	case SO_RFCOMM_LM:
-		*(int *)addr = dlc->rd_mode;
-		return sizeof(int);
+		return sockopt_setint(sopt, dlc->rd_mode);
 
 	default:
 		break;
 	}
 
-	return 0;
+	return ENOPROTOOPT;
 }
--- a/sys/netbt/sco.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netbt/sco.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: sco.h,v 1.2 2006/07/26 10:20:56 tron Exp $	*/
+/*	$NetBSD: sco.h,v 1.3 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -59,13 +59,15 @@
 /* sp_flags */
 #define SP_LISTENING		(1<<0)		/* is listening pcb */
 
+struct socket;
+struct sockopt;
+
 /* sco_socket.c */
-struct socket;
 extern int sco_sendspace;
 extern int sco_recvspace;
 int sco_usrreq(struct socket *, int, struct mbuf *,
 		struct mbuf *, struct mbuf *, struct lwp *);
-int sco_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int sco_ctloutput(int, struct socket *, struct sockopt *);
 
 /* sco_upper.c */
 int sco_attach(struct sco_pcb **, const struct btproto *, void *);
@@ -77,8 +79,8 @@
 int sco_detach(struct sco_pcb **);
 int sco_listen(struct sco_pcb *);
 int sco_send(struct sco_pcb *, struct mbuf *);
-int sco_setopt(struct sco_pcb *, int, void *);
-int sco_getopt(struct sco_pcb *, int, void *);
+int sco_setopt(struct sco_pcb *, const struct sockopt *);
+int sco_getopt(struct sco_pcb *, struct sockopt *);
 
 #endif	/* _KERNEL */
 
--- a/sys/netbt/sco_socket.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netbt/sco_socket.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: sco_socket.c,v 1.10 2008/04/24 11:38:37 ad Exp $	*/
+/*	$NetBSD: sco_socket.c,v 1.11 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sco_socket.c,v 1.10 2008/04/24 11:38:37 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sco_socket.c,v 1.11 2008/08/06 15:01:24 plunky Exp $");
 
 /* load symbolic names */
 #ifdef BLUETOOTH_DEBUG
@@ -251,11 +251,9 @@
  * get/set socket options
  */
 int
-sco_ctloutput(int req, struct socket *so, int level,
-		int optname, struct mbuf **opt)
+sco_ctloutput(int req, struct socket *so, struct sockopt *sopt)
 {
 	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
-	struct mbuf *m;
 	int err = 0;
 
 	DPRINTFN(2, "req %s\n", prcorequests[req]);
@@ -263,26 +261,16 @@
 	if (pcb == NULL)
 		return EINVAL;
 
-	if (level != BTPROTO_SCO)
+	if (sopt->sopt_level != BTPROTO_SCO)
 		return ENOPROTOOPT;
 
 	switch(req) {
 	case PRCO_GETOPT:
-		m = m_get(M_WAIT, MT_SOOPTS);
-		m->m_len = sco_getopt(pcb, optname, mtod(m, uint8_t *));
-		if (m->m_len == 0) {
-			m_freem(m);
-			m = NULL;
-			err = ENOPROTOOPT;
-		}
-		*opt = m;
+		err = sco_getopt(pcb, sopt);
 		break;
 
 	case PRCO_SETOPT:
-		m = *opt;
-		KASSERT(m != NULL);
-		err = sco_setopt(pcb, optname, mtod(m, uint8_t *));
-		m_freem(m);
+		err = sco_setopt(pcb, sopt);
 		break;
 
 	default:
--- a/sys/netbt/sco_upper.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netbt/sco_upper.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: sco_upper.c,v 1.7 2008/03/16 23:28:10 plunky Exp $	*/
+/*	$NetBSD: sco_upper.c,v 1.8 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -32,12 +32,13 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sco_upper.c,v 1.7 2008/03/16 23:28:10 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sco_upper.c,v 1.8 2008/08/06 15:01:24 plunky Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/mbuf.h>
 #include <sys/proc.h>
+#include <sys/socketvar.h>
 #include <sys/systm.h>
 
 #include <netbt/bluetooth.h>
@@ -311,16 +312,16 @@
 }
 
 /*
- * sco_setopt(pcb, option, addr)
+ * sco_setopt(pcb, sopt)
  *
  *	Set SCO pcb options
  */
 int
-sco_setopt(struct sco_pcb *pcb, int opt, void *addr)
+sco_setopt(struct sco_pcb *pcb, const struct sockopt *sopt)
 {
 	int err = 0;
 
-	switch (opt) {
+	switch (sopt->sopt_name) {
 	default:
 		err = ENOPROTOOPT;
 		break;
@@ -330,28 +331,28 @@
 }
 
 /*
- * sco_getopt(pcb, option, addr)
+ * sco_getopt(pcb, sopt)
  *
  *	Get SCO pcb options
  */
 int
-sco_getopt(struct sco_pcb *pcb, int opt, void *addr)
+sco_getopt(struct sco_pcb *pcb, struct sockopt *sopt)
 {
 
-	switch (opt) {
+	switch (sopt->sopt_name) {
 	case SO_SCO_MTU:
-		*(uint16_t *)addr = pcb->sp_mtu;
-		return sizeof(uint16_t);
+		return sockopt_set(sopt, &pcb->sp_mtu, sizeof(uint16_t));
 
 	case SO_SCO_HANDLE:
-		if (pcb->sp_link) {
-			*(uint16_t *)addr = pcb->sp_link->hl_handle;
-			return sizeof(uint16_t);
-		}
-		break;
+		if (pcb->sp_link)
+			return sockopt_set(sopt,
+			    &pcb->sp_link->hl_handle, sizeof(uint16_t));
+
+		return ENOTCONN;
 
 	default:
 		break;
 	}
-	return 0;
+
+	return ENOPROTOOPT;
 }
--- a/sys/netinet/ip_mroute.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet/ip_mroute.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_mroute.c,v 1.114 2008/05/22 01:08:03 dyoung Exp $	*/
+/*	$NetBSD: ip_mroute.c,v 1.115 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -93,7 +93,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_mroute.c,v 1.114 2008/05/22 01:08:03 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_mroute.c,v 1.115 2008/08/06 15:01:23 plunky Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -212,23 +212,19 @@
 
 static int get_sg_cnt(struct sioc_sg_req *);
 static int get_vif_cnt(struct sioc_vif_req *);
-static int ip_mrouter_init(struct socket *, struct mbuf *);
-static int get_version(struct mbuf *);
-static int set_assert(struct mbuf *);
-static int get_assert(struct mbuf *);
-static int add_vif(struct mbuf *);
-static int del_vif(struct mbuf *);
+static int ip_mrouter_init(struct socket *, int);
+static int set_assert(int);
+static int add_vif(struct vifctl *);
+static int del_vif(vifi_t *);
 static void update_mfc_params(struct mfc *, struct mfcctl2 *);
 static void init_mfc_params(struct mfc *, struct mfcctl2 *);
 static void expire_mfc(struct mfc *);
-static int add_mfc(struct mbuf *);
+static int add_mfc(struct sockopt *);
 #ifdef UPCALL_TIMING
 static void collate(struct timeval *);
 #endif
-static int del_mfc(struct mbuf *);
-static int set_api_config(struct mbuf *); /* chose API capabilities */
-static int get_api_support(struct mbuf *);
-static int get_api_config(struct mbuf *);
+static int del_mfc(struct sockopt *);
+static int set_api_config(struct sockopt *); /* chose API capabilities */
 static int socket_send(struct socket *, struct mbuf *, struct sockaddr_in *);
 static void expire_upcalls(void *);
 #ifdef RSVP_ISI
@@ -251,8 +247,8 @@
  * Bandwidth monitoring
  */
 static void free_bw_list(struct bw_meter *);
-static int add_bw_upcall(struct mbuf *);
-static int del_bw_upcall(struct mbuf *);
+static int add_bw_upcall(struct bw_upcall *);
+static int del_bw_upcall(struct bw_upcall *);
 static void bw_meter_receive_packet(struct bw_meter *, int , struct timeval *);
 static void bw_meter_prepare_upcall(struct bw_meter *, struct timeval *);
 static void bw_upcalls_send(void);
@@ -438,51 +434,72 @@
  * Handle MRT setsockopt commands to modify the multicast routing tables.
  */
 int
-ip_mrouter_set(struct socket *so, int optname, struct mbuf **m)
+ip_mrouter_set(struct socket *so, struct sockopt *sopt)
 {
 	int error;
-
-	if (optname != MRT_INIT && so != ip_mrouter)
+	int optval;
+	struct vifctl vifc;
+	vifi_t vifi;
+	struct bw_upcall bwuc;
+
+	if (sopt->sopt_name != MRT_INIT && so != ip_mrouter)
 		error = ENOPROTOOPT;
-	else
-		switch (optname) {
+	else {
+		switch (sopt->sopt_name) {
 		case MRT_INIT:
-			error = ip_mrouter_init(so, *m);
+			error = sockopt_getint(sopt, &optval);
+			if (error)
+				break;
+
+			error = ip_mrouter_init(so, optval);
 			break;
 		case MRT_DONE:
 			error = ip_mrouter_done();
 			break;
 		case MRT_ADD_VIF:
-			error = add_vif(*m);
+			error = sockopt_get(sopt, &vifc, sizeof(vifc));
+			if (error)
+				break;
+			error = add_vif(&vifc);
 			break;
 		case MRT_DEL_VIF:
-			error = del_vif(*m);
+			error = sockopt_get(sopt, &vifi, sizeof(vifi));
+			if (error)
+				break;
+			error = del_vif(&vifi);
 			break;
 		case MRT_ADD_MFC:
-			error = add_mfc(*m);
+			error = add_mfc(sopt);
 			break;
 		case MRT_DEL_MFC:
-			error = del_mfc(*m);
+			error = del_mfc(sopt);
 			break;
 		case MRT_ASSERT:
-			error = set_assert(*m);
+			error = sockopt_getint(sopt, &optval);
+			if (error)
+				break;
+			error = set_assert(optval);
 			break;
 		case MRT_API_CONFIG:
-			error = set_api_config(*m);
+			error = set_api_config(sopt);
 			break;
 		case MRT_ADD_BW_UPCALL:
-			error = add_bw_upcall(*m);
+			error = sockopt_get(sopt, &bwuc, sizeof(bwuc));
+			if (error)
+				break;
+			error = add_bw_upcall(&bwuc);
 			break;
 		case MRT_DEL_BW_UPCALL:
-			error = del_bw_upcall(*m);
+			error = sockopt_get(sopt, &bwuc, sizeof(bwuc));
+			if (error)
+				break;
+			error = del_bw_upcall(&bwuc);
 			break;
 		default:
 			error = ENOPROTOOPT;
 			break;
 		}
-
-	if (*m)
-		m_free(*m);
+	}
 	return (error);
 }
 
@@ -490,38 +507,33 @@
  * Handle MRT getsockopt commands
  */
 int
-ip_mrouter_get(struct socket *so, int optname, struct mbuf **m)
+ip_mrouter_get(struct socket *so, struct sockopt *sopt)
 {
 	int error;
 
 	if (so != ip_mrouter)
 		error = ENOPROTOOPT;
 	else {
-		*m = m_get(M_WAIT, MT_SOOPTS);
-		MCLAIM(*m, so->so_mowner);
-
-		switch (optname) {
+		switch (sopt->sopt_name) {
 		case MRT_VERSION:
-			error = get_version(*m);
+			error = sockopt_setint(sopt, 0x0305); /* XXX !!!! */
 			break;
 		case MRT_ASSERT:
-			error = get_assert(*m);
+			error = sockopt_setint(sopt, pim_assert);
 			break;
 		case MRT_API_SUPPORT:
-			error = get_api_support(*m);
+			error = sockopt_set(sopt, &mrt_api_support,
+			    sizeof(mrt_api_support));
 			break;
 		case MRT_API_CONFIG:
-			error = get_api_config(*m);
+			error = sockopt_set(sopt, &mrt_api_config,
+			    sizeof(mrt_api_config));
 			break;
 		default:
 			error = ENOPROTOOPT;
 			break;
 		}
-
-		if (error)
-			m_free(*m);
 	}
-
 	return (error);
 }
 
@@ -598,10 +610,8 @@
  * Enable multicast routing
  */
 static int
-ip_mrouter_init(struct socket *so, struct mbuf *m)
+ip_mrouter_init(struct socket *so, int v)
 {
-	int *v;
-
 	if (mrtdebug)
 		log(LOG_DEBUG,
 		    "ip_mrouter_init: so_type = %d, pr_protocol = %d\n",
@@ -611,11 +621,7 @@
 	    so->so_proto->pr_protocol != IPPROTO_IGMP)
 		return (EOPNOTSUPP);
 
-	if (m == NULL || m->m_len != sizeof(int))
-		return (EINVAL);
-
-	v = mtod(m, int *);
-	if (*v != 1)
+	if (v != 1)
 		return (EINVAL);
 
 	if (ip_mrouter != NULL)
@@ -732,42 +738,13 @@
 	}
 }
 
-static int
-get_version(struct mbuf *m)
-{
-	int *v = mtod(m, int *);
-
-	*v = 0x0305;	/* XXX !!!! */
-	m->m_len = sizeof(int);
-	return (0);
-}
-
 /*
  * Set PIM assert processing global
  */
 static int
-set_assert(struct mbuf *m)
+set_assert(int i)
 {
-	int *i;
-
-	if (m == NULL || m->m_len != sizeof(int))
-		return (EINVAL);
-
-	i = mtod(m, int *);
-	pim_assert = !!*i;
-	return (0);
-}
-
-/*
- * Get PIM assert processing global
- */
-static int
-get_assert(struct mbuf *m)
-{
-	int *i = mtod(m, int *);
-
-	*i = pim_assert;
-	m->m_len = sizeof(int);
+	pim_assert = !!i;
 	return (0);
 }
 
@@ -775,15 +752,10 @@
  * Configure API capabilities
  */
 static int
-set_api_config(struct mbuf *m)
+set_api_config(struct sockopt *sopt)
 {
-	int i;
-	u_int32_t *apival;
-
-	if (m == NULL || m->m_len < sizeof(u_int32_t))
-		return (EINVAL);
-
-	apival = mtod(m, u_int32_t *);
+	u_int32_t apival;
+	int i, error;
 
 	/*
 	 * We can set the API capabilities only if it is the first operation
@@ -792,60 +764,19 @@
 	 *  - pim_assert is not enabled
 	 *  - the MFC table is empty
 	 */
-	if (numvifs > 0) {
-		*apival = 0;
-		return (EPERM);
-	}
-	if (pim_assert) {
-		*apival = 0;
+	error = sockopt_get(sopt, &apival, sizeof(apival));
+	if (error)
+		return (error);
+	if (numvifs > 0)
 		return (EPERM);
-	}
+	if (pim_assert)
+		return (EPERM);
 	for (i = 0; i < MFCTBLSIZ; i++) {
-		if (LIST_FIRST(&mfchashtbl[i]) != NULL) {
-			*apival = 0;
+		if (LIST_FIRST(&mfchashtbl[i]) != NULL)
 			return (EPERM);
-		}
 	}
 
-	mrt_api_config = *apival & mrt_api_support;
-	*apival = mrt_api_config;
-
-	return (0);
-}
-
-/*
- * Get API capabilities
- */
-static int
-get_api_support(struct mbuf *m)
-{
-	u_int32_t *apival;
-
-	if (m == NULL || m->m_len < sizeof(u_int32_t))
-		return (EINVAL);
-
-	apival = mtod(m, u_int32_t *);
-
-	*apival = mrt_api_support;
-
-	return (0);
-}
-
-/*
- * Get API configured capabilities
- */
-static int
-get_api_config(struct mbuf *m)
-{
-	u_int32_t *apival;
-
-	if (m == NULL || m->m_len < sizeof(u_int32_t))
-		return (EINVAL);
-
-	apival = mtod(m, u_int32_t *);
-
-	*apival = mrt_api_config;
-
+	mrt_api_config = apival & mrt_api_support;
 	return (0);
 }
 
@@ -853,9 +784,8 @@
  * Add a vif to the vif table
  */
 static int
-add_vif(struct mbuf *m)
+add_vif(struct vifctl *vifcp)
 {
-	struct vifctl *vifcp;
 	struct vif *vifp;
 	struct ifaddr *ifa;
 	struct ifnet *ifp;
@@ -863,10 +793,6 @@
 	int error, s;
 	struct sockaddr_in sin;
 
-	if (m == NULL || m->m_len < sizeof(struct vifctl))
-		return (EINVAL);
-
-	vifcp = mtod(m, struct vifctl *);
 	if (vifcp->vifc_vifi >= MAXVIFS)
 		return (EINVAL);
 	if (in_nullhost(vifcp->vifc_lcl_addr))
@@ -1039,17 +965,12 @@
  * Delete a vif from the vif table
  */
 static int
-del_vif(struct mbuf *m)
+del_vif(vifi_t *vifip)
 {
-	vifi_t *vifip;
 	struct vif *vifp;
 	vifi_t vifi;
 	int s;
 
-	if (m == NULL || m->m_len < sizeof(vifi_t))
-		return (EINVAL);
-
-	vifip = mtod(m, vifi_t *);
 	if (*vifip >= numvifs)
 		return (EINVAL);
 
@@ -1135,7 +1056,7 @@
  * Add an mfc entry
  */
 static int
-add_mfc(struct mbuf *m)
+add_mfc(struct sockopt *sopt)
 {
 	struct mfcctl2 mfcctl2;
 	struct mfcctl2 *mfccp;
@@ -1145,26 +1066,24 @@
 	u_short nstl;
 	int s;
 	int mfcctl_size = sizeof(struct mfcctl);
+	int error;
 
 	if (mrt_api_config & MRT_API_FLAGS_ALL)
 		mfcctl_size = sizeof(struct mfcctl2);
 
-	if (m == NULL || m->m_len < mfcctl_size)
-		return (EINVAL);
-
 	/*
 	 * select data size depending on API version.
 	 */
-	if (mrt_api_config & MRT_API_FLAGS_ALL) {
-		struct mfcctl2 *mp2 = mtod(m, struct mfcctl2 *);
-		bcopy(mp2, (void *)&mfcctl2, sizeof(*mp2));
-	} else {
-		struct mfcctl *mp = mtod(m, struct mfcctl *);
-		memcpy(&mfcctl2, mp, sizeof(*mp));
-		memset((char *)&mfcctl2 + sizeof(struct mfcctl), 0,
-		    sizeof(mfcctl2) - sizeof(struct mfcctl));
-	}
 	mfccp = &mfcctl2;
+	memset(&mfcctl2, 0, sizeof(mfcctl2));
+
+	if (mrt_api_config & MRT_API_FLAGS_ALL)
+		error = sockopt_get(sopt, mfccp, sizeof(struct mfcctl2));
+	else
+		error = sockopt_get(sopt, mfccp, sizeof(struct mfcctl));
+
+	if (error)
+		return (error);
 
 	s = splsoftnet();
 	rt = mfc_find(&mfccp->mfcc_origin, &mfccp->mfcc_mcastgrp);
@@ -1305,28 +1224,29 @@
  * Delete an mfc entry
  */
 static int
-del_mfc(struct mbuf *m)
+del_mfc(struct sockopt *sopt)
 {
 	struct mfcctl2 mfcctl2;
 	struct mfcctl2 *mfccp;
 	struct mfc *rt;
 	int s;
-	int mfcctl_size = sizeof(struct mfcctl);
-	struct mfcctl *mp = mtod(m, struct mfcctl *);
+	int error;
 
 	/*
 	 * XXX: for deleting MFC entries the information in entries
 	 * of size "struct mfcctl" is sufficient.
 	 */
 
-	if (m == NULL || m->m_len < mfcctl_size)
-		return (EINVAL);
-
-	memcpy(&mfcctl2, mp, sizeof(*mp));
-	memset((char *)&mfcctl2 + sizeof(struct mfcctl), 0,
-	    sizeof(mfcctl2) - sizeof(struct mfcctl));
-
 	mfccp = &mfcctl2;
+	memset(&mfcctl2, 0, sizeof(mfcctl2));
+
+	error = sockopt_get(sopt, mfccp, sizeof(struct mfcctl));
+	if (error) {
+		/* Try with the size of mfcctl2. */
+		error = sockopt_get(sopt, mfccp, sizeof(struct mfcctl2));
+		if (error)
+			return (error);
+	}
 
 	if (mrtdebug & DEBUG_MFC)
 		log(LOG_DEBUG, "del_mfc origin %x mcastgrp %x\n",
@@ -2557,7 +2477,7 @@
  * Add a bw_meter entry
  */
 static int
-add_bw_upcall(struct mbuf *m)
+add_bw_upcall(struct bw_upcall *req)
 {
     int s;
     struct mfc *mfc;
@@ -2566,12 +2486,6 @@
     struct timeval now;
     struct bw_meter *x;
     uint32_t flags;
-    struct bw_upcall *req;
-
-    if (m == NULL || m->m_len < sizeof(struct bw_upcall))
-	return EINVAL;
-
-    req = mtod(m, struct bw_upcall *);
 
     if (!(mrt_api_config & MRT_MFC_BW_UPCALL))
 	return EOPNOTSUPP;
@@ -2656,17 +2570,11 @@
  * Delete one or multiple bw_meter entries
  */
 static int
-del_bw_upcall(struct mbuf *m)
+del_bw_upcall(struct bw_upcall *req)
 {
     int s;
     struct mfc *mfc;
     struct bw_meter *x;
-    struct bw_upcall *req;
-
-    if (m == NULL || m->m_len < sizeof(struct bw_upcall))
-	return EINVAL;
-
-    req = mtod(m, struct bw_upcall *);
 
     if (!(mrt_api_config & MRT_MFC_BW_UPCALL))
 	return EOPNOTSUPP;
--- a/sys/netinet/ip_mroute.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet/ip_mroute.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_mroute.h,v 1.29 2007/12/25 18:33:46 perry Exp $	*/
+/*	$NetBSD: ip_mroute.h,v 1.30 2008/08/06 15:01:23 plunky Exp $	*/
 
 #ifndef _NETINET_IP_MROUTE_H_
 #define _NETINET_IP_MROUTE_H_
@@ -332,8 +332,8 @@
 	struct timeval	bm_start_time;		/* abs. time		     */
 };
 
-int	ip_mrouter_set(struct socket *, int, struct mbuf **);
-int	ip_mrouter_get(struct socket *, int, struct mbuf **);
+int	ip_mrouter_set(struct socket *, struct sockopt *);
+int	ip_mrouter_get(struct socket *, struct sockopt *);
 int	mrt_ioctl(struct socket *, u_long, void *);
 int	ip_mrouter_done(void);
 void	ip_mrouter_detach(struct ifnet *);
--- a/sys/netinet/ip_output.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet/ip_output.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_output.c,v 1.196 2008/04/28 20:24:09 martin Exp $	*/
+/*	$NetBSD: ip_output.c,v 1.197 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.196 2008/04/28 20:24:09 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.197 2008/08/06 15:01:23 plunky Exp $");
 
 #include "opt_pfil_hooks.h"
 #include "opt_inet.h"
@@ -152,7 +152,6 @@
 static struct ifnet *ip_multicast_if(struct in_addr *, int *);
 static void ip_mloopback(struct ifnet *, struct mbuf *,
     const struct sockaddr_in *);
-static int ip_getoptval(struct mbuf *, u_int8_t *, u_int);
 
 #ifdef PFIL_HOOKS
 extern struct pfil_head inet_pfil_hook;			/* XXX */
@@ -1195,36 +1194,40 @@
  * IP socket option processing.
  */
 int
-ip_ctloutput(int op, struct socket *so, int level, int optname,
-    struct mbuf **mp)
+ip_ctloutput(int op, struct socket *so, struct sockopt *sopt)
 {
 	struct inpcb *inp = sotoinpcb(so);
-	struct mbuf *m = *mp;
 	int optval = 0;
 	int error = 0;
 #if defined(IPSEC) || defined(FAST_IPSEC)
 	struct lwp *l = curlwp;	/*XXX*/
 #endif
 
-	if (level != IPPROTO_IP) {
-		if (op == PRCO_SETOPT && *mp)
-			(void) m_free(*mp);
-		if (level == SOL_SOCKET && optname == SO_NOHEADER)
+	if (sopt->sopt_level != IPPROTO_IP) {
+		if (sopt->sopt_level == SOL_SOCKET && sopt->sopt_name == SO_NOHEADER)
 			return 0;
 		return ENOPROTOOPT;
 	}
 
 	switch (op) {
-
 	case PRCO_SETOPT:
-		switch (optname) {
+		switch (sopt->sopt_name) {
 		case IP_OPTIONS:
 #ifdef notyet
 		case IP_RETOPTS:
-			return (ip_pcbopts(optname, &inp->inp_options, m));
-#else
-			return (ip_pcbopts(&inp->inp_options, m));
 #endif
+		    {
+			struct mbuf *m;
+
+			m = sockopt_getmbuf(sopt);
+			if (m == NULL) {
+				error = ENOBUFS;
+				break;
+			}
+
+			error = ip_pcbopts(&inp->inp_options, m);
+			break;
+		    }
 
 		case IP_TOS:
 		case IP_TTL:
@@ -1232,43 +1235,41 @@
 		case IP_RECVRETOPTS:
 		case IP_RECVDSTADDR:
 		case IP_RECVIF:
-			if (m == NULL || m->m_len != sizeof(int))
-				error = EINVAL;
-			else {
-				optval = *mtod(m, int *);
-				switch (optname) {
+			error = sockopt_getint(sopt, &optval);
+			if (error)
+				break;
 
-				case IP_TOS:
-					inp->inp_ip.ip_tos = optval;
-					break;
+			switch (sopt->sopt_name) {
+			case IP_TOS:
+				inp->inp_ip.ip_tos = optval;
+				break;
 
-				case IP_TTL:
-					inp->inp_ip.ip_ttl = optval;
-					break;
+			case IP_TTL:
+				inp->inp_ip.ip_ttl = optval;
+				break;
 #define	OPTSET(bit) \
 	if (optval) \
 		inp->inp_flags |= bit; \
 	else \
 		inp->inp_flags &= ~bit;
 
-				case IP_RECVOPTS:
-					OPTSET(INP_RECVOPTS);
-					break;
+			case IP_RECVOPTS:
+				OPTSET(INP_RECVOPTS);
+				break;
 
-				case IP_RECVRETOPTS:
-					OPTSET(INP_RECVRETOPTS);
-					break;
+			case IP_RECVRETOPTS:
+				OPTSET(INP_RECVRETOPTS);
+				break;
 
-				case IP_RECVDSTADDR:
-					OPTSET(INP_RECVDSTADDR);
-					break;
+			case IP_RECVDSTADDR:
+				OPTSET(INP_RECVDSTADDR);
+				break;
 
-				case IP_RECVIF:
-					OPTSET(INP_RECVIF);
-					break;
-				}
+			case IP_RECVIF:
+				OPTSET(INP_RECVIF);
+				break;
 			}
-			break;
+		break;
 #undef OPTSET
 
 		case IP_MULTICAST_IF:
@@ -1276,38 +1277,35 @@
 		case IP_MULTICAST_LOOP:
 		case IP_ADD_MEMBERSHIP:
 		case IP_DROP_MEMBERSHIP:
-			error = ip_setmoptions(optname, &inp->inp_moptions, m);
+			error = ip_setmoptions(&inp->inp_moptions, sopt);
 			break;
 
 		case IP_PORTRANGE:
-			if (m == 0 || m->m_len != sizeof(int))
-				error = EINVAL;
-			else {
-				optval = *mtod(m, int *);
-
-				switch (optval) {
+			error = sockopt_getint(sopt, &optval);
+			if (error)
+				break;
 
-				case IP_PORTRANGE_DEFAULT:
-				case IP_PORTRANGE_HIGH:
-					inp->inp_flags &= ~(INP_LOWPORT);
-					break;
+			/* INP_LOCK(inp); */
+			switch (optval) {
+			case IP_PORTRANGE_DEFAULT:
+			case IP_PORTRANGE_HIGH:
+				inp->inp_flags &= ~(INP_LOWPORT);
+				break;
 
-				case IP_PORTRANGE_LOW:
-					inp->inp_flags |= INP_LOWPORT;
-					break;
+			case IP_PORTRANGE_LOW:
+				inp->inp_flags |= INP_LOWPORT;
+				break;
 
-				default:
-					error = EINVAL;
-					break;
-				}
+			default:
+				error = EINVAL;
+				break;
 			}
+			/* INP_UNLOCK(inp); */
 			break;
 
 #if defined(IPSEC) || defined(FAST_IPSEC)
 		case IP_IPSEC_POLICY:
-		{
-			void *req = NULL;
-			size_t len = 0;
+		    {
 			int priv = 0;
 
 #ifdef __NetBSD__
@@ -1319,11 +1317,9 @@
 #else
 			priv = (in6p->in6p_socket->so_state & SS_PRIV);
 #endif
-			if (m) {
-				req = mtod(m, void *);
-				len = m->m_len;
-			}
-			error = ipsec4_set_policy(inp, optname, req, len, priv);
+
+			error = ipsec4_set_policy(inp, sopt->sopt_name,
+			    sopt->sopt_data, sopt->sopt_size, priv);
 			break;
 		    }
 #endif /*IPSEC*/
@@ -1332,22 +1328,18 @@
 			error = ENOPROTOOPT;
 			break;
 		}
-		if (m)
-			(void)m_free(m);
 		break;
 
 	case PRCO_GETOPT:
-		switch (optname) {
+		switch (sopt->sopt_name) {
 		case IP_OPTIONS:
 		case IP_RETOPTS:
-			*mp = m = m_get(M_WAIT, MT_SOOPTS);
-			MCLAIM(m, so->so_mowner);
 			if (inp->inp_options) {
-				m->m_len = inp->inp_options->m_len;
-				bcopy(mtod(inp->inp_options, void *),
-				    mtod(m, void *), (unsigned)m->m_len);
-			} else
-				m->m_len = 0;
+				struct mbuf *m;
+
+				m = m_copym(inp->inp_options, 0, M_COPYALL, M_WAIT);
+				error = sockopt_setmbuf(sopt, m);
+			}
 			break;
 
 		case IP_TOS:
@@ -1357,11 +1349,7 @@
 		case IP_RECVDSTADDR:
 		case IP_RECVIF:
 		case IP_ERRORMTU:
-			*mp = m = m_get(M_WAIT, MT_SOOPTS);
-			MCLAIM(m, so->so_mowner);
-			m->m_len = sizeof(int);
-			switch (optname) {
-
+			switch (sopt->sopt_name) {
 			case IP_TOS:
 				optval = inp->inp_ip.ip_tos;
 				break;
@@ -1392,21 +1380,19 @@
 				optval = OPTBIT(INP_RECVIF);
 				break;
 			}
-			*mtod(m, int *) = optval;
+			error = sockopt_setint(sopt, optval);
 			break;
 
 #if 0	/* defined(IPSEC) || defined(FAST_IPSEC) */
-		/* XXX: code broken */
 		case IP_IPSEC_POLICY:
 		{
-			void *req = NULL;
-			size_t len = 0;
+			struct mbuf *m = NULL;
 
-			if (m) {
-				req = mtod(m, void *);
-				len = m->m_len;
-			}
-			error = ipsec4_get_policy(inp, req, len, mp);
+			/* XXX this will return EINVAL as sopt is empty */
+			error = ipsec4_get_policy(inp, sopt->sopt_data,
+			    sopt->sopt_size, &m);
+			if (error == 0)
+				error = sockopt_setmbuf(sopt, m);
 			break;
 		}
 #endif /*IPSEC*/
@@ -1416,22 +1402,17 @@
 		case IP_MULTICAST_LOOP:
 		case IP_ADD_MEMBERSHIP:
 		case IP_DROP_MEMBERSHIP:
-			error = ip_getmoptions(optname, inp->inp_moptions, mp);
-			if (*mp)
-				MCLAIM(*mp, so->so_mowner);
+			error = ip_getmoptions(inp->inp_moptions, sopt);
 			break;
 
 		case IP_PORTRANGE:
-			*mp = m = m_get(M_WAIT, MT_SOOPTS);
-			MCLAIM(m, so->so_mowner);
-			m->m_len = sizeof(int);
-
 			if (inp->inp_flags & INP_LOWPORT)
 				optval = IP_PORTRANGE_LOW;
 			else
 				optval = IP_PORTRANGE_DEFAULT;
 
-			*mtod(m, int *) = optval;
+			error = sockopt_setint(sopt, optval);
+
 			break;
 
 		default:
@@ -1449,11 +1430,7 @@
  * with destination address if source routed.
  */
 int
-#ifdef notyet
-ip_pcbopts(int optname, struct mbuf **pcbopt, struct mbuf *m)
-#else
 ip_pcbopts(struct mbuf **pcbopt, struct mbuf *m)
-#endif
 {
 	int cnt, optlen;
 	u_char *cp;
@@ -1582,24 +1559,32 @@
 }
 
 static int
-ip_getoptval(struct mbuf *m, u_int8_t *val, u_int maxval)
+ip_getoptval(struct sockopt *sopt, u_int8_t *val, u_int maxval)
 {
 	u_int tval;
+	u_char cval;
+	int error;
 
-	if (m == NULL)
+	if (sopt == NULL)
 		return EINVAL;
 
-	switch (m->m_len) {
+	switch (sopt->sopt_size) {
 	case sizeof(u_char):
-		tval = *(mtod(m, u_char *));
+		error = sockopt_get(sopt, &cval, sizeof(u_char));
+		tval = cval;
 		break;
+
 	case sizeof(u_int):
-		tval = *(mtod(m, u_int *));
+		error = sockopt_get(sopt, &tval, sizeof(u_int));
 		break;
+
 	default:
-		return EINVAL;
+		error = EINVAL;
 	}
 
+	if (error)
+		return error;
+
 	if (tval > maxval)
 		return EINVAL;
 
@@ -1611,12 +1596,12 @@
  * Set the IP multicast options in response to user setsockopt().
  */
 int
-ip_setmoptions(int optname, struct ip_moptions **imop, struct mbuf *m)
+ip_setmoptions(struct ip_moptions **imop, struct sockopt *sopt)
 {
 	int error = 0;
 	int i;
 	struct in_addr addr;
-	struct ip_mreq *mreq;
+	struct ip_mreq lmreq, *mreq;
 	struct ifnet *ifp;
 	struct ip_moptions *imo = *imop;
 	int ifindex;
@@ -1639,17 +1624,15 @@
 		imo->imo_num_memberships = 0;
 	}
 
-	switch (optname) {
-
+	switch (sopt->sopt_name) {
 	case IP_MULTICAST_IF:
 		/*
 		 * Select the interface for outgoing multicast packets.
 		 */
-		if (m == NULL || m->m_len != sizeof(struct in_addr)) {
-			error = EINVAL;
+		error = sockopt_get(sopt, &addr, sizeof(addr));
+		if (error)
 			break;
-		}
-		addr = *(mtod(m, struct in_addr *));
+
 		/*
 		 * INADDR_ANY is used to remove a previous selection.
 		 * When no interface is selected, a default one is
@@ -1680,7 +1663,7 @@
 		/*
 		 * Set the IP time-to-live for outgoing multicast packets.
 		 */
-		error = ip_getoptval(m, &imo->imo_multicast_ttl, MAXTTL);
+		error = ip_getoptval(sopt, &imo->imo_multicast_ttl, MAXTTL);
 		break;
 
 	case IP_MULTICAST_LOOP:
@@ -1688,7 +1671,7 @@
 		 * Set the loopback flag for outgoing multicast packets.
 		 * Must be zero or one.
 		 */
-		error = ip_getoptval(m, &imo->imo_multicast_loop, 1);
+		error = ip_getoptval(sopt, &imo->imo_multicast_loop, 1);
 		break;
 
 	case IP_ADD_MEMBERSHIP:
@@ -1696,11 +1679,12 @@
 		 * Add a multicast group membership.
 		 * Group must be a valid IP multicast address.
 		 */
-		if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
-			error = EINVAL;
+		error = sockopt_get(sopt, &lmreq, sizeof(lmreq));
+		if (error)
 			break;
-		}
-		mreq = mtod(m, struct ip_mreq *);
+
+		mreq = &lmreq;
+
 		if (!IN_MULTICAST(mreq->imr_multiaddr.s_addr)) {
 			error = EINVAL;
 			break;
@@ -1770,11 +1754,12 @@
 		 * Drop a multicast group membership.
 		 * Group must be a valid IP multicast address.
 		 */
-		if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
-			error = EINVAL;
+		error = sockopt_get(sopt, &lmreq, sizeof(lmreq));
+		if (error)
 			break;
-		}
-		mreq = mtod(m, struct ip_mreq *);
+
+		mreq = &lmreq;
+
 		if (!IN_MULTICAST(mreq->imr_multiaddr.s_addr)) {
 			error = EINVAL;
 			break;
@@ -1842,48 +1827,48 @@
  * Return the IP multicast options in response to user getsockopt().
  */
 int
-ip_getmoptions(int optname, struct ip_moptions *imo, struct mbuf **mp)
+ip_getmoptions(struct ip_moptions *imo, struct sockopt *sopt)
 {
-	u_char *ttl;
-	u_char *loop;
-	struct in_addr *addr;
+	struct in_addr addr;
 	struct in_ifaddr *ia;
+	int error;
+	uint8_t optval;
 
-	*mp = m_get(M_WAIT, MT_SOOPTS);
+	error = 0;
 
-	switch (optname) {
-
+	switch (sopt->sopt_name) {
 	case IP_MULTICAST_IF:
-		addr = mtod(*mp, struct in_addr *);
-		(*mp)->m_len = sizeof(struct in_addr);
 		if (imo == NULL || imo->imo_multicast_ifp == NULL)
-			*addr = zeroin_addr;
+			addr = zeroin_addr;
 		else if (imo->imo_multicast_addr.s_addr) {
 			/* return the value user has set */
-			*addr = imo->imo_multicast_addr;
+			addr = imo->imo_multicast_addr;
 		} else {
 			IFP_TO_IA(imo->imo_multicast_ifp, ia);
-			*addr = ia ? ia->ia_addr.sin_addr : zeroin_addr;
+			addr = ia ? ia->ia_addr.sin_addr : zeroin_addr;
 		}
-		return (0);
+		error = sockopt_set(sopt, &addr, sizeof(addr));
+		break;
 
 	case IP_MULTICAST_TTL:
-		ttl = mtod(*mp, u_char *);
-		(*mp)->m_len = 1;
-		*ttl = imo ? imo->imo_multicast_ttl
-			   : IP_DEFAULT_MULTICAST_TTL;
-		return (0);
+		optval = imo ? imo->imo_multicast_ttl
+			     : IP_DEFAULT_MULTICAST_TTL;
+
+		error = sockopt_set(sopt, &optval, sizeof(optval));
+		break;
 
 	case IP_MULTICAST_LOOP:
-		loop = mtod(*mp, u_char *);
-		(*mp)->m_len = 1;
-		*loop = imo ? imo->imo_multicast_loop
-			    : IP_DEFAULT_MULTICAST_LOOP;
-		return (0);
+		optval = imo ? imo->imo_multicast_loop
+			     : IP_DEFAULT_MULTICAST_LOOP;
+
+		error = sockopt_set(sopt, &optval, sizeof(optval));
+		break;
 
 	default:
-		return (EOPNOTSUPP);
+		error = EOPNOTSUPP;
 	}
+
+	return (error);
 }
 
 /*
--- a/sys/netinet/ip_var.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet/ip_var.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip_var.h,v 1.87 2008/04/12 05:58:22 thorpej Exp $	*/
+/*	$NetBSD: ip_var.h,v 1.88 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1993
@@ -200,14 +200,15 @@
 extern struct pool inmulti_pool;
 extern struct pool ipqent_pool;
 struct	 inpcb;
+struct   sockopt;
 
-int	 ip_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int	 ip_ctloutput(int, struct socket *, struct sockopt *);
 int	 ip_dooptions(struct mbuf *);
 void	 ip_drain(void);
 void	 ip_forward(struct mbuf *, int);
 void	 ip_freef(struct ipq *);
 void	 ip_freemoptions(struct ip_moptions *);
-int	 ip_getmoptions(int, struct ip_moptions *, struct mbuf **);
+int	 ip_getmoptions(struct ip_moptions *, struct sockopt *);
 void	 ip_init(void);
 int	 ip_optcopy(struct ip *, struct ip *);
 u_int	 ip_optlen(struct inpcb *);
@@ -220,7 +221,7 @@
 	 ip_rtaddr(struct in_addr);
 void	 ip_savecontrol(struct inpcb *, struct mbuf **, struct ip *,
 	   struct mbuf *);
-int	 ip_setmoptions(int, struct ip_moptions **, struct mbuf *);
+int	 ip_setmoptions(struct ip_moptions **, struct sockopt *);
 void	 ip_slowtimo(void);
 struct mbuf *
 	 ip_srcroute(void);
@@ -228,7 +229,7 @@
 void	 ip_statinc(u_int);
 void	 ipintr(void);
 void *	 rip_ctlinput(int, const struct sockaddr *, void *);
-int	 rip_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int	 rip_ctloutput(int, struct socket *, struct sockopt *);
 void	 rip_init(void);
 void	 rip_input(struct mbuf *, ...);
 int	 rip_output(struct mbuf *, ...);
--- a/sys/netinet/raw_ip.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet/raw_ip.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: raw_ip.c,v 1.107 2008/04/24 11:38:38 ad Exp $	*/
+/*	$NetBSD: raw_ip.c,v 1.108 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: raw_ip.c,v 1.107 2008/04/24 11:38:38 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: raw_ip.c,v 1.108 2008/08/06 15:01:23 plunky Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -380,40 +380,43 @@
  * Raw IP socket option processing.
  */
 int
-rip_ctloutput(int op, struct socket *so, int level, int optname,
-    struct mbuf **m)
+rip_ctloutput(int op, struct socket *so, struct sockopt *sopt)
 {
 	struct inpcb *inp = sotoinpcb(so);
 	int error = 0;
+	int optval;
 
-	if (level == SOL_SOCKET && optname == SO_NOHEADER) {
+	if (sopt->sopt_level == SOL_SOCKET && sopt->sopt_name == SO_NOHEADER) {
 		if (op == PRCO_GETOPT) {
-			*m = m_intopt(so,
-			    (inp->inp_flags & INP_NOHEADER) ? 1 : 0);
-			return 0;
-		} else if (*m == NULL || (*m)->m_len != sizeof(int))
-			error = EINVAL;
-		else if (*mtod(*m, int *)) {
-			inp->inp_flags &= ~INP_HDRINCL;
-			inp->inp_flags |= INP_NOHEADER;
-		} else
-			inp->inp_flags &= ~INP_NOHEADER;
-		goto free_m;
-	} else if (level != IPPROTO_IP)
-		return ip_ctloutput(op, so, level, optname, m);
+			optval = (inp->inp_flags & INP_NOHEADER) ? 1 : 0;
+			error = sockopt_set(sopt, &optval, sizeof(optval));
+		} else if (op == PRCO_SETOPT) {
+			error = sockopt_getint(sopt, &optval);
+			if (error)
+				goto out;
+			if (optval) {
+				inp->inp_flags &= ~INP_HDRINCL;
+				inp->inp_flags |= INP_NOHEADER;
+			} else
+				inp->inp_flags &= ~INP_NOHEADER;
+		}
+		goto out;
+	} else if (sopt->sopt_level != IPPROTO_IP)
+		return ip_ctloutput(op, so, sopt);
 
 	switch (op) {
 
 	case PRCO_SETOPT:
-		switch (optname) {
+		switch (sopt->sopt_name) {
 		case IP_HDRINCL:
-			if (*m == NULL || (*m)->m_len != sizeof(int))
-				error = EINVAL;
-			else if (*mtod(*m, int *))
+			error = sockopt_getint(sopt, &optval);
+			if (error)
+				break;
+			if (optval)
 				inp->inp_flags |= INP_HDRINCL;
 			else
 				inp->inp_flags &= ~INP_HDRINCL;
-			goto free_m;
+			break;
 
 #ifdef MROUTING
 		case MRT_INIT:
@@ -426,20 +429,21 @@
 		case MRT_API_CONFIG:
 		case MRT_ADD_BW_UPCALL:
 		case MRT_DEL_BW_UPCALL:
-			error = ip_mrouter_set(so, optname, m);
+			error = ip_mrouter_set(so, sopt);
 			break;
 #endif
 
 		default:
-			error = ip_ctloutput(op, so, level, optname, m);
+			error = ip_ctloutput(op, so, sopt);
 			break;
 		}
 		break;
 
 	case PRCO_GETOPT:
-		switch (optname) {
+		switch (sopt->sopt_name) {
 		case IP_HDRINCL:
-			*m = m_intopt(so, inp->inp_flags & INP_HDRINCL ? 1 : 0);
+			optval = inp->inp_flags & INP_HDRINCL;
+			error = sockopt_set(sopt, &optval, sizeof(optval));
 			break;
 
 #ifdef MROUTING
@@ -447,20 +451,17 @@
 		case MRT_ASSERT:
 		case MRT_API_SUPPORT:
 		case MRT_API_CONFIG:
-			error = ip_mrouter_get(so, optname, m);
+			error = ip_mrouter_get(so, sopt);
 			break;
 #endif
 
 		default:
-			error = ip_ctloutput(op, so, level, optname, m);
+			error = ip_ctloutput(op, so, sopt);
 			break;
 		}
 		break;
 	}
-	return error;
-free_m:
-	if (op == PRCO_SETOPT && *m != NULL)
-		(void)m_free(*m);
+ out:
 	return error;
 }
 
--- a/sys/netinet/tcp_usrreq.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet/tcp_usrreq.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: tcp_usrreq.c,v 1.146 2008/05/04 07:22:14 thorpej Exp $	*/
+/*	$NetBSD: tcp_usrreq.c,v 1.147 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -95,7 +95,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tcp_usrreq.c,v 1.146 2008/05/04 07:22:14 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tcp_usrreq.c,v 1.147 2008/08/06 15:01:23 plunky Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -639,8 +639,7 @@
 
 
 int
-tcp_ctloutput(int op, struct socket *so, int level, int optname,
-    struct mbuf **mp)
+tcp_ctloutput(int op, struct socket *so, struct sockopt *sopt)
 {
 	int error = 0, s;
 	struct inpcb *inp;
@@ -648,10 +647,12 @@
 	struct in6pcb *in6p;
 #endif
 	struct tcpcb *tp;
-	struct mbuf *m;
-	int i;
 	u_int ui;
 	int family;	/* family of the socket */
+	int level, optname, optval;
+
+	level = sopt->sopt_level;
+	optname = sopt->sopt_name;
 
 	family = so->so_proto->pr_domain->dom_family;
 
@@ -682,20 +683,18 @@
 #endif
 	{
 		splx(s);
-		if (op == PRCO_SETOPT && *mp)
-			(void) m_free(*mp);
 		return (ECONNRESET);
 	}
 	if (level != IPPROTO_TCP) {
 		switch (family) {
 #ifdef INET
 		case PF_INET:
-			error = ip_ctloutput(op, so, level, optname, mp);
+			error = ip_ctloutput(op, so, sopt);
 			break;
 #endif
 #ifdef INET6
 		case PF_INET6:
-			error = ip6_ctloutput(op, so, level, optname, mp);
+			error = ip6_ctloutput(op, so, sopt);
 			break;
 #endif
 		}
@@ -712,18 +711,14 @@
 		tp = NULL;
 
 	switch (op) {
-
 	case PRCO_SETOPT:
-		m = *mp;
 		switch (optname) {
-
 #ifdef TCP_SIGNATURE
 		case TCP_MD5SIG:
-			if (m == NULL || m->m_len != sizeof(int))
-				error = EINVAL;
+			error = sockopt_getint(sopt, &optval);
 			if (error)
 				break;
-			if (*mtod(m, int *) > 0)
+			if (optval > 0)
 				tp->t_flags |= TF_SIGNATURE;
 			else
 				tp->t_flags &= ~TF_SIGNATURE;
@@ -731,33 +726,36 @@
 #endif /* TCP_SIGNATURE */
 
 		case TCP_NODELAY:
-			if (m == NULL || m->m_len != sizeof(int))
-				error = EINVAL;
-			else if (*mtod(m, int *))
+			error = sockopt_getint(sopt, &optval);
+			if (error)
+				break;
+			if (optval)
 				tp->t_flags |= TF_NODELAY;
 			else
 				tp->t_flags &= ~TF_NODELAY;
 			break;
 
 		case TCP_MAXSEG:
-			if (m && m->m_len == sizeof(int) &&
-			    (i = *mtod(m, int *)) > 0 &&
-			    i <= tp->t_peermss)
-				tp->t_peermss = i;  /* limit on send size */
+			error = sockopt_getint(sopt, &optval);
+			if (error)
+				break;
+			if (optval > 0 && optval <= tp->t_peermss)
+				tp->t_peermss = optval; /* limit on send size */
 			else
 				error = EINVAL;
 			break;
 #ifdef notyet
 		case TCP_CONGCTL:
-			if (m == NULL)
-				error = EINVAL;
-			error = tcp_congctl_select(tp, mtod(m, char *));
+			/* XXX string overflow XXX */
+			error = tcp_congctl_select(tp, sopt->sopt_data);
+			break;
 #endif
-			break;
 
 		case TCP_KEEPIDLE:
-			if (m && m->m_len == sizeof(u_int) &&
-			    (ui = *mtod(m, u_int *)) > 0) {
+			error = sockopt_get(sopt, &ui, sizeof(ui));
+			if (error)
+				break;
+			if (ui > 0) {
 				tp->t_keepidle = ui;
 				change_keepalive(so, tp);
 			} else
@@ -765,8 +763,10 @@
 			break;
 
 		case TCP_KEEPINTVL:
-			if (m && m->m_len == sizeof(u_int) &&
-			    (ui = *mtod(m, u_int *)) > 0) {
+			error = sockopt_get(sopt, &ui, sizeof(ui));
+			if (error)
+				break;
+			if (ui > 0) {
 				tp->t_keepintvl = ui;
 				change_keepalive(so, tp);
 			} else
@@ -774,8 +774,10 @@
 			break;
 
 		case TCP_KEEPCNT:
-			if (m && m->m_len == sizeof(u_int) &&
-			    (ui = *mtod(m, u_int *)) > 0) {
+			error = sockopt_get(sopt, &ui, sizeof(ui));
+			if (error)
+				break;
+			if (ui > 0) {
 				tp->t_keepcnt = ui;
 				change_keepalive(so, tp);
 			} else
@@ -783,8 +785,10 @@
 			break;
 
 		case TCP_KEEPINIT:
-			if (m && m->m_len == sizeof(u_int) &&
-			    (ui = *mtod(m, u_int *)) > 0) {
+			error = sockopt_get(sopt, &ui, sizeof(ui));
+			if (error)
+				break;
+			if (ui > 0) {
 				tp->t_keepinit = ui;
 				change_keepalive(so, tp);
 			} else
@@ -795,24 +799,23 @@
 			error = ENOPROTOOPT;
 			break;
 		}
-		if (m)
-			(void) m_free(m);
 		break;
 
 	case PRCO_GETOPT:
-		*mp = m = m_intopt(so, 0);
-
 		switch (optname) {
 #ifdef TCP_SIGNATURE
 		case TCP_MD5SIG:
-			*mtod(m, int *) = (tp->t_flags & TF_SIGNATURE) ? 1 : 0;
+			optval = (tp->t_flags & TF_SIGNATURE) ? 1 : 0;
+			error = sockopt_set(sopt, &optval, sizeof(optval));
 			break;
 #endif
 		case TCP_NODELAY:
-			*mtod(m, int *) = tp->t_flags & TF_NODELAY;
+			optval = tp->t_flags & TF_NODELAY;
+			error = sockopt_set(sopt, &optval, sizeof(optval));
 			break;
 		case TCP_MAXSEG:
-			*mtod(m, int *) = tp->t_peermss;
+			optval = tp->t_peermss;
+			error = sockopt_set(sopt, &optval, sizeof(optval));
 			break;
 #ifdef notyet
 		case TCP_CONGCTL:
--- a/sys/netinet/tcp_var.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet/tcp_var.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: tcp_var.h,v 1.157 2008/04/28 20:24:09 martin Exp $	*/
+/*	$NetBSD: tcp_var.h,v 1.158 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -822,7 +822,7 @@
 void	 *tcp6_ctlinput(int, const struct sockaddr *, void *);
 #endif
 void	 *tcp_ctlinput(int, const struct sockaddr *, void *);
-int	 tcp_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int	 tcp_ctloutput(int, struct socket *, struct sockopt *);
 struct tcpcb *
 	 tcp_disconnect(struct tcpcb *);
 struct tcpcb *
--- a/sys/netinet/udp_usrreq.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet/udp_usrreq.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: udp_usrreq.c,v 1.172 2008/05/04 07:22:14 thorpej Exp $	*/
+/*	$NetBSD: udp_usrreq.c,v 1.173 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.172 2008/05/04 07:22:14 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udp_usrreq.c,v 1.173 2008/08/06 15:01:23 plunky Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -1000,14 +1000,13 @@
 }
 
 int
-udp_ctloutput(int op, struct socket *so, int level, int optname,
-    struct mbuf **mp)
+udp_ctloutput(int op, struct socket *so, struct sockopt *sopt)
 {
 	int s;
 	int error = 0;
-	struct mbuf *m;
 	struct inpcb *inp;
 	int family;
+	int optval;
 
 	family = so->so_proto->pr_domain->dom_family;
 
@@ -1015,16 +1014,16 @@
 	switch (family) {
 #ifdef INET
 	case PF_INET:
-		if (level != IPPROTO_UDP) {
-			error = ip_ctloutput(op, so, level, optname, mp);
+		if (sopt->sopt_level != IPPROTO_UDP) {
+			error = ip_ctloutput(op, so, sopt);
 			goto end;
 		}
 		break;
 #endif
 #ifdef INET6
 	case PF_INET6:
-		if (level != IPPROTO_UDP) {
-			error = ip6_ctloutput(op, so, level, optname, mp);
+		if (sopt->sopt_level != IPPROTO_UDP) {
+			error = ip6_ctloutput(op, so, sopt);
 			goto end;
 		}
 		break;
@@ -1037,17 +1036,15 @@
 
 	switch (op) {
 	case PRCO_SETOPT:
-		m = *mp;
 		inp = sotoinpcb(so);
 
-		switch (optname) {
+		switch (sopt->sopt_name) {
 		case UDP_ENCAP:
-			if (m == NULL || m->m_len != sizeof(int)) {
-				error = EINVAL;
+			error = sockopt_getint(sopt, &optval);
+			if (error)
 				break;
-			}
 
-			switch(*mtod(m, int *)) {
+			switch(optval) {
 #ifdef IPSEC_NAT_T
 			case 0:
 				inp->inp_flags &= ~INP_ESPINUDP_ALL;
@@ -1073,9 +1070,6 @@
 			error = ENOPROTOOPT;
 			break;
 		}
-		if (m != NULL) {
-			m_free(m);
-		}
 		break;
 
 	default:
--- a/sys/netinet/udp_var.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet/udp_var.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: udp_var.h,v 1.35 2008/04/12 05:58:22 thorpej Exp $	*/
+/*	$NetBSD: udp_var.h,v 1.36 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -90,7 +90,7 @@
 extern	struct	inpcbtable udbtable;
 
 void	 *udp_ctlinput(int, const struct sockaddr *, void *);
-int	 udp_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int	 udp_ctloutput(int, struct socket *, struct sockopt *);
 void	 udp_init(void);
 void	 udp_input(struct mbuf *, ...);
 int	 udp_output(struct mbuf *, ...);
--- a/sys/netinet6/icmp6.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet6/icmp6.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: icmp6.c,v 1.148 2008/05/07 11:28:37 bouyer Exp $	*/
+/*	$NetBSD: icmp6.c,v 1.149 2008/08/06 15:01:23 plunky Exp $	*/
 /*	$KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.148 2008/05/07 11:28:37 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.149 2008/08/06 15:01:23 plunky Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -2570,37 +2570,26 @@
  * ICMPv6 socket option processing.
  */
 int
-icmp6_ctloutput(int op, struct socket *so, int level, 
-	int optname, struct mbuf **mp)
+icmp6_ctloutput(int op, struct socket *so, struct sockopt *sopt)
 {
 	int error = 0;
-	int optlen;
 	struct in6pcb *in6p = sotoin6pcb(so);
-	struct mbuf *m = *mp;
 
-	optlen = m ? m->m_len : 0;
-
-	if (level != IPPROTO_ICMPV6)
-		return rip6_ctloutput(op, so, level, optname, mp);
+	if (sopt->sopt_level != IPPROTO_ICMPV6)
+		return rip6_ctloutput(op, so, sopt);
 
 	switch (op) {
 	case PRCO_SETOPT:
-		switch (optname) {
+		switch (sopt->sopt_name) {
 		case ICMP6_FILTER:
 		    {
-			struct icmp6_filter *p;
+			struct icmp6_filter fil;
 
-			if (optlen != sizeof(*p)) {
-				error = EMSGSIZE;
+			error = sockopt_get(sopt, &fil, sizeof(fil));
+			if (error)
 				break;
-			}
-			p = mtod(m, struct icmp6_filter *);
-			if (!p || !in6p->in6p_icmp6filt) {
-				error = EINVAL;
-				break;
-			}
-			bcopy(p, in6p->in6p_icmp6filt,
-				sizeof(struct icmp6_filter));
+			memcpy(in6p->in6p_icmp6filt, &fil,
+			    sizeof(struct icmp6_filter));
 			error = 0;
 			break;
 		    }
@@ -2609,26 +2598,18 @@
 			error = ENOPROTOOPT;
 			break;
 		}
-		if (m)
-			(void)m_freem(m);
 		break;
 
 	case PRCO_GETOPT:
-		switch (optname) {
+		switch (sopt->sopt_name) {
 		case ICMP6_FILTER:
 		    {
-			struct icmp6_filter *p;
-
-			if (!in6p->in6p_icmp6filt) {
+			if (in6p->in6p_icmp6filt == NULL) {
 				error = EINVAL;
 				break;
 			}
-			*mp = m = m_get(M_WAIT, MT_SOOPTS);
-			m->m_len = sizeof(struct icmp6_filter);
-			p = mtod(m, struct icmp6_filter *);
-			bcopy(in6p->in6p_icmp6filt, p,
-				sizeof(struct icmp6_filter));
-			error = 0;
+			error = sockopt_set(sopt, in6p->in6p_icmp6filt,
+			    sizeof(struct icmp6_filter));
 			break;
 		    }
 
--- a/sys/netinet6/ip6_mroute.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet6/ip6_mroute.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6_mroute.c,v 1.95 2008/06/24 10:35:14 gmcgarry Exp $	*/
+/*	$NetBSD: ip6_mroute.c,v 1.96 2008/08/06 15:01:23 plunky Exp $	*/
 /*	$KAME: ip6_mroute.c,v 1.49 2001/07/25 09:21:18 jinmei Exp $	*/
 
 /*
@@ -117,7 +117,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip6_mroute.c,v 1.95 2008/06/24 10:35:14 gmcgarry Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip6_mroute.c,v 1.96 2008/08/06 15:01:23 plunky Exp $");
 
 #include "opt_inet.h"
 #include "opt_mrouting.h"
@@ -161,7 +161,6 @@
 static void phyint_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
 
 static int set_pim6(int *);
-static int get_pim6(struct mbuf *);
 static int socket_send(struct socket *, struct mbuf *,
 	    struct sockaddr_in6 *);
 static int register_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
@@ -308,65 +307,83 @@
  * Handle MRT setsockopt commands to modify the multicast routing tables.
  */
 int
-ip6_mrouter_set(int cmd, struct socket *so, struct mbuf *m)
+ip6_mrouter_set(struct socket *so, struct sockopt *sopt)
 {
-	if (cmd != MRT6_INIT && so != ip6_mrouter)
+	int error, optval;
+	struct mif6ctl mifc;
+	struct mf6cctl mfcc;
+	mifi_t mifi;
+
+	if (sopt->sopt_name != MRT6_INIT && so != ip6_mrouter)
 		return (EACCES);
 
-	switch (cmd) {
+	error = 0;
+
+	switch (sopt->sopt_name) {
 #ifdef MRT6_OINIT
 	case MRT6_OINIT:
 #endif
 	case MRT6_INIT:
-		if (m == NULL || m->m_len != sizeof(int))
-			return (EINVAL);
-		return (ip6_mrouter_init(so, *mtod(m, int *), cmd));
+		error = sockopt_getint(sopt, &optval);
+		if (error)
+			break;
+		return (ip6_mrouter_init(so, optval, sopt->sopt_name));
 	case MRT6_DONE:
 		return (ip6_mrouter_done());
 	case MRT6_ADD_MIF:
-		if (m == NULL || m->m_len != sizeof(struct mif6ctl))
-			return (EINVAL);
-		return (add_m6if(mtod(m, struct mif6ctl *)));
+		error = sockopt_get(sopt, &mifc, sizeof(mifc));
+		if (error)
+			break;
+		return (add_m6if(&mifc));
 	case MRT6_DEL_MIF:
-		if (m == NULL || m->m_len != sizeof(mifi_t))
-			return (EINVAL);
-		return (del_m6if(mtod(m, mifi_t *)));
+		error = sockopt_get(sopt, &mifi, sizeof(mifi));
+		if (error)
+			break;
+		return (del_m6if(&mifi));
 	case MRT6_ADD_MFC:
-		if (m == NULL || m->m_len != sizeof(struct mf6cctl))
-			return (EINVAL);
-		return (add_m6fc(mtod(m, struct mf6cctl *)));
+		error = sockopt_get(sopt, &mfcc, sizeof(mfcc));
+		if (error)
+			break;
+		return (add_m6fc(&mfcc));
 	case MRT6_DEL_MFC:
-		if (m == NULL || m->m_len != sizeof(struct mf6cctl))
-			return (EINVAL);
-		return (del_m6fc(mtod(m,  struct mf6cctl *)));
+		error = sockopt_get(sopt, &mfcc, sizeof(mfcc));
+		if (error)
+			break;
+		return (del_m6fc(&mfcc));
 	case MRT6_PIM:
-		if (m == NULL || m->m_len != sizeof(int))
-			return (EINVAL);
-		return (set_pim6(mtod(m, int *)));
+		error = sockopt_getint(sopt, &optval);
+		if (error)
+			break;
+		return (set_pim6(&optval));
 	default:
-		return (EOPNOTSUPP);
+		error = EOPNOTSUPP;
 	}
+
+	return (error);
 }
 
 /*
  * Handle MRT getsockopt commands
  */
 int
-ip6_mrouter_get(int cmd, struct socket *so, struct mbuf **m)
+ip6_mrouter_get(struct socket *so, struct sockopt *sopt)
 {
-	struct mbuf *mb;
+	int error;
 
 	if (so != ip6_mrouter) return EACCES;
 
-	*m = mb = m_get(M_WAIT, MT_SOOPTS);
+	error = 0;
 
-	switch (cmd) {
+	switch (sopt->sopt_name) {
 	case MRT6_PIM:
-		return get_pim6(mb);
+		error = sockopt_set(sopt, &pim6, sizeof(pim6));
+		break;
 	default:
-		m_free(mb);
-		return EOPNOTSUPP;
+		error = EOPNOTSUPP;
+		break;
 	}
+
+	return (error);
 }
 
 /*
@@ -430,21 +447,6 @@
 	return 0;
 }
 
-/*
- * Get PIM processiong global
- */
-static int
-get_pim6(struct mbuf *m)
-{
-	int *i;
-
-	i = mtod(m, int *);
-
-	*i = pim6;
-
-	return 0;
-}
-
 static int
 set_pim6(int *i)
 {
--- a/sys/netinet6/ip6_mroute.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet6/ip6_mroute.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6_mroute.h,v 1.14 2008/06/24 10:35:15 gmcgarry Exp $	*/
+/*	$NetBSD: ip6_mroute.h,v 1.15 2008/08/06 15:01:23 plunky Exp $	*/
 /*	$KAME: ip6_mroute.h,v 1.17 2001/02/10 02:05:52 itojun Exp $	*/
 
 /*
@@ -267,8 +267,8 @@
 
 #define MAX_UPQ6	4		/* max. no of pkts in upcall Q */
 
-int	ip6_mrouter_set(int, struct socket *, struct mbuf *);
-int	ip6_mrouter_get(int, struct socket *, struct mbuf **);
+int	ip6_mrouter_set(struct socket *, struct sockopt *);
+int	ip6_mrouter_get(struct socket *, struct sockopt *);
 int	ip6_mrouter_done(void);
 void	ip6_mrouter_detach(struct ifnet *);
 int	mrt6_ioctl(u_long, void *);
--- a/sys/netinet6/ip6_output.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet6/ip6_output.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6_output.c,v 1.129 2008/04/23 06:09:05 thorpej Exp $	*/
+/*	$NetBSD: ip6_output.c,v 1.130 2008/08/06 15:01:23 plunky Exp $	*/
 /*	$KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.129 2008/04/23 06:09:05 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.130 2008/08/06 15:01:23 plunky Exp $");
 
 #include "opt_inet.h"
 #include "opt_inet6.h"
@@ -129,7 +129,7 @@
 
 static int ip6_pcbopt(int, u_char *, int, struct ip6_pktopts **,
 	int, int);
-static int ip6_getpcbopt(struct ip6_pktopts *, int, struct mbuf **);
+static int ip6_getpcbopt(struct ip6_pktopts *, int, struct sockopt *);
 static int ip6_setpktopt(int, u_char *, int, struct ip6_pktopts *, int,
 	int, int, int);
 static int ip6_setmoptions(int, struct ip6_moptions **, struct mbuf *);
@@ -144,8 +144,7 @@
 static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int);
 
 #ifdef RFC2292
-static int ip6_pcbopts(struct ip6_pktopts **, struct mbuf *,
-	struct socket *);
+static int ip6_pcbopts(struct ip6_pktopts **, struct socket *, struct sockopt *);
 #endif
 
 #define	IN6_NEED_CHECKSUM(ifp, csum_flags) \
@@ -1465,26 +1464,26 @@
  * IP6 socket option processing.
  */
 int
-ip6_ctloutput(int op, struct socket *so, int level, int optname,
-    struct mbuf **mp)
+ip6_ctloutput(int op, struct socket *so, struct sockopt *sopt)
 {
 	int privileged, optdatalen, uproto;
 	void *optdata;
 	struct in6pcb *in6p = sotoin6pcb(so);
-	struct mbuf *m = *mp;
 	int error, optval;
-	int optlen;
 	struct lwp *l = curlwp;	/* XXX */
-
-	optlen = m ? m->m_len : 0;
+	int level, optname;
+
+	KASSERT(sopt != NULL);
+
+	level = sopt->sopt_level;
+	optname = sopt->sopt_name;
+
 	error = optval = 0;
 	privileged = (l == 0 || kauth_authorize_generic(l->l_cred,
 	    KAUTH_GENERIC_ISSUSER, NULL)) ? 0 : 1;
 	uproto = (int)so->so_proto->pr_protocol;
 
 	if (level != IPPROTO_IPV6) {
-		if (op == PRCO_SETOPT && *mp)
-			(void)m_free(*mp);
 		return ENOPROTOOPT;
 	}
 	switch (op) {
@@ -1492,9 +1491,7 @@
 		switch (optname) {
 #ifdef RFC2292
 		case IPV6_2292PKTOPTIONS:
-			/* m is freed in ip6_pcbopts */
-			error = ip6_pcbopts(&in6p->in6p_outputopts,
-			    m, so);
+			error = ip6_pcbopts(&in6p->in6p_outputopts, so, sopt);
 			break;
 #endif
 
@@ -1529,13 +1526,10 @@
 		case IPV6_RECVPATHMTU:
 		case IPV6_RECVTCLASS:
 		case IPV6_V6ONLY:
-			if (optlen != sizeof(int)) {
-				error = EINVAL;
+			error = sockopt_getint(sopt, &optval);
+			if (error)
 				break;
-			}
-			optval = *mtod(m, int *);
 			switch (optname) {
-
 			case IPV6_UNICAST_HOPS:
 				if (optval < -1 || optval >= 256)
 					error = EINVAL;
@@ -1703,11 +1697,9 @@
 			struct ip6_pktopts **optp;
 			u_int8_t tclass;
 
-			if (optlen != sizeof(tclass)) {
-				error = EINVAL;
+			error = sockopt_get(sopt, &tclass, sizeof(tclass));
+			if (error)
 				break;
-			}
-			tclass = *mtod(m, u_int8_t *);
 			optp = &in6p->in6p_outputopts;
 			error = ip6_pcbopt(optname,
 					   (u_char *)&tclass,
@@ -1720,11 +1712,9 @@
 		case IPV6_TCLASS:
 		case IPV6_DONTFRAG:
 		case IPV6_USE_MIN_MTU:
-			if (optlen != sizeof(optval)) {
-				error = EINVAL;
+			error = sockopt_getint(sopt, &optval);
+			if (error)
 				break;
-			}
-			optval = *mtod(m, int *);
 			{
 				struct ip6_pktopts **optp;
 				optp = &in6p->in6p_outputopts;
@@ -1743,11 +1733,10 @@
 		case IPV6_2292DSTOPTS:
 		case IPV6_2292RTHDR:
 			/* RFC 2292 */
-			if (optlen != sizeof(int)) {
-				error = EINVAL;
+			error = sockopt_getint(sopt, &optval);
+			if (error)
 				break;
-			}
-			optval = *mtod(m, int *);
+
 			switch (optname) {
 			case IPV6_2292PKTINFO:
 				OPTSET2292(IN6P_PKTINFO);
@@ -1780,16 +1769,11 @@
 		case IPV6_RTHDR:
 		case IPV6_DSTOPTS:
 		case IPV6_RTHDRDSTOPTS:
-		case IPV6_NEXTHOP:
-		{
+		case IPV6_NEXTHOP: {
 			/* new advanced API (RFC3542) */
-			u_char *optbuf;
+			void *optbuf;
 			int optbuflen;
 			struct ip6_pktopts **optp;
-			if (!m) {
-				error = EINVAL;
-				break;
-			}
 
 #ifdef RFC2292
 			/* cannot mix with RFC2292 */
@@ -1799,35 +1783,37 @@
 			}
 #endif
 
-			if (m && m->m_next) {
-				error = EINVAL;	/* XXX */
-				break;
-			}
-
-			optbuf = mtod(m, u_char *);
-			optbuflen = m->m_len;
+			optbuflen = sopt->sopt_size; /* XXX-elad */
+			optbuf = malloc(optbuflen, M_IP6OPT, M_WAITOK);
+			sockopt_get(sopt, optbuf, optbuflen);
 			optp = &in6p->in6p_outputopts;
 			error = ip6_pcbopt(optname, optbuf, optbuflen,
 			    optp, privileged, uproto);
 			break;
-		}
+			}
 #undef OPTSET
 
 		case IPV6_MULTICAST_IF:
 		case IPV6_MULTICAST_HOPS:
 		case IPV6_MULTICAST_LOOP:
 		case IPV6_JOIN_GROUP:
-		case IPV6_LEAVE_GROUP:
+		case IPV6_LEAVE_GROUP: {
+			struct mbuf *m;
+
+			m = sockopt_getmbuf(sopt);
+			if (m == NULL) {
+				error = ENOMEM;
+				break;
+			}
 			error = ip6_setmoptions(optname,
 			    &in6p->in6p_moptions, m);
 			break;
+			}
 
 		case IPV6_PORTRANGE:
-			if (!m) {
-				error = EINVAL;
+			error = sockopt_getint(sopt, &optval);
+			if (error)
 				break;
-			}
-			optval = *mtod(m, int *);
 
 			switch (optval) {
 			case IPV6_PORTRANGE_DEFAULT:
@@ -1854,16 +1840,8 @@
 
 #if defined(IPSEC) || defined(FAST_IPSEC)
 		case IPV6_IPSEC_POLICY:
-		{
-			void *req = NULL;
-			size_t len = 0;
-			if (m) {
-				req = mtod(m, void *);
-				len = m->m_len;
-			}
-			error = ipsec6_set_policy(in6p, optname, req,
-						  len, privileged);
-		}
+			error = ipsec6_set_policy(in6p, optname,
+			    sopt->sopt_data, sopt->sopt_size, privileged);
 			break;
 #endif /* IPSEC */
 
@@ -1871,8 +1849,6 @@
 			error = ENOPROTOOPT;
 			break;
 		}
-		if (m)
-			(void)m_free(m);
 		break;
 
 	case PRCO_GETOPT:
@@ -1888,8 +1864,6 @@
 			 * to simplify this part by always returning
 			 * empty data.
 			 */
-			*mp = m_get(M_WAIT, MT_SOOPTS);
-			(*mp)->m_len = 0;
 			break;
 #endif
 
@@ -1967,9 +1941,7 @@
 			}
 			if (error)
 				break;
-			*mp = m = m_get(M_WAIT, MT_SOOPTS);
-			m->m_len = sizeof(int);
-			*mtod(m, int *) = optval;
+			error = sockopt_setint(sopt, optval);
 			break;
 
 		case IPV6_PATHMTU:
@@ -1998,11 +1970,7 @@
 			optdatalen = sizeof(mtuinfo);
 			if (optdatalen > MCLBYTES)
 				return (EMSGSIZE); /* XXX */
-			*mp = m = m_get(M_WAIT, MT_SOOPTS);
-			if (optdatalen > MLEN)
-				MCLGET(m, M_WAIT);
-			m->m_len = optdatalen;
-			memcpy(mtod(m, void *), optdata, optdatalen);
+			error = sockopt_set(sopt, optdata, optdatalen);
 			break;
 		    }
 
@@ -2029,9 +1997,7 @@
 				optval = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS);
 				break;
 			}
-			*mp = m = m_get(M_WAIT, MT_SOOPTS);
-			m->m_len = sizeof(int);
-			*mtod(m, int *) = optval;
+			error = sockopt_setint(sopt, optval);
 			break;
 #endif
 		case IPV6_PKTINFO:
@@ -2045,35 +2011,38 @@
 		case IPV6_DONTFRAG:
 		case IPV6_USE_MIN_MTU:
 			error = ip6_getpcbopt(in6p->in6p_outputopts,
-			    optname, mp);
+			    optname, sopt);
 			break;
 
 		case IPV6_MULTICAST_IF:
 		case IPV6_MULTICAST_HOPS:
 		case IPV6_MULTICAST_LOOP:
 		case IPV6_JOIN_GROUP:
-		case IPV6_LEAVE_GROUP:
+		case IPV6_LEAVE_GROUP: {
+			struct mbuf *m;
+
 			error = ip6_getmoptions(optname,
-			    in6p->in6p_moptions, mp);
+			    in6p->in6p_moptions, &m);
+			if (!error)
+				error = sockopt_setmbuf(sopt, m);
 			break;
+			}
 
 #if defined(IPSEC) || defined(FAST_IPSEC)
 		case IPV6_IPSEC_POLICY:
 		    {
-			void *req = NULL;
-			size_t len = 0;
-			if (m) {
-				req = mtod(m, void *);
-				len = m->m_len;
-			}
-			error = ipsec6_get_policy(in6p, req, len, mp);
+			struct mbuf *m = NULL;
+
+			/* XXX this will return EINVAL as sopt is empty */
+			error = ipsec6_get_policy(in6p, sopt->sopt_data,
+			    sopt->sopt_size, &m);
+			if (!error)
+				error = sockopt_setmbuf(sopt, m);
+
 			break;
 		    }
 #endif /* IPSEC */
 
-
-
-
 		default:
 			error = ENOPROTOOPT;
 			break;
@@ -2084,19 +2053,19 @@
 }
 
 int
-ip6_raw_ctloutput(int op, struct socket *so, int level, int optname, 
-	struct mbuf **mp)
+ip6_raw_ctloutput(int op, struct socket *so, struct sockopt *sopt)
 {
-	int error = 0, optval, optlen;
+	int error = 0, optval;
 	const int icmp6off = offsetof(struct icmp6_hdr, icmp6_cksum);
 	struct in6pcb *in6p = sotoin6pcb(so);
-	struct mbuf *m = *mp;
-
-	optlen = m ? m->m_len : 0;
+	int level, optname;
+
+	KASSERT(sopt != NULL);
+
+	level = sopt->sopt_level;
+	optname = sopt->sopt_name;
 
 	if (level != IPPROTO_IPV6) {
-		if (op == PRCO_SETOPT && *mp)
-			(void)m_free(*mp);
 		return ENOPROTOOPT;
 	}
 
@@ -2112,11 +2081,9 @@
 		 */
 		switch (op) {
 		case PRCO_SETOPT:
-			if (optlen != sizeof(int)) {
-				error = EINVAL;
+			error = sockopt_getint(sopt, &optval);
+			if (error)
 				break;
-			}
-			optval = *mtod(m, int *);
 			if ((optval % 2) != 0) {
 				/* the API assumes even offset values */
 				error = EINVAL;
@@ -2134,9 +2101,7 @@
 			else
 				optval = in6p->in6p_cksum;
 
-			*mp = m = m_get(M_WAIT, MT_SOOPTS);
-			m->m_len = sizeof(int);
-			*mtod(m, int *) = optval;
+			error = sockopt_setint(sopt, optval);
 			break;
 
 		default:
@@ -2150,9 +2115,6 @@
 		break;
 	}
 
-	if (op == PRCO_SETOPT && m)
-		(void)m_free(m);
-
 	return (error);
 }
 
@@ -2162,9 +2124,11 @@
  * specifying behavior of outgoing packets.
  */
 static int
-ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m, struct socket *so)
+ip6_pcbopts(struct ip6_pktopts **pktopt, struct socket *so,
+    struct sockopt *sopt)
 {
 	struct ip6_pktopts *opt = *pktopt;
+	struct mbuf *m;
 	int error = 0;
 	struct lwp *l = curlwp;	/* XXX */
 	int priv = 0;
@@ -2182,7 +2146,7 @@
 		opt = malloc(sizeof(*opt), M_IP6OPT, M_WAITOK);
 	*pktopt = NULL;
 
-	if (!m || m->m_len == 0) {
+	if (sopt == NULL || sopt->sopt_size == 0) {
 		/*
 		 * Only turning off any previous options, regardless of
 		 * whether the opt is just created or given.
@@ -2195,8 +2159,11 @@
 	if (l && !kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
 	    NULL))
 		priv = 1;
-	if ((error = ip6_setpktopts(m, opt, NULL, priv,
-	    so->so_proto->pr_protocol)) != 0) {
+
+	m = sockopt_getmbuf(sopt);
+	error = ip6_setpktopts(m, opt, NULL, priv, so->so_proto->pr_protocol);
+	m_freem(m);
+	if (error != 0) {
 		ip6_clearpktopts(opt, -1); /* XXX: discard all options */
 		free(opt, M_IP6OPT);
 		return (error);
@@ -2238,7 +2205,7 @@
 }
 
 static int
-ip6_getpcbopt(struct ip6_pktopts *pktopt, int optname, struct mbuf **mp)
+ip6_getpcbopt(struct ip6_pktopts *pktopt, int optname, struct sockopt *sopt)
 {
 	void *optdata = NULL;
 	int optdatalen = 0;
@@ -2247,7 +2214,6 @@
 	struct in6_pktinfo null_pktinfo;
 	int deftclass = 0, on;
 	int defminmtu = IP6PO_MINMTU_MCASTONLY;
-	struct mbuf *m;
 
 	switch (optname) {
 	case IPV6_PKTINFO:
@@ -2326,14 +2292,7 @@
 		return (ENOPROTOOPT);
 	}
 
-	if (optdatalen > MCLBYTES)
-		return (EMSGSIZE); /* XXX */
-	*mp = m = m_get(M_WAIT, MT_SOOPTS);
-	if (optdatalen > MLEN)
-		MCLGET(m, M_WAIT);
-	m->m_len = optdatalen;
-	if (optdatalen)
-		memcpy(mtod(m, void *), optdata, optdatalen);
+	error = sockopt_set(sopt, optdata, optdatalen);
 
 	return (error);
 }
--- a/sys/netinet6/ip6_var.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet6/ip6_var.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6_var.h,v 1.50 2008/04/24 11:38:38 ad Exp $	*/
+/*	$NetBSD: ip6_var.h,v 1.51 2008/08/06 15:01:23 plunky Exp $	*/
 /*	$KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $	*/
 
 /*
@@ -64,6 +64,7 @@
 #ifndef _NETINET6_IP6_VAR_H_
 #define _NETINET6_IP6_VAR_H_
 
+#include <sys/socketvar.h>
 #include <net/route.h>
 
 /*
@@ -307,7 +308,7 @@
 
 struct in6pcb;
 
-int	icmp6_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int	icmp6_ctloutput(int, struct socket *, struct sockopt *);
 
 void	ip6_init(void);
 void	ip6intr(void);
@@ -341,8 +342,8 @@
 			struct route *, int,
 			struct ip6_moptions *, struct socket *,
 			struct ifnet **);
-int	ip6_ctloutput(int, struct socket *, int, int, struct mbuf **);
-int	ip6_raw_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int	ip6_ctloutput(int, struct socket *, struct sockopt *);
+int	ip6_raw_ctloutput(int, struct socket *, struct sockopt *);
 void	ip6_initpktopts(struct ip6_pktopts *);
 int	ip6_setpktopts(struct mbuf *, struct ip6_pktopts *,
 			    struct ip6_pktopts *, int, int);
@@ -368,7 +369,7 @@
 void	rip6_init(void);
 int	rip6_input(struct mbuf **, int *, int);
 void	*rip6_ctlinput(int, const struct sockaddr *, void *);
-int	rip6_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int	rip6_ctloutput(int, struct socket *, struct sockopt *);
 int	rip6_output(struct mbuf *, struct socket *, struct sockaddr_in6 *,
 			 struct mbuf *);
 int	rip6_usrreq(struct socket *,
--- a/sys/netinet6/ip6protosw.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet6/ip6protosw.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6protosw.h,v 1.20 2008/04/24 11:38:38 ad Exp $	*/
+/*	$NetBSD: ip6protosw.h,v 1.21 2008/08/06 15:01:23 plunky Exp $	*/
 /*	$KAME: ip6protosw.h,v 1.22 2001/02/08 18:02:08 itojun Exp $	*/
 
 /*
@@ -126,7 +126,7 @@
 	void	*(*pr_ctlinput)		/* control input (from below) */
 			(int, const struct sockaddr *, void *);
 	int	(*pr_ctloutput)		/* control output (from above) */
-			(int, struct socket *, int, int, struct mbuf **);
+			(int, struct socket *, struct sockopt *);
 
 /* user-protocol hook */
 	int	(*pr_usrreq)		/* user request: see list below */
--- a/sys/netinet6/raw_ip6.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netinet6/raw_ip6.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: raw_ip6.c,v 1.99 2008/05/04 07:22:15 thorpej Exp $	*/
+/*	$NetBSD: raw_ip6.c,v 1.100 2008/08/06 15:01:23 plunky Exp $	*/
 /*	$KAME: raw_ip6.c,v 1.82 2001/07/23 18:57:56 jinmei Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.99 2008/05/04 07:22:15 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.100 2008/08/06 15:01:23 plunky Exp $");
 
 #include "opt_ipsec.h"
 
@@ -562,25 +562,30 @@
  * Raw IPv6 socket option processing.
  */
 int
-rip6_ctloutput(int op, struct socket *so, int level, int optname,
-    struct mbuf **mp)
+rip6_ctloutput(int op, struct socket *so, struct sockopt *sopt)
 {
 	int error = 0;
 
-	if (level == SOL_SOCKET && optname == SO_NOHEADER) {
+	if (sopt->sopt_level == SOL_SOCKET && sopt->sopt_name == SO_NOHEADER) {
+		int optval;
+
 		/* need to fiddle w/ opt(IPPROTO_IPV6, IPV6_CHECKSUM)? */
 		if (op == PRCO_GETOPT) {
-			*mp = m_intopt(so, 1);
-			return 0;
-		} else if (*mp == NULL || (*mp)->m_len != sizeof(int))
-			error = EINVAL;
-		else if (*mtod(*mp, int *) == 0)
-			error = EINVAL;
-		goto free_m;
-	} else if (level != IPPROTO_IPV6)
-		return ip6_ctloutput(op, so, level, optname, mp);
+			optval = 1;
+			error = sockopt_set(sopt, &optval, sizeof(optval));
+		} else if (op == PRCO_SETOPT) {
+			error = sockopt_getint(sopt, &optval);
+			if (error)
+				goto out;
+			if (optval == 0)
+				error = EINVAL;
+		}
 
-	switch (optname) {
+		goto out;
+	} else if (sopt->sopt_level != IPPROTO_IPV6)
+		return ip6_ctloutput(op, so, sopt);
+
+	switch (sopt->sopt_name) {
 	case MRT6_INIT:
 	case MRT6_DONE:
 	case MRT6_ADD_MIF:
@@ -589,20 +594,18 @@
 	case MRT6_DEL_MFC:
 	case MRT6_PIM:
 		if (op == PRCO_SETOPT)
-			error = ip6_mrouter_set(optname, so, *mp);
+			error = ip6_mrouter_set(so, sopt);
 		else if (op == PRCO_GETOPT)
-			error = ip6_mrouter_get(optname, so, mp);
+			error = ip6_mrouter_get(so, sopt);
 		else
 			error = EINVAL;
 		break;
 	case IPV6_CHECKSUM:
-		return ip6_raw_ctloutput(op, so, level, optname, mp);
+		return ip6_raw_ctloutput(op, so, sopt);
 	default:
-		return ip6_ctloutput(op, so, level, optname, mp);
+		return ip6_ctloutput(op, so, sopt);
 	}
-free_m:
-	if (op == PRCO_SETOPT && *mp != NULL)
-		m_free(*mp);
+ out:
 	return error;
 }
 
--- a/sys/netiso/clnp.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netiso/clnp.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: clnp.h,v 1.25 2007/12/25 18:33:48 perry Exp $	*/
+/*	$NetBSD: clnp.h,v 1.26 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993, 1994
@@ -513,7 +513,7 @@
 /* clnp_raw.c */
 void rclnp_input (struct mbuf *, ...);
 int rclnp_output (struct mbuf *, ...);
-int rclnp_ctloutput (int, struct socket *, int, int, struct mbuf **);
+int rclnp_ctloutput (int, struct socket *, struct sockopt *);
 int clnp_usrreq (struct socket *, int, struct mbuf *, struct mbuf *,
 		     struct mbuf *, struct lwp *);
 
--- a/sys/netiso/clnp_raw.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netiso/clnp_raw.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: clnp_raw.c,v 1.29 2008/04/28 13:24:38 ad Exp $	*/
+/*	$NetBSD: clnp_raw.c,v 1.30 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -59,7 +59,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: clnp_raw.c,v 1.29 2008/04/28 13:24:38 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: clnp_raw.c,v 1.30 2008/08/06 15:01:23 plunky Exp $");
 
 #include <sys/param.h>
 #include <sys/mbuf.h>
@@ -185,13 +185,12 @@
  * FUNCTION:		rclnp_ctloutput
  *
  * PURPOSE:			Raw clnp socket option processing
- *					All options are stored inside an mbuf.
+ *				All options are stored inside a sockopt.
  *
  * RETURNS:			success - 0
  *					failure - unix error code
  *
- * SIDE EFFECTS:	If the options mbuf does not exist, it the mbuf passed
- *					is used.
+ * SIDE EFFECTS:
  *
  * NOTES:
  */
@@ -199,9 +198,7 @@
 rclnp_ctloutput(
 	int             op,	/* type of operation */
 	struct socket  *so,	/* ptr to socket */
-	int             level,	/* level of option */
-	int             optname,/* name of option */
-	struct mbuf   **m)	/* ptr to ptr to option data */
+	struct sockopt *sopt)	/* socket options */
 {
 	int             error = 0;
 	struct rawisopcb *rp = sotorawisopcb(so);	/* raw cb ptr */
@@ -209,48 +206,49 @@
 #ifdef ARGO_DEBUG
 	if (argo_debug[D_CTLOUTPUT]) {
 		printf("rclnp_ctloutput: op = x%x, level = x%x, name = x%x\n",
-		    op, level, optname);
-		if (*m != NULL) {
-			printf("rclnp_ctloutput: %d bytes of mbuf data\n", (*m)->m_len);
-			dump_buf(mtod((*m), void *), (*m)->m_len);
-		}
+		    op, sopt->sopt_level, sopt->sopt_name);
+		printf("rclnp_ctloutput: %d bytes of data\n", sopt->sopt_size);
+		dump_buf(sopt->sopt_data, sopt->sopt_size);
 	}
 #endif
 
 #ifdef SOL_NETWORK
-	if (level != SOL_NETWORK)
-		error = EINVAL;
-	else
-		switch (op) {
-#else
+	if (sopt->sopt_level != SOL_NETWORK)
+		return (EINVAL);
+#endif
+
 	switch (op) {
-#endif				/* SOL_NETWORK */
 	case PRCO_SETOPT:
-		switch (optname) {
+		switch (sopt->sopt_name) {
 		case CLNPOPT_FLAGS:{
-				u_short         usr_flags;
-				/*
-				 * Insure that the data passed has exactly
-				 * one short in it
-				 */
-				if ((*m == NULL) || ((*m)->m_len != sizeof(short))) {
-					error = EINVAL;
-					break;
-				}
-				/*
-				 *	Don't allow invalid flags to be set
-				 */
-				usr_flags = (*mtod((*m), short *));
+			u_short flags;
+
+			error = sockopt_get(sopt, &flags, sizeof(flags));
+			if (error)
+				break;
+
+			/*
+			 *	Don't allow invalid flags to be set
+			 */
+			if ((flags & (CLNP_VFLAGS)) != flags)
+				error = EINVAL;
+			else
+				rp->risop_flags |= flags;
 
-				if ((usr_flags & (CLNP_VFLAGS)) != usr_flags) {
-					error = EINVAL;
-				} else
-					rp->risop_flags |= usr_flags;
+			break;
+			}
+
+		case CLNPOPT_OPTS: {
+			struct mbuf *m;
 
-			} break;
+			m = sockopt_getmbuf(sopt);
+			if (m == NULL) {
+				error = ENOBUFS;
+				break;
+			}
 
-		case CLNPOPT_OPTS:
-			error = clnp_set_opts(&rp->risop_isop.isop_options, m);
+			error = clnp_set_opts(&rp->risop_isop.isop_options, &m);
+			m_freem(m);
 			if (error)
 				break;
 			rp->risop_isop.isop_optindex = m_get(M_WAIT, MT_SOOPTS);
@@ -260,13 +258,14 @@
 					  mtod(rp->risop_isop.isop_optindex,
 					       struct clnp_optidx *));
 			break;
+			}
 		}
 		break;
 
 	case PRCO_GETOPT:
 #ifdef notdef
 		/* commented out to keep hi C quiet */
-		switch (optname) {
+		switch (sopt->sopt_name) {
 		default:
 			error = EINVAL;
 			break;
@@ -277,11 +276,6 @@
 		error = EINVAL;
 		break;
 	}
-	if (op == PRCO_SETOPT) {
-		/* note: m_freem does not barf is *m is NULL */
-		m_freem(*m);
-		*m = NULL;
-	}
 	return error;
 }
 
--- a/sys/netiso/tp_output.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netiso/tp_output.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: tp_output.c,v 1.34 2007/11/09 21:00:06 plunky Exp $	*/
+/*	$NetBSD: tp_output.c,v 1.35 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tp_output.c,v 1.34 2007/11/09 21:00:06 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tp_output.c,v 1.35 2008/08/06 15:01:23 plunky Exp $");
 
 #include "opt_inet.h"
 #include "opt_iso.h"
@@ -350,10 +350,11 @@
 }
 
 /*
- * NAME: 	tp_ctloutput()
+ * NAME: 	tp_ctloutput1()
  *
  * CALLED FROM:
  * 	[sg]etsockopt(), via so[sg]etopt().
+ *	via tp_ctloutput() below
  *
  * FUNCTION and ARGUMENTS:
  * 	Implements the socket options at transport level.
@@ -385,8 +386,8 @@
  *
  * NOTES:
  */
-int
-tp_ctloutput(int cmd, struct socket  *so, int level, int optname,
+static int
+tp_ctloutput1(int cmd, struct socket  *so, int level, int optname,
 	struct mbuf **mp)
 {
 	struct lwp *l = curlwp;		/* XXX */
@@ -765,3 +766,40 @@
 	splx(s);
 	return error;
 }
+
+/*
+ * temporary sockopt wrapper, the above needs to be worked through
+ */
+int
+tp_ctloutput(int cmd, struct socket  *so, struct sockopt *sopt)
+{
+	struct mbuf *m;
+	int err;
+
+	switch(cmd) {
+	case PRCO_SETOPT:
+		m = sockopt_getmbuf(sopt);
+		if (m == NULL) {
+			err = ENOMEM;
+			break;
+		}
+
+		err = tp_ctloutput1(cmd, so, sopt->sopt_level, sopt->sopt_name, &m);
+		break;
+
+	case PRCO_GETOPT:
+		m = NULL;
+		err = tp_ctloutput1(cmd, so, sopt->sopt_level, sopt->sopt_name, &m);
+		if (err)
+			break;
+
+		err = sockopt_setmbuf(sopt, m);
+		break;
+
+	default:
+		err = ENOPROTOOPT;
+		break;
+	}
+
+	return err;
+}
--- a/sys/netiso/tp_usrreq.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netiso/tp_usrreq.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: tp_usrreq.c,v 1.36 2008/04/28 13:24:38 ad Exp $	*/
+/*	$NetBSD: tp_usrreq.c,v 1.37 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -65,7 +65,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tp_usrreq.c,v 1.36 2008/04/28 13:24:38 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tp_usrreq.c,v 1.37 2008/08/06 15:01:23 plunky Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -789,6 +789,7 @@
 int
 tp_snd_control(struct mbuf *m, struct socket *so, struct mbuf **data)
 {
+	struct sockopt sopt;
 	struct cmsghdr *ch;
 	int             error = 0;
 
@@ -796,8 +797,13 @@
 		ch = mtod(m, struct cmsghdr *);
 		m->m_len -= sizeof(*ch);
 		m->m_data += sizeof(*ch);
-		error = tp_ctloutput(PRCO_SETOPT,
-				     so, ch->cmsg_level, ch->cmsg_type, &m);
+
+		sockopt_init(&sopt, ch->cmsg_level, ch->cmsg_type, 0);
+		sockopt_setmbuf(&sopt, m);
+		error = tp_ctloutput(PRCO_SETOPT, so, &sopt);
+		sockopt_destroy(&sopt);
+		m = NULL;
+
 		if (ch->cmsg_type == TPOPT_DISC_DATA) {
 			if (data && *data) {
 				m_freem(*data);
--- a/sys/netiso/tp_var.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netiso/tp_var.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: tp_var.h,v 1.17 2008/04/28 20:24:10 martin Exp $	*/
+/*	$NetBSD: tp_var.h,v 1.18 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*-
  * Copyright (c) 1995 The NetBSD Foundation, Inc.
@@ -107,7 +107,7 @@
 
 /* tp_output.c */
 int tp_consistency (struct tp_pcb *, u_int, struct tp_conn_param *);
-int tp_ctloutput (int, struct socket *, int, int, struct mbuf **);
+int tp_ctloutput (int, struct socket *, struct sockopt *);
 
 /* tp_pcb.c */
 void tp_init    (void);
--- a/sys/netsmb/smb_trantcp.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/netsmb/smb_trantcp.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: smb_trantcp.c,v 1.37 2008/06/24 11:20:37 ad Exp $	*/
+/*	$NetBSD: smb_trantcp.c,v 1.38 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: smb_trantcp.c,v 1.37 2008/06/24 11:20:37 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: smb_trantcp.c,v 1.38 2008/08/06 15:01:23 plunky Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -108,7 +108,8 @@
 static int
 nb_setsockopt_int(struct socket *so, int level, int name, int val)
 {
-	return sosetopt(so, level, name, NULL); /* XXX */
+
+	return so_setsockopt(NULL, so, level, name, &val, sizeof(val));	/* XXX */
 }
 
 static int
--- a/sys/nfs/nfs_boot.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/nfs/nfs_boot.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfs_boot.c,v 1.73 2008/05/22 00:57:09 dyoung Exp $	*/
+/*	$NetBSD: nfs_boot.c,v 1.74 2008/08/06 15:01:23 plunky Exp $	*/
 
 /*-
  * Copyright (c) 1995, 1997 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_boot.c,v 1.73 2008/05/22 00:57:09 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_boot.c,v 1.74 2008/08/06 15:01:23 plunky Exp $");
 
 #include "opt_nfs.h"
 #include "opt_tftproot.h"
@@ -335,29 +335,24 @@
 nfs_boot_setrecvtimo(so)
 	struct socket *so;
 {
-	struct mbuf *m;
-	struct timeval *tv;
+	struct timeval tv;
 
-	m = m_get(M_WAIT, MT_SOOPTS);
-	tv = mtod(m, struct timeval *);
-	m->m_len = sizeof(*tv);
-	tv->tv_sec = 1;
-	tv->tv_usec = 0;
-	return (sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m));
+	tv.tv_sec = 1;
+	tv.tv_usec = 0;
+
+	return (so_setsockopt(NULL, so, SOL_SOCKET, SO_RCVTIMEO, &tv,
+	    sizeof(tv)));
 }
 
 int
 nfs_boot_enbroadcast(so)
 	struct socket *so;
 {
-	struct mbuf *m;
-	int32_t *on;
+	int32_t on;
 
-	m = m_get(M_WAIT, MT_SOOPTS);
-	on = mtod(m, int32_t *);
-	m->m_len = sizeof(*on);
-	*on = 1;
-	return (sosetopt(so, SOL_SOCKET, SO_BROADCAST, m));
+	on = 1;
+	return (so_setsockopt(NULL, so, SOL_SOCKET, SO_BROADCAST, &on,
+	    sizeof(on)));
 }
 
 int
--- a/sys/nfs/nfs_bootdhcp.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/nfs/nfs_bootdhcp.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfs_bootdhcp.c,v 1.41 2008/07/20 02:06:37 uwe Exp $	*/
+/*	$NetBSD: nfs_bootdhcp.c,v 1.42 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 1995, 1997 The NetBSD Foundation, Inc.
@@ -44,7 +44,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_bootdhcp.c,v 1.41 2008/07/20 02:06:37 uwe Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_bootdhcp.c,v 1.42 2008/08/06 15:01:24 plunky Exp $");
 
 #include "opt_nfs_boot.h"
 #include "opt_tftproot.h"
@@ -498,13 +498,11 @@
 	 * interface (why?) and then fails because broadcast
 	 * is not supported on that interface...
 	 */
-	{	int32_t *opt;
-		m = m_get(M_WAIT, MT_SOOPTS);
-		opt = mtod(m, int32_t *);
-		m->m_len = sizeof(*opt);
-		*opt = 1;
-		error = sosetopt(so, SOL_SOCKET, SO_DONTROUTE, m);
-		m = NULL;	/* was consumed */
+	{	int32_t opt;
+
+		opt = 1;
+		error = so_setsockopt(NULL, so, SOL_SOCKET, SO_DONTROUTE, &opt,
+		    sizeof(opt));
 	}
 	if (error) {
 		DPRINTF(("bootpc_call: SO_DONTROUTE failed %d\n", error));
@@ -524,13 +522,11 @@
 	 * The "helper-address" feature of some popular router vendor seems
 	 * to do simple IP forwarding and drops packets with (ip_ttl == 1).
 	 */
-	{	u_char *opt;
-		m = m_get(M_WAIT, MT_SOOPTS);
-		opt = mtod(m, u_char *);
-		m->m_len = sizeof(*opt);
-		*opt = 7;
-		error = sosetopt(so, IPPROTO_IP, IP_MULTICAST_TTL, m);
-		m = NULL;	/* was consumed */
+	{	u_char opt;
+
+		opt = 7;
+		error = so_setsockopt(NULL, so, IPPROTO_IP, IP_MULTICAST_TTL,
+		    &opt, sizeof(opt));
 	}
 	if (error) {
 		DPRINTF(("bootpc_call: IP_MULTICAST_TTL failed %d\n", error));
--- a/sys/nfs/nfs_socket.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/nfs/nfs_socket.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfs_socket.c,v 1.170 2008/04/24 11:38:39 ad Exp $	*/
+/*	$NetBSD: nfs_socket.c,v 1.171 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*
  * Copyright (c) 1989, 1991, 1993, 1995
@@ -39,7 +39,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_socket.c,v 1.170 2008/04/24 11:38:39 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_socket.c,v 1.171 2008/08/06 15:01:24 plunky Exp $");
 
 #include "fs_nfs.h"
 #include "opt_nfs.h"
@@ -199,6 +199,7 @@
 	struct sockaddr_in6 *sin6;
 #endif
 	struct mbuf *m;
+	int val;
 
 	nmp->nm_so = (struct socket *)0;
 	saddr = mtod(nmp->nm_nam, struct sockaddr *);
@@ -218,11 +219,10 @@
 	 * Some servers require that the client port be a reserved port number.
 	 */
 	if (saddr->sa_family == AF_INET && (nmp->nm_flag & NFSMNT_RESVPORT)) {
-		m = m_get(M_WAIT, MT_SOOPTS);
-		MCLAIM(m, so->so_mowner);
-		*mtod(m, int32_t *) = IP_PORTRANGE_LOW;
-		m->m_len = sizeof(int32_t);
-		if ((error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, m)))
+		val = IP_PORTRANGE_LOW;
+
+		if ((error = so_setsockopt(NULL, so, IPPROTO_IP, IP_PORTRANGE,
+		    &val, sizeof(val))))
 			goto bad;
 		m = m_get(M_WAIT, MT_SONAME);
 		MCLAIM(m, so->so_mowner);
@@ -238,11 +238,10 @@
 	}
 #ifdef INET6
 	if (saddr->sa_family == AF_INET6 && (nmp->nm_flag & NFSMNT_RESVPORT)) {
-		m = m_get(M_WAIT, MT_SOOPTS);
-		MCLAIM(m, so->so_mowner);
-		*mtod(m, int32_t *) = IPV6_PORTRANGE_LOW;
-		m->m_len = sizeof(int32_t);
-		if ((error = sosetopt(so, IPPROTO_IPV6, IPV6_PORTRANGE, m)))
+		val = IPV6_PORTRANGE_LOW;
+
+		if ((error = so_setsockopt(NULL, so, IPPROTO_IPV6,
+		    IPV6_PORTRANGE, &val, sizeof(val))))
 			goto bad;
 		m = m_get(M_WAIT, MT_SONAME);
 		MCLAIM(m, so->so_mowner);
@@ -322,18 +321,14 @@
 		if (nmp->nm_sotype != SOCK_STREAM)
 			panic("nfscon sotype");
 		if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
-			m = m_get(M_WAIT, MT_SOOPTS);
-			MCLAIM(m, so->so_mowner);
-			*mtod(m, int32_t *) = 1;
-			m->m_len = sizeof(int32_t);
-			sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
+			val = 1;
+			so_setsockopt(NULL, so, SOL_SOCKET, SO_KEEPALIVE, &val,
+			    sizeof(val));
 		}
 		if (so->so_proto->pr_protocol == IPPROTO_TCP) {
-			m = m_get(M_WAIT, MT_SOOPTS);
-			MCLAIM(m, so->so_mowner);
-			*mtod(m, int32_t *) = 1;
-			m->m_len = sizeof(int32_t);
-			sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
+			val = 1;
+			so_setsockopt(NULL, so, IPPROTO_TCP, TCP_NODELAY, &val,
+			    sizeof(val));
 		}
 		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR +
 		    sizeof (u_int32_t)) * 2;
--- a/sys/nfs/nfs_syscalls.c	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/nfs/nfs_syscalls.c	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfs_syscalls.c,v 1.137 2008/06/24 11:18:14 ad Exp $	*/
+/*	$NetBSD: nfs_syscalls.c,v 1.138 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_syscalls.c,v 1.137 2008/06/24 11:18:14 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_syscalls.c,v 1.138 2008/08/06 15:01:24 plunky Exp $");
 
 #include "fs_nfs.h"
 #include "opt_nfs.h"
@@ -392,12 +392,12 @@
 	file_t *fp;
 	struct mbuf *mynam;
 {
-	struct mbuf *m;
 	int siz;
 	struct nfssvc_sock *slp;
 	struct socket *so;
 	struct nfssvc_sock *tslp;
 	int error;
+	int val;
 
 	so = (struct socket *)fp->f_data;
 	tslp = (struct nfssvc_sock *)0;
@@ -442,11 +442,9 @@
 	 * repeatedly for the same socket, but that isn't harmful.
 	 */
 	if (so->so_type == SOCK_STREAM) {
-		m = m_get(M_WAIT, MT_SOOPTS);
-		MCLAIM(m, &nfs_mowner);
-		*mtod(m, int32_t *) = 1;
-		m->m_len = sizeof(int32_t);
-		sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
+		val = 1;
+		so_setsockopt(NULL, so, SOL_SOCKET, SO_KEEPALIVE, &val,
+		    sizeof(val));
 	}
 	if ((so->so_proto->pr_domain->dom_family == AF_INET
 #ifdef INET6
@@ -454,11 +452,9 @@
 #endif
 	    ) &&
 	    so->so_proto->pr_protocol == IPPROTO_TCP) {
-		m = m_get(M_WAIT, MT_SOOPTS);
-		MCLAIM(m, &nfs_mowner);
-		*mtod(m, int32_t *) = 1;
-		m->m_len = sizeof(int32_t);
-		sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
+		val = 1;
+		so_setsockopt(NULL, so, IPPROTO_TCP, TCP_NODELAY, &val,
+		    sizeof(val));
 	}
 	solock(so);
 	so->so_rcv.sb_flags &= ~SB_NOINTR;
--- a/sys/sys/protosw.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/sys/protosw.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: protosw.h,v 1.43 2008/04/24 11:38:39 ad Exp $	*/
+/*	$NetBSD: protosw.h,v 1.44 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 1982, 1986, 1993
@@ -60,6 +60,7 @@
 struct mbuf;
 struct sockaddr;
 struct socket;
+struct sockopt;
 struct domain;
 struct proc;
 struct lwp;
@@ -78,7 +79,7 @@
 	void	*(*pr_ctlinput)		/* control input (from below) */
 			(int, const struct sockaddr *, void *);
 	int	(*pr_ctloutput)		/* control output (from above) */
-			(int, struct socket *, int, int, struct mbuf **);
+			(int, struct socket *, struct sockopt *);
 
 /* user-protocol hook */
 	int	(*pr_usrreq)		/* user request: see list below */
@@ -214,14 +215,9 @@
 
 /*
  * The arguments to ctloutput are:
- *	(*protosw[].pr_ctloutput)(req, so, level, optname, optval);
+ *	(*protosw[].pr_ctloutput)(req, so, sopt);
  * req is one of the actions listed below, so is a (struct socket *),
- * level is an indication of which protocol layer the option is intended.
- * optname is a protocol dependent socket option request,
- * optval is a pointer to a mbuf-chain pointer, for value-return results.
- * The protocol is responsible for disposal of the mbuf chain *optval
- * if supplied,
- * the caller is responsible for any space held by *optval, when returned.
+ * sopt is a (struct sockopt *)
  * A non-zero return from usrreq gives an
  * UNIX error number which should be passed to higher level software.
  */
@@ -281,12 +277,12 @@
 
 #define	PR_WRAP_CTLOUTPUT(name)				\
 static int						\
-name##_wrapper(int a, struct socket *b, int c, int d,	\
-     struct mbuf **e)					\
+name##_wrapper(int a, struct socket *b,			\
+    struct sockopt *c)					\
 {							\
 	int rv;						\
 	KERNEL_LOCK(1, NULL);				\
-	rv = name(a, b, c, d, e);			\
+	rv = name(a, b, c);				\
 	KERNEL_UNLOCK_ONE(NULL);			\
 	return rv;					\
 }
--- a/sys/sys/socketvar.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/sys/socketvar.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: socketvar.h,v 1.112 2008/08/04 03:55:48 tls Exp $	*/
+/*	$NetBSD: socketvar.h,v 1.113 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -219,6 +219,14 @@
 	SLIST_ENTRY(accept_filter) accf_next;
 };
 
+struct sockopt {
+	int		sopt_level;		/* option level */
+	int		sopt_name;		/* option name */
+	size_t		sopt_size;		/* data length */
+	void *		sopt_data;		/* data pointer */
+	uint8_t		sopt_buf[sizeof(int)];	/* internal storage */
+};
+
 extern u_long		sb_max;
 extern int		somaxkva;
 extern int		sock_loan_thresh;
@@ -231,7 +239,6 @@
 struct stat;
 struct knote;
 
-struct	mbuf *m_intopt(struct socket *, int);
 struct	mbuf *getsombuf(struct socket *, int);
 
 /*
@@ -280,7 +287,7 @@
 int	fsocreate(int, struct socket **, int, int, struct lwp *, int *);
 int	sodisconnect(struct socket *);
 void	sofree(struct socket *);
-int	sogetopt(struct socket *, int, int, struct mbuf **);
+int	sogetopt(struct socket *, struct sockopt *);
 void	sohasoutofband(struct socket *);
 void	soisconnected(struct socket *);
 void	soisconnecting(struct socket *);
@@ -297,7 +304,8 @@
 void	sorflush(struct socket *);
 int	sosend(struct socket *, struct mbuf *, struct uio *,
 	    struct mbuf *, struct mbuf *, int, struct lwp *);
-int	sosetopt(struct socket *, int, int, struct mbuf *);
+int	sosetopt(struct socket *, struct sockopt *);
+int	so_setsockopt(struct lwp *, struct socket *, int, int, const void *, size_t);
 int	soshutdown(struct socket *, int);
 void	sowakeup(struct socket *, struct sockbuf *, int);
 int	sockargs(struct mbuf **, const void *, size_t, int);
@@ -313,6 +321,15 @@
 void	sosetlock(struct socket *);
 void	solockreset(struct socket *, kmutex_t *);
 
+void	sockopt_init(struct sockopt *, int, int, size_t);
+void	sockopt_destroy(struct sockopt *);
+int	sockopt_set(struct sockopt *, const void *, size_t);
+int	sockopt_setint(struct sockopt *, int);
+int	sockopt_get(const struct sockopt *, void *, size_t);
+int	sockopt_getint(const struct sockopt *, int *);
+int	sockopt_setmbuf(struct sockopt *, struct mbuf *);
+struct mbuf *sockopt_getmbuf(const struct sockopt *);
+
 int	copyout_sockname(struct sockaddr *, unsigned int *, int, struct mbuf *);
 int	copyout_msg_control(struct lwp *, struct msghdr *, struct mbuf *);
 void	free_control_mbuf(struct lwp *, struct mbuf *, struct mbuf *);
@@ -512,8 +529,8 @@
 /*
  * Accept filter functions (duh).
  */
-int	do_getopt_accept_filter(struct socket *, struct mbuf *);
-int	do_setopt_accept_filter(struct socket *, struct mbuf *);
+int	do_getopt_accept_filter(struct socket *, struct sockopt *);
+int	do_setopt_accept_filter(struct socket *, const struct sockopt *);
 int	accept_filt_add(struct accept_filter *);
 int	accept_filt_del(char *);
 struct	accept_filter *accept_filt_get(char *);
--- a/sys/sys/un.h	Wed Aug 06 14:21:33 2008 +0000
+++ b/sys/sys/un.h	Wed Aug 06 15:01:23 2008 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: un.h,v 1.43 2008/04/24 11:38:39 ad Exp $	*/
+/*	$NetBSD: un.h,v 1.44 2008/08/06 15:01:24 plunky Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1993
@@ -73,10 +73,11 @@
 #ifdef _KERNEL
 struct unpcb;
 struct socket;
+struct sockopt;
 
 int	uipc_usrreq(struct socket *, int, struct mbuf *,
 	    struct mbuf *, struct mbuf *, struct lwp *);
-int	uipc_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int	uipc_ctloutput(int, struct socket *, struct sockopt *);
 void	uipc_init (void);
 kmutex_t *uipc_dgramlock (void);
 kmutex_t *uipc_streamlock (void);