Index: compat/linux/common/linux_socket.c
===================================================================
RCS file: /usr/cvs/src/sys/compat/linux/common/linux_socket.c,v
retrieving revision 1.85
diff -u -p -r1.85 linux_socket.c
--- compat/linux/common/linux_socket.c	20 Dec 2007 23:02:56 -0000	1.85
+++ compat/linux/common/linux_socket.c	21 Dec 2007 00:03:29 -0000
@@ -323,15 +323,12 @@ linux_sys_socket(struct lwp *l, const st
 		struct file *fp;
 
 		if (getsock(p->p_fd, *retval, &fp) == 0) {
-			struct mbuf *m;
-
-			m = m_get(M_WAIT, MT_SOOPTS);
-			m->m_len = sizeof(int);
-			*mtod(m, int *) = 0;
+			int val;
 
 			/* ignore error */
-			(void) sosetopt((struct socket *)fp->f_data,
-				IPPROTO_IPV6, IPV6_V6ONLY, m);
+			val = 0;
+			(void)so_setsockopt(l, (struct socket *)fp->f_data,
+			    IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
 
 			FILE_UNUSE(fp, l);
 		}
Index: kern/uipc_socket.c
===================================================================
RCS file: /usr/cvs/src/sys/kern/uipc_socket.c,v
retrieving revision 1.150
diff -u -p -r1.150 uipc_socket.c
--- kern/uipc_socket.c	16 Dec 2007 21:25:59 -0000	1.150
+++ kern/uipc_socket.c	29 Dec 2007 12:49:07 -0000
@@ -1457,20 +1457,187 @@ sorflush(struct socket *so)
 	sbrelease(&asb, so);
 }
 
+void
+sockopt_destroy(struct sockopt *sopt)
+{
+	if (sopt->sopt_m != NULL) {
+		m_freem(sopt->sopt_m);
+		sopt->sopt_m = NULL;
+		sopt->sopt_un = NULL;
+	} else if (sopt->sopt_un != NULL) {
+		free(sopt->sopt_un, M_SOOPTS);
+		sopt->sopt_un = NULL;
+	}
+}
+
+static int
+sockopt_ensure_writable(struct sockopt *sopt, size_t len)
+{
+#if 0
+	/* check role */
+	if (sopt->sopt_dir != SOPT_SET) {
+		return ENOMEM;
+	}
+#endif
+
+	/* do not overwrite shared storage */
+	if (sopt->sopt_m != NULL) {
+		m_freem(sopt->sopt_m);
+		sopt->sopt_m = NULL;
+		sopt->sopt_un = NULL;
+	}
+
+	if (sopt->sopt_un != NULL && sopt->sopt_size >= len)
+		return 0;
+
+	if (sopt->sopt_un != NULL)
+		free(sopt->sopt_un, M_SOOPTS);
+
+	sopt->sopt_un = malloc(len, M_SOOPTS,
+	    sopt->sopt_waitok ? M_WAITOK : M_NOWAIT);
+
+	if (sopt->sopt_un == NULL)
+		return ENOMEM;
+
+	sopt->sopt_size = len;
+
+	return 0;
+}
+
+int
+sockopt_set(struct sockopt *sopt, const void *buf, size_t len)
+{
+	int rc;
+
+	if ((rc = sockopt_ensure_writable(sopt, len)) != 0)
+		return rc;
+
+	KASSERT(sopt->sopt_size >= len);
+
+	memcpy(sopt->sopt_un, buf, len);
+	sopt->sopt_size = len;
+
+	return 0;
+}
+
+int
+sockopt_setint(struct sockopt *sopt, int val)
+{
+	const int len = sizeof(int);
+	int rc;
+
+	if ((rc = sockopt_ensure_writable(sopt, len)) != 0)
+		return rc;
+
+	sopt->sopt_un->un_int = val;
+	sopt->sopt_size = len;
+
+	return 0;
+}
+
+void *
+sockopt_get(const struct sockopt *sopt, size_t len)
+{
+	if (sopt->sopt_un == NULL || sopt->sopt_size != len)
+		return NULL;
+
+	return (void *)sopt->sopt_un;
+}
+
+int *
+sockopt_getintptr(const struct sockopt *sopt)
+{
+	if (sopt->sopt_un == NULL || sopt->sopt_size != sizeof(int))
+		return NULL;
+
+	return &sopt->sopt_un->un_int;
+}
+
+struct mbuf *
+sockopt_getmbuf(const struct sockopt *sopt)
+{
+	struct mbuf *m;
+	struct sockopt *p;
+	int waitok;
+
+#if 0
+	/* check role */
+	if (sopt->sopt_dir != SOPT_SET) {
+		return NULL;
+#endif
+
+	waitok = sopt->sopt_waitok ? M_WAIT : M_DONTWAIT;
+
+	if (sopt->sopt_m != NULL)
+		goto out;
+
+	m = m_get(waitok, MT_SOOPTS);
+
+	if (m == NULL)
+		return NULL;
+
+	MEXTADD(m, sopt->sopt_un, sopt->sopt_size, M_SOOPTS, NULL, NULL);
+
+	if ((m->m_flags & M_EXT) == 0) {
+		m_freem(m);
+		return NULL;
+	}
+
+	p = __UNCONST(sopt);
+	p->sopt_m = m;
+
+out:
+	return m_copym(sopt->sopt_m, 0, M_COPYALL, waitok);
+}
+
+int
+sockopt_setmbuf(struct sockopt *sopt, struct mbuf *m)
+{
+	int rc;
+	u_int len;
+
+	len = m_length(m);
+
+	if (!M_UNWRITABLE(m, len)) {
+		if (sopt->sopt_m != NULL)
+			m_freem(sopt->sopt_m);
+		else if (sopt->sopt_un != NULL)
+			free(sopt->sopt_un, M_SOOPTS);
+		sopt->sopt_m = m;
+		sopt->sopt_un = mtod(m, union sopt_union *);
+		sopt->sopt_size = len;
+		return 0;
+	}
+
+	if ((rc = sockopt_ensure_writable(sopt, len)) != 0)
+		goto out;
+
+	m_copydata(m, 0, len, sopt->sopt_un);
+	sopt->sopt_size = len;
+
+out:
+	m_freem(m);
+	return rc;
+}
+
 static int
-sosetopt1(struct socket *so, int level, int optname, struct mbuf *m)
+sosetopt1(struct socket *so, struct sockopt *sopt)
 {
 	int optval, val;
-	struct linger	*l;
-	struct sockbuf	*sb;
+	struct linger *l;
+	struct sockbuf *sb;
 	struct timeval *tv;
+	void *v;
 
-	switch (optname) {
+	if (sopt == NULL)
+		return (EINVAL);
 
+	switch (sopt->sopt_name) {
 	case SO_LINGER:
-		if (m == NULL || m->m_len != sizeof(struct linger))
-			return EINVAL;
-		l = mtod(m, struct linger *);
+		l = sockopt_get(sopt, sizeof(*l));
+		if (l == NULL)
+			return (EINVAL);
+
 		if (l->l_linger < 0 || l->l_linger > USHRT_MAX ||
 		    l->l_linger > (INT_MAX / hz))
 			return EDOM;
@@ -1490,34 +1657,40 @@ sosetopt1(struct socket *so, int level, 
 	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;
+		v = sockopt_getintptr(sopt);
+		if (v == NULL)
+			return (EINVAL);
+
+		optval = *((int *)v);
+
+		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;
+		v = sockopt_getintptr(sopt);
+		if (v == NULL)
+			return (EINVAL);
+
+		optval = *((int *)v);
 
 		/*
 		 * 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:
 		case SO_RCVBUF:
-			sb = (optname == SO_SNDBUF) ?
+			sb = (sopt->sopt_name == SO_SNDBUF) ?
 			    &so->so_snd : &so->so_rcv;
 			if (sbreserve(sb, (u_long)optval, so) == 0)
 				return ENOBUFS;
@@ -1543,17 +1716,17 @@ sosetopt1(struct socket *so, int level, 
 
 	case SO_SNDTIMEO:
 	case SO_RCVTIMEO:
-		if (m == NULL || m->m_len < sizeof(*tv))
-			return EINVAL;
-		tv = mtod(m, struct timeval *);
+		tv = sockopt_get(sopt, sizeof(*tv));
+		if (tv == NULL)
+			return (EINVAL);
+
 		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) {
-
+		switch (sopt->sopt_name) {
 		case SO_SNDTIMEO:
 			so->so_snd.sb_timeo = val;
 			break;
@@ -1570,52 +1743,76 @@ sosetopt1(struct socket *so, int level, 
 }
 
 int
-sosetopt(struct socket *so, int level, int optname, struct mbuf *m)
+sosetopt(struct socket *so, struct sockopt *sopt)
 {
 	int error, prerr;
 
-	if (level == SOL_SOCKET)
-		error = sosetopt1(so, level, optname, m);
+	if (sopt == NULL)
+		return (EINVAL);
+
+	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)(so, sopt);
 		if (prerr == 0)
 			error = 0;
 		else if (prerr != ENOPROTOOPT)
 			error = prerr;
-	} else if (m != NULL)
-		(void)m_free(m);
+	}
 	return error;
 }
 
 int
-sogetopt(struct socket *so, int level, int optname, struct mbuf **mp)
+so_setsockopt(struct lwp *l, struct socket *so, int level, int name, void *val,
+    socklen_t valsize)
 {
-	struct mbuf	*m;
+	struct sockopt sopt;
+
+	/*if (val == NULL && valsize != 0)
+		return (EFAULT);
+	if ((int)valsize < 0 || (int)valsize > sizeof(sopt.sopt_val))
+		return (EINVAL);*/
+
+	memset(&sopt, 0, sizeof(sopt));
+	sopt.sopt_dir = SOPT_SET;
+	sopt.sopt_level = level;
+	sopt.sopt_name = name;
+	/* memcpy(sopt.sopt_val, val, valsize);
+	sopt.sopt_valsize = valsize; */
+	sockopt_set(&sopt, val, valsize);
+	sopt.sopt_lwp = l;
+
+	return (sosetopt(so, &sopt));
+}
 
-	if (level != SOL_SOCKET) {
+int
+sogetopt(struct socket *so, struct sockopt *sopt)
+{
+	int error = 0;
+	int optval;
+
+	if (sopt->sopt_level != SOL_SOCKET) {
 		if (so->so_proto && so->so_proto->pr_ctloutput) {
-			return ((*so->so_proto->pr_ctloutput)
-				  (PRCO_GETOPT, so, level, optname, mp));
+			return ((*so->so_proto->pr_ctloutput)(so, sopt));
 		} else
 			return (ENOPROTOOPT);
 	} else {
-		m = m_get(M_WAIT, MT_SOOPTS);
-		m->m_len = sizeof(int);
+		switch (sopt->sopt_name) {
 
-		switch (optname) {
+		case SO_LINGER: {
+			struct linger lgr;
 
-		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;
+			lgr.l_onoff = (so->so_options & SO_LINGER) ? 1 : 0;
+			lgr.l_linger = so->so_linger;
+
+			error = sockopt_set(sopt, &lgr, sizeof(lgr));
 			break;
+			}
 
 		case SO_USELOOPBACK:
 		case SO_DONTROUTE:
@@ -1626,57 +1823,60 @@ sogetopt(struct socket *so, int level, i
 		case SO_BROADCAST:
 		case SO_OOBINLINE:
 		case SO_TIMESTAMP:
-			*mtod(m, int *) = (so->so_options & optname) ? 1 : 0;
+			optval = so->so_options & sopt->sopt_name;
+
+ integer:
+			error = sockopt_set(sopt, &optval, sizeof optval);
 			break;
 
 		case SO_TYPE:
-			*mtod(m, int *) = so->so_type;
-			break;
+			optval = so->so_type;
+			goto integer;
 
 		case SO_ERROR:
-			*mtod(m, int *) = so->so_error;
+			optval = so->so_error;
 			so->so_error = 0;
-			break;
+			goto integer;
 
 		case SO_SNDBUF:
-			*mtod(m, int *) = so->so_snd.sb_hiwat;
-			break;
+			optval = so->so_snd.sb_hiwat;
+			goto integer;
 
 		case SO_RCVBUF:
-			*mtod(m, int *) = so->so_rcv.sb_hiwat;
-			break;
+			optval = so->so_rcv.sb_hiwat;
+			goto integer;
 
 		case SO_SNDLOWAT:
-			*mtod(m, int *) = so->so_snd.sb_lowat;
-			break;
+			optval = so->so_snd.sb_lowat;
+			goto integer;
 
 		case SO_RCVLOWAT:
-			*mtod(m, int *) = so->so_rcv.sb_lowat;
-			break;
+			optval = so->so_rcv.sb_lowat;
+			goto integer;
 
 		case SO_SNDTIMEO:
-		case SO_RCVTIMEO:
-		    {
-			int val = (optname == SO_SNDTIMEO ?
+		case SO_RCVTIMEO: {
+			struct timeval tv;
+
+			optval = (sopt->sopt_name == 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;
+			tv.tv_sec = optval / hz;
+			tv.tv_usec = (optval % hz) * tick;
+
+			error = sockopt_set(sopt, &tv, sizeof(tv));
 			break;
-		    }
+			}
 
 		case SO_OVERFLOWED:
-			*mtod(m, int *) = so->so_rcv.sb_overflowed;
-			break;
+			optval = so->so_rcv.sb_overflowed;
+			goto integer;
 
 		default:
-			(void)m_free(m);
-			return (ENOPROTOOPT);
+			error = ENOPROTOOPT;
+			break;
 		}
-		*mp = m;
-		return (0);
+		return (error);
 	}
 }
 
Index: kern/uipc_syscalls.c
===================================================================
RCS file: /usr/cvs/src/sys/kern/uipc_syscalls.c,v
retrieving revision 1.126
diff -u -p -r1.126 uipc_syscalls.c
--- kern/uipc_syscalls.c	26 Dec 2007 16:01:37 -0000	1.126
+++ kern/uipc_syscalls.c	29 Dec 2007 15:45:46 -0000
@@ -882,38 +882,42 @@ sys_setsockopt(struct lwp *l, const stru
 		syscallarg(const void *)	val;
 		syscallarg(unsigned int)	valsize;
 	} */
-	struct proc	*p;
 	struct file	*fp;
-	struct mbuf	*m;
-	struct socket	*so;
 	int		error;
-	unsigned int	len;
+	void *lbuf = NULL;
+	struct sockopt sopt;
+
+	/* Sanity. */
+	if (SCARG(uap, valsize) > MCLBYTES)
+		return (EINVAL);
+
+	lbuf = kmem_zalloc(MCLBYTES, KM_SLEEP);
+
+	memset(&sopt, 0, sizeof(sopt));
+	sopt.sopt_dir = SOPT_SET;
+	error = copyin(SCARG(uap, val), lbuf, SCARG(uap, valsize));
+	if (error)
+		goto out;
+	sopt.sopt_level = SCARG(uap, level);
+	sopt.sopt_name = SCARG(uap, name);
+	sopt.sopt_lwp = l;
+	sopt.sopt_waitok = 1;
+	error = sockopt_set(&sopt, lbuf, SCARG(uap, valsize));
+	if (error)
+		goto out;
 
-	p = l->l_proc;
-	m = NULL;
 	/* getsock() will use the descriptor for us */
-	if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0)
-		return (error);
-	so = (struct socket *)fp->f_data;
-	len = SCARG(uap, valsize);
-	if (len > MCLBYTES) {
-		error = EINVAL;
+	error = getsock(l->l_proc->p_fd, SCARG(uap, s), &fp);
+	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);
- out:
+
+	error = sosetopt((struct socket *)fp->f_data, &sopt);
+
 	FILE_UNUSE(fp, l);
+	
+ out:
+	sockopt_destroy(&sopt);
+	kmem_free(lbuf, MCLBYTES);
 	return (error);
 }
 
@@ -929,41 +933,48 @@ sys_getsockopt(struct lwp *l, const stru
 		syscallarg(unsigned int *)	avalsize;
 	} */
 	struct file	*fp;
-	struct mbuf	*m;
-	unsigned int	op, i, valsize;
 	int		error;
-	char *val = SCARG(uap, val);
+	void *lbuf;
+	unsigned int valsize;
+	struct sockopt sopt;
 
-	m = NULL;
 	/* getsock() will use the descriptor for us */
-	if ((error = getsock(l->l_proc->p_fd, SCARG(uap, s), &fp)) != 0)
+	error = getsock(l->l_proc->p_fd, SCARG(uap, s), &fp);
+	if (error)
 		return (error);
-	if (val != NULL) {
-		error = copyin(SCARG(uap, avalsize),
-			       &valsize, sizeof(valsize));
+
+	memset(&sopt, 0, sizeof(sopt));
+	sopt.sopt_dir = SOPT_GET;
+	sopt.sopt_level = SCARG(uap, level);
+	sopt.sopt_name = SCARG(uap, name);
+	if (SCARG(uap, val) != NULL) {
+		error = copyin(SCARG(uap, avalsize), &valsize,
+		    sizeof(valsize));
 		if (error)
 			goto out;
 	} else
 		valsize = 0;
-	if ((error = sogetopt((struct socket *)fp->f_data, SCARG(uap, level),
-	    SCARG(uap, name), &m)) == 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));
+	sopt.sopt_waitok = 1;
+	sopt.sopt_lwp = l;
+
+	error = sogetopt((struct socket *)fp->f_data, &sopt);
+	if (error)
+		goto out;
+
+	lbuf = sopt.sopt_un;
+	if ((SCARG(uap, val) != NULL) && (valsize != 0)) {
+		unsigned int copylen = min(valsize, sopt.sopt_size);
+
+		error = copyout(lbuf, SCARG(uap, val), copylen);
+		if (error)
+			goto out;
+
+		error = copyout(&copylen, SCARG(uap, avalsize),
+		    sizeof(copylen));
 	}
-	if (m != NULL)
-		(void) m_freem(m);
+
  out:
+	sockopt_destroy(&sopt);
 	FILE_UNUSE(fp, l);
 	return (error);
 }
Index: kern/uipc_usrreq.c
===================================================================
RCS file: /usr/cvs/src/sys/kern/uipc_usrreq.c,v
retrieving revision 1.104
diff -u -p -r1.104 uipc_usrreq.c
--- kern/uipc_usrreq.c	5 Jan 2008 19:08:49 -0000	1.104
+++ kern/uipc_usrreq.c	7 Jan 2008 19:31:13 -0000
@@ -451,72 +451,65 @@ release:
  * Unix domain socket option processing.
  */
 int
-uipc_ctloutput(int op, struct socket *so, int level, int optname,
-	struct mbuf **mp)
+uipc_ctloutput(struct socket *so, struct sockopt *sopt)
 {
 	struct unpcb *unp = sotounpcb(so);
-	struct mbuf *m = *mp;
 	int optval = 0, error = 0;
+	void *v;
 
-	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) {
+	} else switch (sopt->sopt_dir) {
+	case SOPT_SET:
+		switch (sopt->sopt_name) {
 		case LOCAL_CREDS:
 		case LOCAL_CONNWAIT:
-			if (m == NULL || m->m_len != sizeof(int))
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
 				error = EINVAL;
-			else {
-				optval = *mtod(m, int *);
-				switch (optname) {
+				break;
+			}
+			optval = *((int *)v);
+			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;
+		break;
 #undef OPTSET
 
 		default:
 			error = ENOPROTOOPT;
 			break;
 		}
-		if (m)
-			(void) m_free(m);
 		break;
 
-	case PRCO_GETOPT:
-		switch (optname) {
+	case SOPT_GET:
+		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;
+				struct unpcbid peerid;
+
+				peerid = unp->unp_connid;
+				error = sockopt_set(sopt, &peerid, sizeof(peerid));
 			} 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_set(sopt, &optval, sizeof(optval));
 			break;
 #undef OPTBIT
 
Index: net/if_gre.c
===================================================================
RCS file: /usr/cvs/src/sys/net/if_gre.c,v
retrieving revision 1.122
diff -u -p -r1.122 if_gre.c
--- net/if_gre.c	20 Dec 2007 18:12:11 -0000	1.122
+++ net/if_gre.c	21 Dec 2007 00:04:04 -0000
@@ -466,6 +466,7 @@ gre_socreate(struct gre_softc *sc, struc
 	struct sockaddr *sa;
 	sa_family_t af;
 	struct socket *so;
+	int val;
 
 	GRE_DPRINTF(sc, "%s: enter\n", __func__);
 
@@ -509,19 +510,18 @@ gre_socreate(struct gre_softc *sc, struc
 	}
 
 	/* 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;
+	rc = so_setsockopt(l, so, IPPROTO_IP, IP_TTL, &ip_gre_ttl, sizeof(ip_gre_ttl));
 	if (rc != 0) {
-		GRE_DPRINTF(sc, "%s: sosetopt ttl failed\n", __func__);
+		GRE_DPRINTF(sc, "%s: so_setsockopt ttl failed\n", __func__);
 		rc = 0;
 	}
-	rc = sosetopt(so, SOL_SOCKET, SO_NOHEADER, m_intopt(so, 1));
+	val = 1;
+	rc = so_setsockopt(l, so, SOL_SOCKET, SO_NOHEADER, &val, sizeof(val));
 	if (rc != 0) {
-		GRE_DPRINTF(sc, "%s: sosetopt SO_NOHEADER failed\n", __func__);
+		GRE_DPRINTF(sc, "%s: so_setsockopt SO_NOHEADER failed\n",
+		    __func__);
 		rc = 0;
 	}
 out:
@@ -1259,7 +1259,7 @@ gre_ioctl(struct ifnet *ifp, const u_lon
 	case SIOCSLIFPHYADDR:
 	case SIOCDIFPHYADDR:
 		if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_INTERFACE,
-		    KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
+		    KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, KAUTH_ARG(cmd),
 		    NULL) != 0)
 			return EPERM;
 		break;
Index: netbt/hci.h
===================================================================
RCS file: /usr/cvs/src/sys/netbt/hci.h,v
retrieving revision 1.21
diff -u -p -r1.21 hci.h
--- netbt/hci.h	30 Dec 2007 18:26:42 -0000	1.21
+++ netbt/hci.h	2 Jan 2008 12:43:08 -0000
@@ -74,6 +74,7 @@
 #ifndef _NETBT_HCI_H_
 #define _NETBT_HCI_H_
 
+#include <sys/socketvar.h>
 #include <netbt/bluetooth.h>
 
 /**************************************************************************
@@ -2208,7 +2209,7 @@ void hci_memo_free(struct hci_memo *);
 /* 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(struct socket *, struct sockopt *);
 void hci_mtap(struct mbuf *, struct hci_unit *);
 
 /* hci_unit.c */
Index: netbt/hci_socket.c
===================================================================
RCS file: /usr/cvs/src/sys/netbt/hci_socket.c,v
retrieving revision 1.13
diff -u -p -r1.13 hci_socket.c
--- netbt/hci_socket.c	30 Dec 2007 18:26:42 -0000	1.13
+++ netbt/hci_socket.c	2 Jan 2008 12:43:08 -0000
@@ -697,14 +697,19 @@ release:
  * get/set socket options
  */
 int
-hci_ctloutput(int req, struct socket *so, int level,
-		int optname, struct mbuf **opt)
+hci_ctloutput(struct socket *so, struct sockopt *sopt)
 {
 	struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
-	struct mbuf *m;
 	int err = 0;
+	int req, level, optname, optval;
+	struct hci_filter *hcifil;
+	void *v;
+
+	req = sopt->sopt_dir;
+	level = sopt->sopt_level;
+	optname = sopt->sopt_name;
 
-	DPRINTFN(2, "req %s\n", prcorequests[req]);
+	DPRINTFN(2, "req %s\n", (req == SOPT_SET) ? "SET" : "GET");
 
 	if (pcb == NULL)
 		return EINVAL;
@@ -713,51 +718,60 @@ hci_ctloutput(int req, struct socket *so
 		return ENOPROTOOPT;
 
 	switch(req) {
-	case PRCO_GETOPT:
-		m = m_get(M_WAIT, MT_SOOPTS);
+	case SOPT_GET:
 		switch (optname) {
 		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;
+				optval = 1;
 			else
-				*mtod(m, int *) = 0;
+				optval = 0;
+			err = sockopt_set(sopt, &optval, sizeof(optval));
 			break;
 
 		default:
 			err = ENOPROTOOPT;
-			m_freem(m);
-			m = NULL;
 			break;
 		}
-		*opt = m;
 		break;
 
-	case PRCO_SETOPT:
-		m = *opt;
-		if (m) switch (optname) {
+	case SOPT_SET:
+		switch (optname) {
 		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);
+			hcifil = sockopt_get(sopt, sizeof(*hcifil));
+			if (hcifil == NULL) {
+				err = EINVAL;
+				break;
+			}
+			memcpy(&pcb->hp_efilter, hcifil, sizeof(*hcifil));
 			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);
+			hcifil = sockopt_get(sopt, sizeof(*hcifil));
+			if (hcifil == NULL) {
+				err = EINVAL;
+				break;
+			}
+			memcpy(&pcb->hp_pfilter, hcifil, sizeof(*hcifil));
 			break;
 
 		case SO_HCI_DIRECTION:	/* request direction ctl messages */
-			if (*mtod(m, int *))
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
+				err = EINVAL;
+				break;
+			}
+			optval = *((int *)v);
+			if (optval)
 				pcb->hp_flags |= HCI_DIRECTION;
 			else
 				pcb->hp_flags &= ~HCI_DIRECTION;
@@ -767,7 +781,6 @@ hci_ctloutput(int req, struct socket *so
 			err = ENOPROTOOPT;
 			break;
 		}
-		m_freem(m);
 		break;
 
 	default:
Index: netbt/l2cap.h
===================================================================
RCS file: /usr/cvs/src/sys/netbt/l2cap.h,v
retrieving revision 1.6
diff -u -p -r1.6 l2cap.h
--- netbt/l2cap.h	3 Nov 2007 17:20:17 -0000	1.6
+++ netbt/l2cap.h	21 Dec 2007 00:27:29 -0000
@@ -70,6 +70,7 @@
 #define _NETBT_L2CAP_H_
 
 #include <sys/types.h>
+#include <sys/socketvar.h>
 
 /**************************************************************************
  **************************************************************************
@@ -464,7 +465,7 @@ int l2cap_send_connect_rsp(struct hci_li
 
 /* 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(struct socket *, struct sockopt *);
 
 /* l2cap_upper.c */
 int l2cap_attach(struct l2cap_channel **, const struct btproto *, void *);
@@ -476,8 +477,8 @@ int l2cap_disconnect(struct l2cap_channe
 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 *, struct sockopt *);
+int l2cap_getopt(struct l2cap_channel *, struct sockopt *);
 
 #endif	/* _KERNEL */
 
Index: netbt/l2cap_socket.c
===================================================================
RCS file: /usr/cvs/src/sys/netbt/l2cap_socket.c,v
retrieving revision 1.7
diff -u -p -r1.7 l2cap_socket.c
--- netbt/l2cap_socket.c	21 Apr 2007 06:15:23 -0000	1.7
+++ netbt/l2cap_socket.c	29 Dec 2007 12:41:14 -0000
@@ -259,14 +259,16 @@ release:
  *	"Reconfigure Channel Request" in the L2CAP specification.
  */
 int
-l2cap_ctloutput(int req, struct socket *so, int level,
-		int optname, struct mbuf **opt)
+l2cap_ctloutput(struct socket *so, struct sockopt *sopt)
 {
 	struct l2cap_channel *pcb = so->so_pcb;
-	struct mbuf *m;
 	int err = 0;
+	int req, level, len;
 
-	DPRINTFN(2, "%s\n", prcorequests[req]);
+	req = sopt->sopt_dir;
+	level = sopt->sopt_level;
+
+	DPRINTFN(2, "%s\n", (req == SOPT_SET) ? "SET" : "GET");
 
 	if (pcb == NULL)
 		return EINVAL;
@@ -275,22 +277,14 @@ l2cap_ctloutput(int req, struct socket *
 		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;
+	case SOPT_GET:
+		len = l2cap_getopt(pcb, sopt);
+		if (len == 0)
 			err = ENOPROTOOPT;
-		}
-		*opt = m;
 		break;
 
-	case PRCO_SETOPT:
-		m = *opt;
-		KASSERT(m != NULL);
-		err = l2cap_setopt(pcb, optname, mtod(m, void *));
-		m_freem(m);
+	case SOPT_SET:
+		err = l2cap_setopt(pcb, sopt);
 		break;
 
 	default:
@@ -368,13 +362,24 @@ l2cap_linkmode(void *arg, int new)
 {
 	struct socket *so = arg;
 	int mode;
+	struct sockopt sopt;
 
 	DPRINTF("auth %s, encrypt %s, secure %s\n",
 		(new & L2CAP_LM_AUTH ? "on" : "off"),
 		(new & L2CAP_LM_ENCRYPT ? "on" : "off"),
 		(new & L2CAP_LM_SECURE ? "on" : "off"));
 
-	(void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode);
+	/* XXX elad - maybe create a function that does this */
+	memset(&sopt, 0, sizeof(sopt));
+	sopt.sopt_dir = SOPT_GET;
+	sopt.sopt_level = BTPROTO_L2CAP;
+	sopt.sopt_name = SO_L2CAP_LM;
+	sopt.sopt_lwp = NULL;
+
+	(void)l2cap_getopt(so->so_pcb, &sopt);
+
+	mode = *sockopt_getintptr(&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)))
Index: netbt/l2cap_upper.c
===================================================================
RCS file: /usr/cvs/src/sys/netbt/l2cap_upper.c,v
retrieving revision 1.8
diff -u -p -r1.8 l2cap_upper.c
--- netbt/l2cap_upper.c	29 Apr 2007 20:23:36 -0000	1.8
+++ netbt/l2cap_upper.c	29 Dec 2007 12:41:22 -0000
@@ -420,14 +420,21 @@ l2cap_send(struct l2cap_channel *chan, s
  *	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, struct sockopt *sopt)
 {
 	int mode, err = 0;
 	uint16_t mtu;
+	void *v;
 
-	switch (opt) {
+	switch (sopt->sopt_name) {
 	case SO_L2CAP_IMTU:	/* set Incoming MTU */
-		mtu = *(uint16_t *)addr;
+		v = sockopt_get(sopt, sizeof(mtu));
+		if (v == NULL) {
+			err = EINVAL;
+			break;
+		}
+		mtu = *((uint16_t *)v);
+
 		if (mtu < L2CAP_MTU_MINIMUM)
 			err = EINVAL;
 		else if (chan->lc_state == L2CAP_CLOSED)
@@ -438,7 +445,13 @@ l2cap_setopt(struct l2cap_channel *chan,
 		break;
 
 	case SO_L2CAP_LM:	/* set link mode */
-		mode = *(int *)addr;
+		v = sockopt_getintptr(sopt);
+		if (v == NULL) {
+			err = EINVAL;
+			break;
+		}
+		mode = *((int *)v);
+
 		mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH);
 
 		if (mode & L2CAP_LM_SECURE)
@@ -470,37 +483,47 @@ l2cap_setopt(struct l2cap_channel *chan,
  *	Return configuration parameters.
  */
 int
-l2cap_getopt(struct l2cap_channel *chan, int opt, void *addr)
+l2cap_getopt(struct l2cap_channel *chan, struct sockopt *sopt)
 {
+	uint16_t ui;
 
-	switch (opt) {
+	switch (sopt->sopt_name) {
 	case SO_L2CAP_IMTU:	/* get Incoming MTU */
-		*(uint16_t *)addr = chan->lc_imtu;
+		ui = chan->lc_imtu;
+
+ integer:
+		if (sockopt_set(sopt, &ui, sizeof(ui)) != 0)
+			goto bad;
 		return sizeof(uint16_t);
 
 	case SO_L2CAP_OMTU:	/* get Outgoing MTU */
-		*(uint16_t *)addr = chan->lc_omtu;
-		return sizeof(uint16_t);
+		ui = chan->lc_omtu;
+		goto integer;
 
 	case SO_L2CAP_IQOS:	/* get Incoming QoS flow spec */
-		memcpy(addr, &chan->lc_iqos, sizeof(l2cap_qos_t));
+		if (sockopt_set(sopt, &chan->lc_iqos, sizeof(l2cap_qos_t)) != 0)
+			goto bad;
 		return sizeof(l2cap_qos_t);
 
 	case SO_L2CAP_OQOS:	/* get Outgoing QoS flow spec */
-		memcpy(addr, &chan->lc_oqos, sizeof(l2cap_qos_t));
+		if (sockopt_set(sopt, &chan->lc_oqos, sizeof(l2cap_qos_t)) != 0)
+			goto bad;
 		return sizeof(l2cap_qos_t);
 
 	case SO_L2CAP_FLUSH:	/* get Flush Timeout */
-		*(uint16_t *)addr = chan->lc_flush;
-		return sizeof(uint16_t);
+		ui = chan->lc_flush;
+		goto integer;
 
 	case SO_L2CAP_LM:	/* get link mode */
-		*(int *)addr = chan->lc_mode;
+		if (sockopt_set(sopt, &chan->lc_mode, sizeof(chan->lc_mode)) != 0)
+			goto bad;
+
 		return sizeof(int);
 
 	default:
 		break;
 	}
 
+ bad:
 	return 0;
 }
Index: netbt/rfcomm.h
===================================================================
RCS file: /usr/cvs/src/sys/netbt/rfcomm.h,v
retrieving revision 1.6
diff -u -p -r1.6 rfcomm.h
--- netbt/rfcomm.h	20 Nov 2007 20:25:58 -0000	1.6
+++ netbt/rfcomm.h	21 Dec 2007 11:18:44 -0000
@@ -63,6 +63,7 @@
 #define _NETBT_RFCOMM_H_
 
 #include <sys/types.h>
+#include <sys/socketvar.h>
 
 /*************************************************************************
  *************************************************************************
@@ -403,7 +404,7 @@ int rfcomm_session_send_mcc(struct rfcom
 
 /* 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(struct socket *, struct sockopt *);
 
 /* rfcomm_upper.c */
 int rfcomm_attach(struct rfcomm_dlc **, const struct btproto *, void *);
@@ -416,8 +417,8 @@ int rfcomm_detach(struct rfcomm_dlc **);
 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 *, struct sockopt *);
+int rfcomm_getopt(struct rfcomm_dlc *, struct sockopt *);
 
 #endif /* _KERNEL */
 
Index: netbt/rfcomm_dlc.c
===================================================================
RCS file: /usr/cvs/src/sys/netbt/rfcomm_dlc.c,v
retrieving revision 1.4
diff -u -p -r1.4 rfcomm_dlc.c
--- netbt/rfcomm_dlc.c	3 Nov 2007 17:20:17 -0000	1.4
+++ netbt/rfcomm_dlc.c	18 Dec 2007 21:34:07 -0000
@@ -221,6 +221,7 @@ int
 rfcomm_dlc_setmode(struct rfcomm_dlc *dlc)
 {
 	int mode = 0;
+	struct sockopt sopt;
 
 	KASSERT(dlc->rd_session != NULL);
 	KASSERT(dlc->rd_session->rs_state == RFCOMM_SESSION_OPEN);
@@ -239,7 +240,14 @@ rfcomm_dlc_setmode(struct rfcomm_dlc *dl
 	if (dlc->rd_mode & RFCOMM_LM_SECURE)
 		mode |= L2CAP_LM_SECURE;
 
-	return l2cap_setopt(dlc->rd_session->rs_l2cap, SO_L2CAP_LM, &mode);
+	/* XXX elad - functionize */
+	sopt.sopt_dir = SOPT_SET;
+	sopt.sopt_level = BTPROTO_L2CAP;
+	sopt.sopt_name = SO_L2CAP_LM;
+	sockopt_setint(&sopt, mode);
+	sopt.sopt_lwp = NULL;
+
+	return l2cap_setopt(dlc->rd_session->rs_l2cap, &sopt);
 }
 
 /*
Index: netbt/rfcomm_session.c
===================================================================
RCS file: /usr/cvs/src/sys/netbt/rfcomm_session.c,v
retrieving revision 1.11
diff -u -p -r1.11 rfcomm_session.c
--- netbt/rfcomm_session.c	3 Nov 2007 17:20:17 -0000	1.11
+++ netbt/rfcomm_session.c	18 Dec 2007 21:36:42 -0000
@@ -163,6 +163,7 @@ rfcomm_session_alloc(struct rfcomm_sessi
 {
 	struct rfcomm_session *rs;
 	int err;
+	struct sockopt sopt;
 
 	rs = malloc(sizeof(*rs), M_BLUETOOTH, M_NOWAIT | M_ZERO);
 	if (rs == NULL)
@@ -182,7 +183,15 @@ rfcomm_session_alloc(struct rfcomm_sessi
 		return NULL;
 	}
 
-	(void)l2cap_getopt(rs->rs_l2cap, SO_L2CAP_OMTU, &rs->rs_mtu);
+	/* XXX elad - functionize */
+	sopt.sopt_dir = SOPT_GET;
+	sopt.sopt_level = BTPROTO_L2CAP;
+	sopt.sopt_name = SO_L2CAP_OMTU;
+	sopt.sopt_lwp = NULL;
+
+	(void)l2cap_getopt(rs->rs_l2cap, &sopt);
+
+	rs->rs_mtu = *((uint16_t *)sockopt_get(&sopt, sizeof(rs->rs_mtu)));
 
 	if (laddr->bt_psm == L2CAP_PSM_ANY)
 		laddr->bt_psm = L2CAP_PSM_RFCOMM;
@@ -336,6 +345,7 @@ static void
 rfcomm_session_connected(void *arg)
 {
 	struct rfcomm_session *rs = arg;
+	struct sockopt sopt;
 
 	DPRINTF("Connected\n");
 
@@ -348,7 +358,15 @@ rfcomm_session_connected(void *arg)
 	 * 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);
+	/* XXX elad - functionize */
+	sopt.sopt_dir = SOPT_GET;
+	sopt.sopt_level = BTPROTO_L2CAP;
+	sopt.sopt_name = SO_L2CAP_OMTU;
+	sopt.sopt_lwp = NULL;
+
+	l2cap_getopt(rs->rs_l2cap, &sopt);
+
+	rs->rs_mtu = *((uint16_t *)sockopt_get(&sopt, sizeof(rs->rs_mtu)));
 
 	rs->rs_mtu -= 6; /* (RFCOMM overhead could be this big) */
 	if (rs->rs_mtu < RFCOMM_MTU_MIN) {
Index: netbt/rfcomm_socket.c
===================================================================
RCS file: /usr/cvs/src/sys/netbt/rfcomm_socket.c,v
retrieving revision 1.8
diff -u -p -r1.8 rfcomm_socket.c
--- netbt/rfcomm_socket.c	15 Oct 2007 18:04:34 -0000	1.8
+++ netbt/rfcomm_socket.c	29 Dec 2007 12:40:43 -0000
@@ -260,14 +260,17 @@ release:
  *
  */
 int
-rfcomm_ctloutput(int req, struct socket *so, int level,
-		int optname, struct mbuf **opt)
+rfcomm_ctloutput(struct socket *so, struct sockopt *sopt)
 {
 	struct rfcomm_dlc *pcb = so->so_pcb;
-	struct mbuf *m;
 	int err = 0;
+	int req, level, optname, len;
 
-	DPRINTFN(2, "%s\n", prcorequests[req]);
+	req = sopt->sopt_dir;
+	level = sopt->sopt_level;
+	optname = sopt->sopt_name;
+
+	DPRINTFN(2, "%s\n", (req == SOPT_SET) ? "SET" : "GET");
 
 	if (pcb == NULL)
 		return EINVAL;
@@ -276,22 +279,14 @@ rfcomm_ctloutput(int req, struct socket 
 		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;
+	case SOPT_GET:
+		len = rfcomm_getopt(pcb, sopt);
+		if (len == 0)
 			err = ENOPROTOOPT;
-		}
-		*opt = m;
 		break;
 
-	case PRCO_SETOPT:
-		m = *opt;
-		KASSERT(m != NULL);
-		err = rfcomm_setopt(pcb, optname, mtod(m, void *));
-		m_freem(m);
+	case SOPT_SET:
+		err = rfcomm_setopt(pcb, sopt);
 		break;
 
 	default:
@@ -378,13 +373,23 @@ rfcomm_linkmode(void *arg, int new)
 {
 	struct socket *so = arg;
 	int mode;
+	struct sockopt sopt;
 
 	DPRINTF("auth %s, encrypt %s, secure %s\n",
 		(new & RFCOMM_LM_AUTH ? "on" : "off"),
 		(new & RFCOMM_LM_ENCRYPT ? "on" : "off"),
 		(new & RFCOMM_LM_SECURE ? "on" : "off"));
 
-	(void)rfcomm_getopt(so->so_pcb, SO_RFCOMM_LM, &mode);
+	/* XXX elad - functionize */
+	sopt.sopt_dir = SOPT_GET;
+	sopt.sopt_level = BTPROTO_RFCOMM;
+	sopt.sopt_name = SO_RFCOMM_LM;
+	sopt.sopt_lwp = NULL;
+
+	(void)rfcomm_getopt(so->so_pcb, &sopt);
+
+	mode = *sockopt_getintptr(&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)))
Index: netbt/rfcomm_upper.c
===================================================================
RCS file: /usr/cvs/src/sys/netbt/rfcomm_upper.c,v
retrieving revision 1.10
diff -u -p -r1.10 rfcomm_upper.c
--- netbt/rfcomm_upper.c	20 Nov 2007 20:25:57 -0000	1.10
+++ netbt/rfcomm_upper.c	29 Dec 2007 12:40:52 -0000
@@ -439,14 +439,24 @@ rfcomm_rcvd(struct rfcomm_dlc *dlc, size
  * set DLC options
  */
 int
-rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, void *addr)
+rfcomm_setopt(struct rfcomm_dlc *dlc, struct sockopt *sopt)
 {
 	int mode, err = 0;
 	uint16_t mtu;
+	int opt;
+	void *v;
+
+	opt = sopt->sopt_name;
 
 	switch (opt) {
 	case SO_RFCOMM_MTU:
-		mtu = *(uint16_t *)addr;
+		v = sockopt_get(sopt, sizeof(mtu));
+		if (v == NULL) {
+			err = EINVAL;
+			break;
+		}
+		mtu = *((uint16_t *)v);
+
 		if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
 			err = EINVAL;
 		else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
@@ -457,7 +467,13 @@ rfcomm_setopt(struct rfcomm_dlc *dlc, in
 		break;
 
 	case SO_RFCOMM_LM:
-		mode = *(int *)addr;
+		v = sockopt_getintptr(sopt);
+		if (v == NULL) {
+			err = EINVAL;
+			break;
+		}
+		mode = *((int *)v);
+
 		mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
 
 		if (mode & RFCOMM_LM_SECURE)
@@ -486,35 +502,48 @@ rfcomm_setopt(struct rfcomm_dlc *dlc, in
  * 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;
+	int opt, i, error;
+	uint16_t ui;
+
+	opt = sopt->sopt_name;
 
 	switch (opt) {
 	case SO_RFCOMM_MTU:
-		*(uint16_t *)addr = dlc->rd_mtu;
+		ui = dlc->rd_mtu;
+		error = sockopt_set(sopt, &ui, sizeof(ui));
+		if (error)
+			goto bad;
 		return 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;
+		error = sockopt_set(sopt, &fc, sizeof(fc));
+		if (error)
+			goto bad;
 
-		return sizeof(*fc);
+		return sizeof(fc);
 
 	case SO_RFCOMM_LM:
-		*(int *)addr = dlc->rd_mode;
+		i = dlc->rd_mode;
+		error = sockopt_set(sopt, &i, sizeof(i));
+		if (error)
+			goto bad;
 		return sizeof(int);
 
 	default:
 		break;
 	}
 
+ bad:
 	return 0;
 }
Index: netbt/sco.h
===================================================================
RCS file: /usr/cvs/src/sys/netbt/sco.h,v
retrieving revision 1.2
diff -u -p -r1.2 sco.h
--- netbt/sco.h	26 Jul 2006 10:20:56 -0000	1.2
+++ netbt/sco.h	16 Dec 2007 15:35:49 -0000
@@ -65,7 +65,7 @@ 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(struct socket *, struct sockopt *);
 
 /* sco_upper.c */
 int sco_attach(struct sco_pcb **, const struct btproto *, void *);
@@ -77,8 +77,8 @@ int sco_disconnect(struct sco_pcb *, int
 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 *, struct sockopt *);
+int sco_getopt(struct sco_pcb *, struct sockopt *);
 
 #endif	/* _KERNEL */
 
Index: netbt/sco_socket.c
===================================================================
RCS file: /usr/cvs/src/sys/netbt/sco_socket.c,v
retrieving revision 1.9
diff -u -p -r1.9 sco_socket.c
--- netbt/sco_socket.c	21 Apr 2007 06:15:23 -0000	1.9
+++ netbt/sco_socket.c	16 Dec 2007 15:35:49 -0000
@@ -246,14 +246,16 @@ release:
  * get/set socket options
  */
 int
-sco_ctloutput(int req, struct socket *so, int level,
-		int optname, struct mbuf **opt)
+sco_ctloutput(struct socket *so, struct sockopt *sopt)
 {
 	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
-	struct mbuf *m;
 	int err = 0;
+	int req, level, len;
 
-	DPRINTFN(2, "req %s\n", prcorequests[req]);
+	req = sopt->sopt_dir;
+	level = sopt->sopt_level;
+
+	DPRINTFN(2, "req %s\n", (req == SOPT_SET) ? "SET" : "GET");
 
 	if (pcb == NULL)
 		return EINVAL;
@@ -263,21 +265,13 @@ sco_ctloutput(int req, struct socket *so
 
 	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;
+		len = sco_getopt(pcb, sopt);
+		if (len == 0)
 			err = ENOPROTOOPT;
-		}
-		*opt = m;
 		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:
Index: netbt/sco_upper.c
===================================================================
RCS file: /usr/cvs/src/sys/netbt/sco_upper.c,v
retrieving revision 1.6
diff -u -p -r1.6 sco_upper.c
--- netbt/sco_upper.c	30 Mar 2007 20:47:03 -0000	1.6
+++ netbt/sco_upper.c	21 Dec 2007 22:33:32 -0000
@@ -319,11 +319,11 @@ sco_send(struct sco_pcb *pcb, struct mbu
  *	Set SCO pcb options
  */
 int
-sco_setopt(struct sco_pcb *pcb, int opt, void *addr)
+sco_setopt(struct sco_pcb *pcb, struct sockopt *sopt)
 {
 	int err = 0;
 
-	switch (opt) {
+	switch (sopt->sopt_name) {
 	default:
 		err = ENOPROTOOPT;
 		break;
@@ -338,23 +338,32 @@ sco_setopt(struct sco_pcb *pcb, int opt,
  *	Get SCO pcb options
  */
 int
-sco_getopt(struct sco_pcb *pcb, int opt, void *addr)
+sco_getopt(struct sco_pcb *pcb, struct sockopt *sopt)
 {
+	uint16_t ui;
+	int error;
 
-	switch (opt) {
+	switch (sopt->sopt_name) {
 	case SO_SCO_MTU:
-		*(uint16_t *)addr = pcb->sp_mtu;
+		ui = pcb->sp_mtu;
+
+ uinteger:
+		error = sockopt_set(sopt, &ui, sizeof(ui));
+		if (error)
+			goto bad;
 		return sizeof(uint16_t);
 
 	case SO_SCO_HANDLE:
 		if (pcb->sp_link) {
-			*(uint16_t *)addr = pcb->sp_link->hl_handle;
-			return sizeof(uint16_t);
+			ui = pcb->sp_link->hl_handle;
+			goto uinteger;
 		}
 		break;
 
 	default:
 		break;
 	}
+
+ bad:
 	return 0;
 }
Index: netinet/ip_mroute.c
===================================================================
RCS file: /usr/cvs/src/sys/netinet/ip_mroute.c,v
retrieving revision 1.110
diff -u -p -r1.110 ip_mroute.c
--- netinet/ip_mroute.c	21 Dec 2007 02:07:55 -0000	1.110
+++ netinet/ip_mroute.c	29 Dec 2007 12:40:02 -0000
@@ -212,23 +212,19 @@ static const struct protosw vif_protosw 
 
 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 *);
+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(u_int32_t *); /* 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 @@ static int priority(struct vif *, struct
  * 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,97 @@ u_int32_t upcall_data[51];
  * 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;
+	int optval;
+	struct vifctl *vifc;
+	vifi_t *vifi;
+	struct bw_upcall *bwuc;
+	void *v;
 
-	if (optname != MRT_INIT && so != ip_mrouter)
+	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);
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
+				error = EINVAL;
+				break;
+			}
+			optval = *((int *)v);
+
+			if (optval != 1) {
+				error = EINVAL;
+				break;
+			}
+
+			error = ip_mrouter_init(so);
 			break;
 		case MRT_DONE:
 			error = ip_mrouter_done();
 			break;
 		case MRT_ADD_VIF:
-			error = add_vif(*m);
+			vifc = sockopt_get(sopt, sizeof(vifc));
+			if (vifc == NULL) {
+				error = EINVAL;
+				break;
+			}
+			error = add_vif(vifc);
 			break;
 		case MRT_DEL_VIF:
-			error = del_vif(*m);
+			vifi = sockopt_get(sopt, sizeof(vifi));
+			if (vifi == NULL) {
+				error = EINVAL;
+				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);
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
+				error = EINVAL;
+				break;
+			}
+			optval = *((int *)v);
+			error = set_assert(optval);
 			break;
 		case MRT_API_CONFIG:
-			error = set_api_config(*m);
+			v = sockopt_get(sopt, sizeof(uint16_t));
+			if (v == NULL) {
+				error = EINVAL;
+				break;
+			}
+			error = set_api_config(v);
 			break;
 		case MRT_ADD_BW_UPCALL:
-			error = add_bw_upcall(*m);
+			bwuc = sockopt_get(sopt, sizeof(bwuc));
+			if (bwuc == NULL) {
+				error = EINVAL;
+				break;
+			}
+			error = add_bw_upcall(bwuc);
 			break;
 		case MRT_DEL_BW_UPCALL:
-			error = del_bw_upcall(*m);
+			bwuc = sockopt_get(sopt, sizeof(bwuc));
+			if (bwuc == NULL) {
+				error = EINVAL;
+				break;
+			}
+			error = del_bw_upcall(bwuc);
 			break;
 		default:
 			error = ENOPROTOOPT;
 			break;
 		}
-
-	if (*m)
-		m_free(*m);
+	}
 	return (error);
 }
 
@@ -490,38 +532,37 @@ ip_mrouter_set(struct socket *so, int op
  * 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;
+	int optval;
+	uint32_t ui;
 
 	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);
+			optval = 0x0305; /* XXX !!!! */
+			error = sockopt_set(sopt, &optval, sizeof(optval));
 			break;
 		case MRT_ASSERT:
-			error = get_assert(*m);
+			optval = pim_assert;
+			error = sockopt_set(sopt, &optval, sizeof(optval));
 			break;
 		case MRT_API_SUPPORT:
-			error = get_api_support(*m);
+			ui = mrt_api_support;
+			error = sockopt_set(sopt, &ui, sizeof(ui));
 			break;
 		case MRT_API_CONFIG:
-			error = get_api_config(*m);
+			ui = mrt_api_config;
+			error = sockopt_set(sopt, &ui, sizeof(ui));
 			break;
 		default:
 			error = ENOPROTOOPT;
 			break;
 		}
-
-		if (error)
-			m_free(*m);
 	}
-
 	return (error);
 }
 
@@ -598,10 +639,8 @@ get_vif_cnt(struct sioc_vif_req *req)
  * Enable multicast routing
  */
 static int
-ip_mrouter_init(struct socket *so, struct mbuf *m)
+ip_mrouter_init(struct socket *so)
 {
-	int *v;
-
 	if (mrtdebug)
 		log(LOG_DEBUG,
 		    "ip_mrouter_init: so_type = %d, pr_protocol = %d\n",
@@ -611,13 +650,6 @@ ip_mrouter_init(struct socket *so, struc
 	    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)
-		return (EINVAL);
-
 	if (ip_mrouter != NULL)
 		return (EADDRINUSE);
 
@@ -733,42 +765,13 @@ ip_mrouter_detach(struct ifnet *ifp)
 	}
 }
 
-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);
 }
 
@@ -776,15 +779,9 @@ get_assert(struct mbuf *m)
  * Configure API capabilities
  */
 static int
-set_api_config(struct mbuf *m)
+set_api_config(u_int32_t *apival)
 {
 	int i;
-	u_int32_t *apival;
-
-	if (m == NULL || m->m_len < sizeof(u_int32_t))
-		return (EINVAL);
-
-	apival = mtod(m, u_int32_t *);
 
 	/*
 	 * We can set the API capabilities only if it is the first operation
@@ -815,48 +812,11 @@ set_api_config(struct mbuf *m)
 }
 
 /*
- * 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;
-
-	return (0);
-}
-
-/*
  * 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;
@@ -864,10 +824,6 @@ add_vif(struct mbuf *m)
 	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))
@@ -1040,17 +996,12 @@ reset_vif(struct vif *vifp)
  * 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);
 
@@ -1136,7 +1087,7 @@ expire_mfc(struct mfc *rt)
  * Add an mfc entry
  */
 static int
-add_mfc(struct mbuf *m)
+add_mfc(struct sockopt *sopt)
 {
 	struct mfcctl2 mfcctl2;
 	struct mfcctl2 *mfccp;
@@ -1150,17 +1101,25 @@ add_mfc(struct mbuf *m)
 	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 *);
+		struct mfcctl2 *mp2;
+
+		mfcctl_size = sizeof(*mp2);
+		mp2 = sockopt_get(sopt, mfcctl_size);
+		if (mp2 == NULL)
+			return (EINVAL);
+
 		bcopy(mp2, (void *)&mfcctl2, sizeof(*mp2));
 	} else {
-		struct mfcctl *mp = mtod(m, struct mfcctl *);
+		struct mfcctl *mp;
+
+		mfcctl_size = sizeof(*mp);
+		mp = sockopt_get(sopt, mfcctl_size);
+		if (mp == NULL)
+			return (EINVAL);
 		memcpy(&mfcctl2, mp, sizeof(*mp));
 		memset((char *)&mfcctl2 + sizeof(struct mfcctl), 0,
 		    sizeof(mfcctl2) - sizeof(struct mfcctl));
@@ -1306,23 +1265,28 @@ collate(struct timeval *t)
  * 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 *);
+	struct mfcctl *mp;
+	struct mfcctl *mp2;
+
+	mp = sockopt_get(sopt, sizeof(*mp));
+	if (mp == NULL) {
+		mp2 = sockopt_get(sopt, sizeof(*mp2));
+		if (mp2 == NULL) /* XXX elad */
+			return (EINVAL);
+		mp = (struct mfcctl *)mp2;
+	}
 
 	/*
 	 * 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));
@@ -2553,7 +2517,7 @@ compute_bw_meter_flags(struct bw_upcall 
  * 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;
@@ -2562,12 +2526,6 @@ add_bw_upcall(struct mbuf *m)
     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;
@@ -2652,17 +2610,11 @@ free_bw_list(struct bw_meter *list)
  * 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;
Index: netinet/ip_mroute.h
===================================================================
RCS file: /usr/cvs/src/sys/netinet/ip_mroute.h,v
retrieving revision 1.29
diff -u -p -r1.29 ip_mroute.h
--- netinet/ip_mroute.h	25 Dec 2007 18:33:46 -0000	1.29
+++ netinet/ip_mroute.h	26 Dec 2007 22:33:45 -0000
@@ -332,8 +332,8 @@ struct bw_meter {
 	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 *);
Index: netinet/ip_output.c
===================================================================
RCS file: /usr/cvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.191
diff -u -p -r1.191 ip_output.c
--- netinet/ip_output.c	14 Jan 2008 04:19:09 -0000	1.191
+++ netinet/ip_output.c	15 Jan 2008 11:55:33 -0000
@@ -157,7 +157,6 @@ static struct mbuf *ip_insertoptions(str
 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 */
@@ -1197,36 +1196,46 @@ ip_optcopy(struct ip *ip, struct ip *jp)
  * IP socket option processing.
  */
 int
-ip_ctloutput(int op, struct socket *so, int level, int optname,
-    struct mbuf **mp)
+ip_ctloutput(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
+	int op, level;
+	void *v;
+
+	op = sopt->sopt_dir;
+	level = sopt->sopt_level;
 
 	if (level != IPPROTO_IP) {
-		if (op == PRCO_SETOPT && *mp)
-			(void) m_free(*mp);
-		if (level == SOL_SOCKET && optname == SO_NOHEADER)
+		if (level == SOL_SOCKET && sopt->sopt_name == SO_NOHEADER)
 			return 0;
 		return ENOPROTOOPT;
 	}
 
 	switch (op) {
-
-	case PRCO_SETOPT:
-		switch (optname) {
+	case SOPT_SET:
+		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, sopt->sopt_name, m);
+			if (!error)
+				error = sockopt_setmbuf(sopt, m);
+
+			return (error);
+			}
 
 		case IP_TOS:
 		case IP_TTL:
@@ -1234,43 +1243,44 @@ ip_ctloutput(int op, struct socket *so, 
 		case IP_RECVRETOPTS:
 		case IP_RECVDSTADDR:
 		case IP_RECVIF:
-			if (m == NULL || m->m_len != sizeof(int))
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
 				error = EINVAL;
-			else {
-				optval = *mtod(m, int *);
-				switch (optname) {
-
-				case IP_TOS:
-					inp->inp_ip.ip_tos = optval;
-					break;
-
-				case IP_TTL:
-					inp->inp_ip.ip_ttl = optval;
-					break;
+				break;
+			}
+			optval = *((int *)v);
+
+			switch (sopt->sopt_name) {
+			case IP_TOS:
+				inp->inp_ip.ip_tos = 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_RECVRETOPTS:
-					OPTSET(INP_RECVRETOPTS);
-					break;
-
-				case IP_RECVDSTADDR:
-					OPTSET(INP_RECVDSTADDR);
-					break;
-
-				case IP_RECVIF:
-					OPTSET(INP_RECVIF);
-					break;
-				}
+			case IP_RECVOPTS:
+				OPTSET(INP_RECVOPTS);
+				break;
+
+			case IP_RECVRETOPTS:
+				OPTSET(INP_RECVRETOPTS);
+				break;
+
+			case IP_RECVDSTADDR:
+				OPTSET(INP_RECVDSTADDR);
+				break;
+
+			case IP_RECVIF:
+				OPTSET(INP_RECVIF);
+				break;
 			}
-			break;
+		break;
 #undef OPTSET
 
 		case IP_MULTICAST_IF:
@@ -1278,31 +1288,33 @@ ip_ctloutput(int op, struct socket *so, 
 		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))
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
 				error = EINVAL;
-			else {
-				optval = *mtod(m, int *);
+				break;
+			}
+			optval = *((int *)v);
 
-				switch (optval) {
+			/* INP_LOCK(inp); */
+			switch (optval) {
+			case IP_PORTRANGE_DEFAULT:
+			case IP_PORTRANGE_HIGH:
+				inp->inp_flags &= ~(INP_LOWPORT);
+				break;
 
-				case IP_PORTRANGE_DEFAULT:
-				case IP_PORTRANGE_HIGH:
-					inp->inp_flags &= ~(INP_LOWPORT);
-					break;
-
-				case IP_PORTRANGE_LOW:
-					inp->inp_flags |= INP_LOWPORT;
-					break;
-
-				default:
-					error = EINVAL;
-					break;
-				}
+			case IP_PORTRANGE_LOW:
+				inp->inp_flags |= INP_LOWPORT;
+				break;
+
+			default:
+				error = EINVAL;
+				break;
 			}
+			/* INP_UNLOCK(inp); */
 			break;
 
 #if defined(IPSEC) || defined(FAST_IPSEC)
@@ -1311,9 +1323,12 @@ ip_ctloutput(int op, struct socket *so, 
 			void *req = NULL;
 			size_t len = 0;
 			int priv = 0;
+			struct mbuf *m;
+			int optname;
 
 #ifdef __NetBSD__
-			if (l == 0 || kauth_authorize_generic(l->l_cred,
+			if (sopt->sopt_lwp == NULL ||
+			    kauth_authorize_generic(sopt->sopt_lwp->l_cred,
 			    KAUTH_GENERIC_ISSUSER, NULL))
 				priv = 0;
 			else
@@ -1321,11 +1336,20 @@ ip_ctloutput(int op, struct socket *so, 
 #else
 			priv = (in6p->in6p_socket->so_state & SS_PRIV);
 #endif
-			if (m) {
-				req = mtod(m, void *);
-				len = m->m_len;
+
+			m = sockopt_getmbuf(sopt);
+			if (m == NULL) {
+				error = ENOBUFS;
+				break;
 			}
+			req = mtod(m, void *);
+			len = m->m_len;
+			optname = sopt->sopt_name;
 			error = ipsec4_set_policy(inp, optname, req, len, priv);
+			m_freem(m);
+			if (!error)
+				error = sockopt_setmbuf(sopt, m);
+
 			break;
 		    }
 #endif /*IPSEC*/
@@ -1334,22 +1358,18 @@ ip_ctloutput(int op, struct socket *so, 
 			error = ENOPROTOOPT;
 			break;
 		}
-		if (m)
-			(void)m_free(m);
 		break;
 
-	case PRCO_GETOPT:
-		switch (optname) {
+	case SOPT_GET:
+		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);
+				error = sockopt_set(sopt,
+				    mtod(inp->inp_options, void *),
+				    inp->inp_options->m_len);
 			} else
-				m->m_len = 0;
+				sopt->sopt_size = 0;
 			break;
 
 		case IP_TOS:
@@ -1359,10 +1379,7 @@ ip_ctloutput(int op, struct socket *so, 
 		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;
@@ -1394,7 +1411,7 @@ ip_ctloutput(int op, struct socket *so, 
 				optval = OPTBIT(INP_RECVIF);
 				break;
 			}
-			*mtod(m, int *) = optval;
+			error = sockopt_set(sopt, &optval, sizeof(optval));
 			break;
 
 #if 0	/* defined(IPSEC) || defined(FAST_IPSEC) */
@@ -1403,12 +1420,17 @@ ip_ctloutput(int op, struct socket *so, 
 		{
 			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);
+			if (!error)
+				error = soopt_mcopyout(sopt, m); /* XXX */
+			if (!error)
+				m_freem(m);
 			break;
 		}
 #endif /*IPSEC*/
@@ -1418,22 +1440,17 @@ ip_ctloutput(int op, struct socket *so, 
 		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_set(sopt, &optval, sizeof(optval));
+
 			break;
 
 		default:
@@ -1451,11 +1468,7 @@ ip_ctloutput(int op, struct socket *so, 
  * 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
+ip_pcbopts(struct mbuf **pcbopt, int optname, struct mbuf *m)
 {
 	int cnt, optlen;
 	u_char *cp;
@@ -1584,19 +1597,19 @@ ip_multicast_if(struct in_addr *a, int *
 }
 
 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;
 
-	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 *));
+		tval = *((u_int8_t *)sockopt_get(sopt, sizeof(u_int8_t)));
 		break;
 	case sizeof(u_int):
-		tval = *(mtod(m, u_int *));
+		tval = *((u_int *)sockopt_get(sopt, sizeof(u_int)));
 		break;
 	default:
 		return EINVAL;
@@ -1613,7 +1626,7 @@ ip_getoptval(struct mbuf *m, u_int8_t *v
  * 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;
@@ -1622,6 +1635,7 @@ ip_setmoptions(int optname, struct ip_mo
 	struct ifnet *ifp;
 	struct ip_moptions *imo = *imop;
 	int ifindex;
+	void *v;
 
 	if (imo == NULL) {
 		/*
@@ -1641,17 +1655,18 @@ ip_setmoptions(int optname, struct ip_mo
 		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)) {
+		v = sockopt_get(sopt, sizeof(addr));
+		if (v == NULL) {
 			error = EINVAL;
 			break;
 		}
-		addr = *(mtod(m, struct in_addr *));
+		addr = *((struct in_addr *)v);
+
 		/*
 		 * INADDR_ANY is used to remove a previous selection.
 		 * When no interface is selected, a default one is
@@ -1682,7 +1697,7 @@ ip_setmoptions(int optname, struct ip_mo
 		/*
 		 * 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:
@@ -1690,7 +1705,7 @@ ip_setmoptions(int optname, struct ip_mo
 		 * 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:
@@ -1698,11 +1713,12 @@ ip_setmoptions(int optname, struct ip_mo
 		 * Add a multicast group membership.
 		 * Group must be a valid IP multicast address.
 		 */
-		if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
+		mreq = sockopt_get(sopt, sizeof(*mreq));
+		if (mreq == NULL) {
 			error = EINVAL;
 			break;
 		}
-		mreq = mtod(m, struct ip_mreq *);
+
 		if (!IN_MULTICAST(mreq->imr_multiaddr.s_addr)) {
 			error = EINVAL;
 			break;
@@ -1772,11 +1788,12 @@ ip_setmoptions(int optname, struct ip_mo
 		 * Drop a multicast group membership.
 		 * Group must be a valid IP multicast address.
 		 */
-		if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
+		mreq = sockopt_get(sopt, sizeof(*mreq));
+		if (mreq == NULL) {
 			error = EINVAL;
 			break;
 		}
-		mreq = mtod(m, struct ip_mreq *);
+
 		if (!IN_MULTICAST(mreq->imr_multiaddr.s_addr)) {
 			error = EINVAL;
 			break;
@@ -1844,48 +1861,58 @@ ip_setmoptions(int optname, struct ip_mo
  * 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;
+	u_char coptval;
+	int error, optval;
 
-	*mp = m_get(M_WAIT, MT_SOOPTS);
-
-	switch (optname) {
+	error = 0;
 
+	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);
+		if (imo != NULL)
+			optval = coptval = imo->imo_multicast_ttl;
+		else
+			optval = coptval = IP_DEFAULT_MULTICAST_TTL;
+
+		if (sopt->sopt_size == sizeof(u_char))
+			error = sockopt_set(sopt, &coptval, sizeof(u_char));
+		else
+			error = sockopt_set(sopt, &optval, sizeof(int));
+		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);
+		if (imo != NULL)
+			optval = coptval = imo->imo_multicast_loop;
+		else
+			optval = coptval = IP_DEFAULT_MULTICAST_LOOP;
+
+		if (sopt->sopt_size == sizeof(u_char))
+			error = sockopt_set(sopt, &coptval, sizeof(u_char));
+		else
+			error = sockopt_set(sopt, &optval, sizeof(int));
+		break;
 
 	default:
-		return (EOPNOTSUPP);
+		error = EOPNOTSUPP;
 	}
+
+	return (error);
 }
 
 /*
Index: netinet/ip_var.h
===================================================================
RCS file: /usr/cvs/src/sys/netinet/ip_var.h,v
retrieving revision 1.83
diff -u -p -r1.83 ip_var.h
--- netinet/ip_var.h	25 Dec 2007 18:33:47 -0000	1.83
+++ netinet/ip_var.h	26 Dec 2007 22:33:45 -0000
@@ -218,34 +218,35 @@ extern int ip_hashsize;
 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(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 *);
 int	 ip_output(struct mbuf *, ...);
 int	 ip_fragment(struct mbuf *, struct ifnet *, u_long);
-int	 ip_pcbopts(struct mbuf **, struct mbuf *);
+int	 ip_pcbopts(struct mbuf **, int, struct mbuf *);
 struct mbuf *
 	 ip_reass(struct ipqent *, struct ipq *, struct ipqhead *);
 struct in_ifaddr *
 	 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);
 int	 ip_sysctl(int *, u_int, void *, size_t *, void *, size_t);
 void	 ipintr(void);
 void *	 rip_ctlinput(int, const struct sockaddr *, void *);
-int	 rip_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int	 rip_ctloutput(struct socket *, struct sockopt *);
 void	 rip_init(void);
 void	 rip_input(struct mbuf *, ...);
 int	 rip_output(struct mbuf *, ...);
Index: netinet/raw_ip.c
===================================================================
RCS file: /usr/cvs/src/sys/netinet/raw_ip.c,v
retrieving revision 1.102
diff -u -p -r1.102 raw_ip.c
--- netinet/raw_ip.c	21 Dec 2007 02:07:55 -0000	1.102
+++ netinet/raw_ip.c	29 Dec 2007 12:39:25 -0000
@@ -373,40 +373,50 @@ rip_output(struct mbuf *m, ...)
  * Raw IP socket option processing.
  */
 int
-rip_ctloutput(int op, struct socket *so, int level, int optname,
-    struct mbuf **m)
+rip_ctloutput(struct socket *so, struct sockopt *sopt)
 {
 	struct inpcb *inp = sotoinpcb(so);
 	int error = 0;
+	int optval;
+	void *v;
 
-	if (level == SOL_SOCKET && optname == 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);
+	if (sopt->sopt_level == SOL_SOCKET && sopt->sopt_name == SO_NOHEADER) {
+		if (sopt->sopt_dir == SOPT_GET) {
+			optval = (inp->inp_flags & INP_NOHEADER) ? 1 : 0;
+			error = sockopt_set(sopt, &optval, sizeof(optval));
+		} else if (sopt->sopt_dir == SOPT_SET) {
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
+				error = EINVAL;
+				goto out;
+			}
+			optval = *((int *)v);
+			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(so, sopt);
 
-	switch (op) {
+	switch (sopt->sopt_dir) {
 
-	case PRCO_SETOPT:
-		switch (optname) {
+	case SOPT_SET:
+		switch (sopt->sopt_name) {
 		case IP_HDRINCL:
-			if (*m == NULL || (*m)->m_len != sizeof(int))
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
 				error = EINVAL;
-			else if (*mtod(*m, int *))
+				break;
+			}
+			optval = *((int *)v);
+			if (optval)
 				inp->inp_flags |= INP_HDRINCL;
 			else
 				inp->inp_flags &= ~INP_HDRINCL;
-			goto free_m;
+			break;
 
 #ifdef MROUTING
 		case MRT_INIT:
@@ -419,20 +429,21 @@ rip_ctloutput(int op, struct socket *so,
 		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(so, sopt);
 			break;
 		}
 		break;
 
-	case PRCO_GETOPT:
-		switch (optname) {
+	case SOPT_GET:
+		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
@@ -440,20 +451,17 @@ rip_ctloutput(int op, struct socket *so,
 		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(so, sopt);
 			break;
 		}
 		break;
 	}
-	return error;
-free_m:
-	if (op == PRCO_SETOPT && *m != NULL)
-		(void)m_free(*m);
+ out:
 	return error;
 }
 
Index: netinet/tcp_usrreq.c
===================================================================
RCS file: /usr/cvs/src/sys/netinet/tcp_usrreq.c,v
retrieving revision 1.140
diff -u -p -r1.140 tcp_usrreq.c
--- netinet/tcp_usrreq.c	16 Dec 2007 14:12:35 -0000	1.140
+++ netinet/tcp_usrreq.c	29 Dec 2007 12:39:15 -0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: tcp_usrreq.c,v 1.140 2007/12/16 14:12:35 elad Exp $	*/
+/*	$NetBSD: tcp_usrreq.c,v 1.139 2007/11/27 22:45:30 christos Exp $	*/
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -102,7 +102,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tcp_usrreq.c,v 1.140 2007/12/16 14:12:35 elad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tcp_usrreq.c,v 1.139 2007/11/27 22:45:30 christos Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -639,8 +639,7 @@ change_keepalive(struct socket *so, stru
 
 
 int
-tcp_ctloutput(int op, struct socket *so, int level, int optname,
-    struct mbuf **mp)
+tcp_ctloutput(struct socket *so, struct sockopt *sopt)
 {
 	int error = 0, s;
 	struct inpcb *inp;
@@ -648,10 +647,17 @@ tcp_ctloutput(int op, struct socket *so,
 	struct in6pcb *in6p;
 #endif
 	struct tcpcb *tp;
-	struct mbuf *m;
-	int i;
 	u_int ui;
 	int family;	/* family of the socket */
+	int op, level, optname, optval;
+#ifdef notyet /* XXX tcp_congctl_select() */
+	char name[TCPCC_MAXLEN];
+#endif
+	void *v;
+
+	op = sopt->sopt_dir;
+	level = sopt->sopt_level;
+	optname = sopt->sopt_name;
 
 	family = so->so_proto->pr_domain->dom_family;
 
@@ -682,20 +688,18 @@ tcp_ctloutput(int op, struct socket *so,
 #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(so, sopt);
 			break;
 #endif
 #ifdef INET6
 		case PF_INET6:
-			error = ip6_ctloutput(op, so, level, optname, mp);
+			error = ip6_ctloutput(so, sopt);
 			break;
 #endif
 		}
@@ -712,18 +716,17 @@ tcp_ctloutput(int op, struct socket *so,
 		tp = NULL;
 
 	switch (op) {
-
-	case PRCO_SETOPT:
-		m = *mp;
+	case SOPT_SET:
 		switch (optname) {
-
 #ifdef TCP_SIGNATURE
 		case TCP_MD5SIG:
-			if (m == NULL || m->m_len != sizeof(int))
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
 				error = EINVAL;
-			if (error)
 				break;
-			if (*mtod(m, int *) > 0)
+			}
+			optval = *((int *)v);
+			if (optval > 0)
 				tp->t_flags |= TF_SIGNATURE;
 			else
 				tp->t_flags &= ~TF_SIGNATURE;
@@ -731,33 +734,50 @@ tcp_ctloutput(int op, struct socket *so,
 #endif /* TCP_SIGNATURE */
 
 		case TCP_NODELAY:
-			if (m == NULL || m->m_len != sizeof(int))
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
 				error = EINVAL;
-			else if (*mtod(m, int *))
+				break;
+			}
+			optval = *((int *)v);
+			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 */
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
+				error = EINVAL;
+				break;
+			}
+			optval = *((int *)v);
+			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)
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
 				error = EINVAL;
-			error = tcp_congctl_select(tp, mtod(m, char *));
+				break;
+			}
+			optval = *((int *)v);
+			error = tcp_congctl_select(tp, name);
 #endif
 			break;
 
 		case TCP_KEEPIDLE:
-			if (m && m->m_len == sizeof(u_int) &&
-			    (ui = *mtod(m, u_int *)) > 0) {
+			v = sockopt_get(sopt, sizeof(ui));
+			if (v == NULL) {
+				error = EINVAL;
+				break;
+			}
+			ui = *((u_int *)v);
+			if (ui > 0) {
 				tp->t_keepidle = ui;
 				change_keepalive(so, tp);
 			} else
@@ -765,8 +785,13 @@ tcp_ctloutput(int op, struct socket *so,
 			break;
 
 		case TCP_KEEPINTVL:
-			if (m && m->m_len == sizeof(u_int) &&
-			    (ui = *mtod(m, u_int *)) > 0) {
+			v = sockopt_get(sopt, sizeof(ui));
+			if (v == NULL) {
+				error = EINVAL;
+				break;
+			}
+			ui = *((u_int *)v);
+			if (ui > 0) {
 				tp->t_keepintvl = ui;
 				change_keepalive(so, tp);
 			} else
@@ -774,8 +799,13 @@ tcp_ctloutput(int op, struct socket *so,
 			break;
 
 		case TCP_KEEPCNT:
-			if (m && m->m_len == sizeof(u_int) &&
-			    (ui = *mtod(m, u_int *)) > 0) {
+			v = sockopt_get(sopt, sizeof(ui));
+			if (v == NULL) {
+				error = EINVAL;
+				break;
+			}
+			ui = *((u_int *)v);
+			if (ui > 0) {
 				tp->t_keepcnt = ui;
 				change_keepalive(so, tp);
 			} else
@@ -783,8 +813,13 @@ tcp_ctloutput(int op, struct socket *so,
 			break;
 
 		case TCP_KEEPINIT:
-			if (m && m->m_len == sizeof(u_int) &&
-			    (ui = *mtod(m, u_int *)) > 0) {
+			v = sockopt_get(sopt, sizeof(ui));
+			if (v == NULL) {
+				error = EINVAL;
+				break;
+			}
+			ui = *((u_int *)v);
+			if (ui > 0) {
 				tp->t_keepinit = ui;
 				change_keepalive(so, tp);
 			} else
@@ -795,24 +830,23 @@ tcp_ctloutput(int op, struct socket *so,
 			error = ENOPROTOOPT;
 			break;
 		}
-		if (m)
-			(void) m_free(m);
 		break;
 
-	case PRCO_GETOPT:
-		*mp = m = m_intopt(so, 0);
-
+	case SOPT_GET:
 		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:
Index: netinet/tcp_var.h
===================================================================
RCS file: /usr/cvs/src/sys/netinet/tcp_var.h,v
retrieving revision 1.151
diff -u -p -r1.151 tcp_var.h
--- netinet/tcp_var.h	25 Dec 2007 18:33:47 -0000	1.151
+++ netinet/tcp_var.h	26 Dec 2007 22:33:46 -0000
@@ -844,7 +844,7 @@ int	 tcp_isdead(struct tcpcb *);
 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(struct socket *, struct sockopt *);
 struct tcpcb *
 	 tcp_disconnect(struct tcpcb *);
 struct tcpcb *
Index: netinet/udp_usrreq.c
===================================================================
RCS file: /usr/cvs/src/sys/netinet/udp_usrreq.c,v
retrieving revision 1.163
diff -u -p -r1.163 udp_usrreq.c
--- netinet/udp_usrreq.c	27 Nov 2007 22:45:30 -0000	1.163
+++ netinet/udp_usrreq.c	29 Dec 2007 12:40:21 -0000
@@ -987,14 +987,14 @@ udp_ctlinput(int cmd, const struct socka
 }
 
 int
-udp_ctloutput(int op, struct socket *so, int level, int optname,
-    struct mbuf **mp)
+udp_ctloutput(struct socket *so, struct sockopt *sopt)
 {
 	int s;
 	int error = 0;
-	struct mbuf *m;
 	struct inpcb *inp;
 	int family;
+	int optval;
+	void *v;
 
 	family = so->so_proto->pr_domain->dom_family;
 
@@ -1002,16 +1002,16 @@ udp_ctloutput(int op, struct socket *so,
 	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(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(so, sopt);
 			goto end;
 		}
 		break;
@@ -1022,19 +1022,20 @@ udp_ctloutput(int op, struct socket *so,
 	}
 
 
-	switch (op) {
-	case PRCO_SETOPT:
-		m = *mp;
+	switch (sopt->sopt_dir) {
+	case SOPT_SET:
 		inp = sotoinpcb(so);
 
-		switch (optname) {
+		switch (sopt->sopt_name) {
 		case UDP_ENCAP:
-			if (m == NULL || m->m_len != sizeof(int)) {
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
 				error = EINVAL;
 				break;
 			}
+			optval = *((int *)v);
 
-			switch(*mtod(m, int *)) {
+			switch(optval) {
 #ifdef IPSEC_NAT_T
 			case 0:
 				inp->inp_flags &= ~INP_ESPINUDP_ALL;
@@ -1060,9 +1061,6 @@ udp_ctloutput(int op, struct socket *so,
 			error = ENOPROTOOPT;
 			break;
 		}
-		if (m != NULL) {
-			m_free(m);
-		}
 		break;
 
 	default:
Index: netinet/udp_var.h
===================================================================
RCS file: /usr/cvs/src/sys/netinet/udp_var.h,v
retrieving revision 1.33
diff -u -p -r1.33 udp_var.h
--- netinet/udp_var.h	25 Dec 2007 18:33:47 -0000	1.33
+++ netinet/udp_var.h	26 Dec 2007 22:33:46 -0000
@@ -95,7 +95,7 @@ extern	struct	udpstat udpstat;
 #endif
 
 void	 *udp_ctlinput(int, const struct sockaddr *, void *);
-int	 udp_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int	 udp_ctloutput(struct socket *, struct sockopt *);
 void	 udp_init(void);
 void	 udp_input(struct mbuf *, ...);
 int	 udp_output(struct mbuf *, ...);
Index: netinet6/icmp6.c
===================================================================
RCS file: /usr/cvs/src/sys/netinet6/icmp6.c,v
retrieving revision 1.141
diff -u -p -r1.141 icmp6.c
--- netinet6/icmp6.c	4 Dec 2007 10:27:33 -0000	1.141
+++ netinet6/icmp6.c	22 Dec 2007 16:09:13 -0000
@@ -2553,32 +2553,23 @@ fail:
  * ICMPv6 socket option processing.
  */
 int
-icmp6_ctloutput(int op, struct socket *so, int level, 
-	int optname, struct mbuf **mp)
+icmp6_ctloutput(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 (sopt->sopt_level != IPPROTO_ICMPV6)
+		return rip6_ctloutput(so, sopt);
 
-	if (level != IPPROTO_ICMPV6)
-		return rip6_ctloutput(op, so, level, optname, mp);
-
-	switch (op) {
-	case PRCO_SETOPT:
-		switch (optname) {
+	switch (sopt->sopt_dir) {
+	case SOPT_SET:
+		switch (sopt->sopt_name) {
 		case ICMP6_FILTER:
 		    {
 			struct icmp6_filter *p;
 
-			if (optlen != sizeof(*p)) {
-				error = EMSGSIZE;
-				break;
-			}
-			p = mtod(m, struct icmp6_filter *);
-			if (!p || !in6p->in6p_icmp6filt) {
+			p = sockopt_get(sopt, sizeof(*p));
+			if (p == NULL) {
 				error = EINVAL;
 				break;
 			}
@@ -2592,26 +2583,18 @@ icmp6_ctloutput(int op, struct socket *s
 			error = ENOPROTOOPT;
 			break;
 		}
-		if (m)
-			(void)m_freem(m);
 		break;
 
-	case PRCO_GETOPT:
-		switch (optname) {
+	case SOPT_GET:
+		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;
 		    }
 
Index: netinet6/ip6_mroute.c
===================================================================
RCS file: /usr/cvs/src/sys/netinet6/ip6_mroute.c,v
retrieving revision 1.86
diff -u -p -r1.86 ip6_mroute.c
--- netinet6/ip6_mroute.c	27 Nov 2007 22:45:30 -0000	1.86
+++ netinet6/ip6_mroute.c	29 Dec 2007 12:39:42 -0000
@@ -159,7 +159,6 @@ static int ip6_mdq(struct mbuf *, struct
 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 *);
@@ -296,65 +295,98 @@ static callout_t expire_upcalls_ch;
  * 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;
+	void *v;
+
+	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));
+		v = sockopt_getintptr(sopt);
+		if (v == NULL) {
+			error = EINVAL;
+			break;
+		}
+		optval = *((int *)v);
+		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 *)));
+		mifc = sockopt_get(sopt, sizeof(*mifc));
+		if (mifc == NULL) {
+			error = EINVAL;
+			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 *)));
+		mifi = sockopt_get(sopt, sizeof(*mifi));
+		if (mifi == NULL) {
+			error = EINVAL;
+			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 *)));
+		mfcc = sockopt_get(sopt, sizeof(*mfcc));
+		if (mfcc == NULL) {
+			error = EINVAL;
+			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 *)));
+		mfcc = sockopt_get(sopt, sizeof(*mfcc));
+		if (mfcc == NULL) {
+			error = EINVAL;
+			break;
+		}
+		return (del_m6fc(mfcc));
 	case MRT6_PIM:
-		if (m == NULL || m->m_len != sizeof(int))
-			return (EINVAL);
-		return (set_pim6(mtod(m, int *)));
+		v = sockopt_getintptr(sopt);
+		if (v == NULL) {
+			error = EINVAL;
+			break;
+		}
+		optval = *((int *)v);
+		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);
 }
 
 /*
@@ -418,21 +450,6 @@ get_mif6_cnt(struct sioc_mif_req6 *req)
 	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)
 {
Index: netinet6/ip6_mroute.h
===================================================================
RCS file: /usr/cvs/src/sys/netinet6/ip6_mroute.h,v
retrieving revision 1.13
diff -u -p -r1.13 ip6_mroute.h
--- netinet6/ip6_mroute.h	1 Nov 2007 20:33:57 -0000	1.13
+++ netinet6/ip6_mroute.h	13 Dec 2007 19:45:23 -0000
@@ -267,8 +267,8 @@ struct rtdetq {		/* XXX: rtdetq is also 
 
 #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(int, void *);
Index: netinet6/ip6_output.c
===================================================================
RCS file: /usr/cvs/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.126
diff -u -p -r1.126 ip6_output.c
--- netinet6/ip6_output.c	14 Jan 2008 04:16:45 -0000	1.126
+++ netinet6/ip6_output.c	15 Jan 2008 11:55:34 -0000
@@ -127,7 +127,7 @@ struct ip6_exthdrs {
 
 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 *);
@@ -143,7 +143,7 @@ static int copypktopts(struct ip6_pktopt
 
 #ifdef RFC2292
 static int ip6_pcbopts(struct ip6_pktopts **, struct mbuf *,
-	struct socket *);
+	struct socket *, struct sockopt *);
 #endif
 
 #define	IN6_NEED_CHECKSUM(ifp, csum_flags) \
@@ -1463,37 +1463,50 @@ ip6_getpmtu(struct route *ro_pmtu, struc
  * IP6 socket option processing.
  */
 int
-ip6_ctloutput(int op, struct socket *so, int level, int optname,
-    struct mbuf **mp)
+ip6_ctloutput(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 */
+	struct lwp *l;
+	int level, op, optname;
+	void *v;
+
+	KASSERT(sopt != NULL);
+
+	level = sopt->sopt_level;
+	op = sopt->sopt_dir;
+	optname = sopt->sopt_name;
+	l = sopt->sopt_lwp;
 
-	optlen = m ? m->m_len : 0;
 	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) {
-	case PRCO_SETOPT:
+	case SOPT_SET:
 		switch (optname) {
 #ifdef RFC2292
-		case IPV6_2292PKTOPTIONS:
+		case IPV6_2292PKTOPTIONS: {
+			struct mbuf *m;
+
+			m = sockopt_getmbuf(sopt); /* XXX */
+
 			/* m is freed in ip6_pcbopts */
 			error = ip6_pcbopts(&in6p->in6p_outputopts,
-			    m, so);
+			    m, so, sopt);
+			if (!error)
+				error = sockopt_setmbuf(sopt, m);
+
+			m_free(m); /* XXX */
+
 			break;
+			}
 #endif
 
 		/*
@@ -1527,13 +1540,13 @@ ip6_ctloutput(int op, struct socket *so,
 		case IPV6_RECVPATHMTU:
 		case IPV6_RECVTCLASS:
 		case IPV6_V6ONLY:
-			if (optlen != sizeof(int)) {
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
 				error = EINVAL;
 				break;
 			}
-			optval = *mtod(m, int *);
+			optval = *((int *)v);
 			switch (optname) {
-
 			case IPV6_UNICAST_HOPS:
 				if (optval < -1 || optval >= 256)
 					error = EINVAL;
@@ -1701,11 +1714,12 @@ else 					\
 			struct ip6_pktopts **optp;
 			u_int8_t tclass;
 
-			if (optlen != sizeof(tclass)) {
+			v = sockopt_get(sopt, sizeof(tclass));
+			if (v == NULL) {
 				error = EINVAL;
 				break;
 			}
-			tclass = *mtod(m, u_int8_t *);
+			tclass = *((u_int8_t *)v);
 			optp = &in6p->in6p_outputopts;
 			error = ip6_pcbopt(optname,
 					   (u_char *)&tclass,
@@ -1718,11 +1732,12 @@ else 					\
 		case IPV6_TCLASS:
 		case IPV6_DONTFRAG:
 		case IPV6_USE_MIN_MTU:
-			if (optlen != sizeof(optval)) {
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
 				error = EINVAL;
 				break;
 			}
-			optval = *mtod(m, int *);
+			optval = *((int *)v);
 			{
 				struct ip6_pktopts **optp;
 				optp = &in6p->in6p_outputopts;
@@ -1741,11 +1756,13 @@ else 					\
 		case IPV6_2292DSTOPTS:
 		case IPV6_2292RTHDR:
 			/* RFC 2292 */
-			if (optlen != sizeof(int)) {
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
 				error = EINVAL;
 				break;
 			}
-			optval = *mtod(m, int *);
+			optval = *((int *)v);
+
 			switch (optname) {
 			case IPV6_2292PKTINFO:
 				OPTSET2292(IN6P_PKTINFO);
@@ -1778,16 +1795,11 @@ else 					\
 		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 */
@@ -1797,35 +1809,40 @@ else 					\
 			}
 #endif
 
-			if (m && m->m_next) {
-				error = EINVAL;	/* XXX */
-				break;
-			}
-
-			optbuf = mtod(m, u_char *);
-			optbuflen = m->m_len;
+			optbuflen = sopt->sopt_size;
+			optbuf = sockopt_get(sopt, 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)
+				return (ENOMEM);
 			error = ip6_setmoptions(optname,
 			    &in6p->in6p_moptions, m);
+			if (!error)
+				error = sockopt_setmbuf(sopt, m);
+
 			break;
+			}
 
 		case IPV6_PORTRANGE:
-			if (!m) {
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
 				error = EINVAL;
 				break;
 			}
-			optval = *mtod(m, int *);
+			optval = *((int *)v);
 
 			switch (optval) {
 			case IPV6_PORTRANGE_DEFAULT:
@@ -1855,12 +1872,19 @@ else 					\
 		{
 			void *req = NULL;
 			size_t len = 0;
-			if (m) {
+			struct mbuf *m;
+
+			m = sockopt_getmbuf(sopt);
+			if (m != NULL) {
 				req = mtod(m, void *);
 				len = m->m_len;
 			}
 			error = ipsec6_set_policy(in6p, optname, req,
 						  len, privileged);
+			if (!error)
+				error = sockopt_setmbuf(sopt, m);
+
+			m_free(m);
 		}
 			break;
 #endif /* IPSEC */
@@ -1869,11 +1893,9 @@ else 					\
 			error = ENOPROTOOPT;
 			break;
 		}
-		if (m)
-			(void)m_free(m);
 		break;
 
-	case PRCO_GETOPT:
+	case SOPT_GET:
 		switch (optname) {
 #ifdef RFC2292
 		case IPV6_2292PKTOPTIONS:
@@ -1886,8 +1908,6 @@ else 					\
 			 * to simplify this part by always returning
 			 * empty data.
 			 */
-			*mp = m_get(M_WAIT, MT_SOOPTS);
-			(*mp)->m_len = 0;
 			break;
 #endif
 
@@ -1965,9 +1985,7 @@ else 					\
 			}
 			if (error)
 				break;
-			*mp = m = m_get(M_WAIT, MT_SOOPTS);
-			m->m_len = sizeof(int);
-			*mtod(m, int *) = optval;
+			error = sockopt_set(sopt, &optval, sizeof(optval));
 			break;
 
 		case IPV6_PATHMTU:
@@ -1996,11 +2014,7 @@ else 					\
 			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;
 		    }
 
@@ -2027,9 +2041,7 @@ else 					\
 				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_set(sopt, &optval, sizeof(optval));
 			break;
 #endif
 		case IPV6_PKTINFO:
@@ -2043,30 +2055,43 @@ else 					\
 		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_set(sopt, mtod(m, void *),
+				    m->m_len);
+			m_free(m);
 			break;
+			}
 
 #if defined(IPSEC) || defined(FAST_IPSEC)
-		case IPV6_IPSEC_POLICY:
-		    {
+		case IPV6_IPSEC_POLICY: {
+			struct mbuf *m = NULL;
 			void *req = NULL;
 			size_t len = 0;
-			if (m) {
+
+			m = sockopt_getmbuf(sopt);
+			if (m != NULL) {
 				req = mtod(m, void *);
 				len = m->m_len;
 			}
-			error = ipsec6_get_policy(in6p, req, len, mp);
+
+			error = ipsec6_get_policy(in6p, req, len, &m);
+			if (!error)
+				error = sockopt_setmbuf(sopt, m);
+
 			break;
-		    }
+			}
 #endif /* IPSEC */
 
 
@@ -2082,19 +2107,21 @@ else 					\
 }
 
 int
-ip6_raw_ctloutput(int op, struct socket *so, int level, int optname, 
-	struct mbuf **mp)
+ip6_raw_ctloutput(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;
+	int op, level, optname;
+	void *v;
+
+	KASSERT(sopt != NULL);
 
-	optlen = m ? m->m_len : 0;
+	op = sopt->sopt_dir;
+	level = sopt->sopt_level;
+	optname = sopt->sopt_name;
 
 	if (level != IPPROTO_IPV6) {
-		if (op == PRCO_SETOPT && *mp)
-			(void)m_free(*mp);
 		return ENOPROTOOPT;
 	}
 
@@ -2109,12 +2136,13 @@ ip6_raw_ctloutput(int op, struct socket 
 		 * behavior does not meet RFC3542.
 		 */
 		switch (op) {
-		case PRCO_SETOPT:
-			if (optlen != sizeof(int)) {
+		case SOPT_SET:
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
 				error = EINVAL;
 				break;
 			}
-			optval = *mtod(m, int *);
+			optval = *((int *)v);
 			if ((optval % 2) != 0) {
 				/* the API assumes even offset values */
 				error = EINVAL;
@@ -2126,15 +2154,13 @@ ip6_raw_ctloutput(int op, struct socket 
 				in6p->in6p_cksum = optval;
 			break;
 
-		case PRCO_GETOPT:
+		case SOPT_GET:
 			if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
 				optval = icmp6off;
 			else
 				optval = in6p->in6p_cksum;
 
-			*mp = m = m_get(M_WAIT, MT_SOOPTS);
-			m->m_len = sizeof(int);
-			*mtod(m, int *) = optval;
+			error = sockopt_set(sopt, &optval, sizeof(optval));
 			break;
 
 		default:
@@ -2148,9 +2174,6 @@ ip6_raw_ctloutput(int op, struct socket 
 		break;
 	}
 
-	if (op == PRCO_SETOPT && m)
-		(void)m_free(m);
-
 	return (error);
 }
 
@@ -2160,7 +2183,8 @@ ip6_raw_ctloutput(int op, struct socket 
  * 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 mbuf *m, struct socket *so,
+    struct sockopt *sopt)
 {
 	struct ip6_pktopts *opt = *pktopt;
 	int error = 0;
@@ -2236,7 +2260,7 @@ ip6_pcbopt(int optname, u_char *buf, int
 }
 
 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;
@@ -2245,7 +2269,6 @@ ip6_getpcbopt(struct ip6_pktopts *pktopt
 	struct in6_pktinfo null_pktinfo;
 	int deftclass = 0, on;
 	int defminmtu = IP6PO_MINMTU_MCASTONLY;
-	struct mbuf *m;
 
 	switch (optname) {
 	case IPV6_PKTINFO:
@@ -2324,14 +2347,7 @@ ip6_getpcbopt(struct ip6_pktopts *pktopt
 		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);
 }
Index: netinet6/ip6_var.h
===================================================================
RCS file: /usr/cvs/src/sys/netinet6/ip6_var.h,v
retrieving revision 1.46
diff -u -p -r1.46 ip6_var.h
--- netinet6/ip6_var.h	29 Oct 2007 16:54:43 -0000	1.46
+++ netinet6/ip6_var.h	13 Dec 2007 15:42:15 -0000
@@ -64,6 +64,7 @@
 #ifndef _NETINET6_IP6_VAR_H_
 #define _NETINET6_IP6_VAR_H_
 
+#include <sys/socketvar.h>
 #include <net/route.h>
 
 /*
@@ -311,7 +312,7 @@ extern int	ip6_hashsize;		/* size of has
 
 struct in6pcb;
 
-int	icmp6_ctloutput(int, struct socket *, int, int, struct mbuf **);
+int	icmp6_ctloutput(struct socket *, struct sockopt *);
 
 void	ip6_init(void);
 void	ip6intr(void);
@@ -345,8 +346,8 @@ int	ip6_output(struct mbuf *, struct ip6
 			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(struct socket *, struct sockopt *);
+int	ip6_raw_ctloutput(struct socket *, struct sockopt *);
 void	ip6_initpktopts(struct ip6_pktopts *);
 int	ip6_setpktopts(struct mbuf *, struct ip6_pktopts *,
 			    struct ip6_pktopts *, int, int);
@@ -370,7 +371,7 @@ int	ip6flow_invalidate_all(int);
 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(struct socket *, struct sockopt *);
 int	rip6_output(struct mbuf *, struct socket *, struct sockaddr_in6 *,
 			 struct mbuf *);
 int	rip6_usrreq(struct socket *,
Index: netinet6/ip6protosw.h
===================================================================
RCS file: /usr/cvs/src/sys/netinet6/ip6protosw.h,v
retrieving revision 1.19
diff -u -p -r1.19 ip6protosw.h
--- netinet6/ip6protosw.h	19 Jul 2007 20:48:57 -0000	1.19
+++ netinet6/ip6protosw.h	13 Dec 2007 22:35:44 -0000
@@ -126,7 +126,7 @@ struct ip6protosw {
 	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 **);
+			(struct socket *, struct sockopt *);
 
 /* user-protocol hook */
 	int	(*pr_usrreq)		/* user request: see list below */
Index: netinet6/raw_ip6.c
===================================================================
RCS file: /usr/cvs/src/sys/netinet6/raw_ip6.c,v
retrieving revision 1.91
diff -u -p -r1.91 raw_ip6.c
--- netinet6/raw_ip6.c	27 Nov 2007 22:45:30 -0000	1.91
+++ netinet6/raw_ip6.c	29 Dec 2007 12:40:33 -0000
@@ -552,25 +552,35 @@ rip6_output(struct mbuf *m, struct socke
  * Raw IPv6 socket option processing.
  */
 int
-rip6_ctloutput(int op, struct socket *so, int level, int optname,
-    struct mbuf **mp)
+rip6_ctloutput(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);
+		if (sopt->sopt_dir == SOPT_GET) {
+			optval = 1;
+			error = sockopt_set(sopt, &optval, sizeof(optval));
+		} else if (sopt->sopt_dir == SOPT_SET) {
+			void *v;
+
+			v = sockopt_getintptr(sopt);
+			if (v == NULL) {
+				error = EINVAL;
+				goto out;
+			}
+			optval = *((int *)v);
+			if (optval == 0)
+				error = EINVAL;
+		}
+
+		goto out;
+	} else if (sopt->sopt_level != IPPROTO_IPV6)
+		return ip6_ctloutput(so, sopt);
 
-	switch (optname) {
+	switch (sopt->sopt_name) {
 	case MRT6_INIT:
 	case MRT6_DONE:
 	case MRT6_ADD_MIF:
@@ -578,21 +588,19 @@ rip6_ctloutput(int op, struct socket *so
 	case MRT6_ADD_MFC:
 	case MRT6_DEL_MFC:
 	case MRT6_PIM:
-		if (op == PRCO_SETOPT)
-			error = ip6_mrouter_set(optname, so, *mp);
-		else if (op == PRCO_GETOPT)
-			error = ip6_mrouter_get(optname, so, mp);
+		if (sopt->sopt_dir == SOPT_SET)
+			error = ip6_mrouter_set(so, sopt);
+		else if (sopt->sopt_dir == SOPT_GET)
+			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(so, sopt);
 	default:
-		return ip6_ctloutput(op, so, level, optname, mp);
+		return ip6_ctloutput(so, sopt);
 	}
-free_m:
-	if (op == PRCO_SETOPT && *mp != NULL)
-		m_free(*mp);
+ out:
 	return error;
 }
 
Index: netiso/clnp.h
===================================================================
RCS file: /usr/cvs/src/sys/netiso/clnp.h,v
retrieving revision 1.25
diff -u -p -r1.25 clnp.h
--- netiso/clnp.h	25 Dec 2007 18:33:48 -0000	1.25
+++ netiso/clnp.h	26 Dec 2007 22:33:49 -0000
@@ -513,7 +513,7 @@ void clnp_ctloutput (void);
 /* 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 (struct socket *, struct sockopt *);
 int clnp_usrreq (struct socket *, int, struct mbuf *, struct mbuf *,
 		     struct mbuf *, struct lwp *);
 
Index: netiso/clnp_raw.c
===================================================================
RCS file: /usr/cvs/src/sys/netiso/clnp_raw.c,v
retrieving revision 1.28
diff -u -p -r1.28 clnp_raw.c
--- netiso/clnp_raw.c	2 May 2007 20:40:28 -0000	1.28
+++ netiso/clnp_raw.c	26 Dec 2007 20:31:07 -0000
@@ -197,60 +197,66 @@ rclnp_output(struct mbuf *m0, ...)
  */
 int
 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 */
+	struct mbuf *m;
+
+	m = sockopt_getmbuf(sopt);
+	if (m == NULL)
+		return (ENOBUFS);
 
 #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);
+		    sopt->sopt_dir, sopt->sopt_level, sopt->sopt_name);
+		if (m != NULL) {
+			printf("rclnp_ctloutput: %d bytes of mbuf data\n", (m)->m_len);
+			dump_buf(mtod((m), void *), (m)->m_len);
 		}
 	}
 #endif
 
 #ifdef SOL_NETWORK
-	if (level != SOL_NETWORK)
+	if (sopt->sopt_level != SOL_NETWORK)
 		error = EINVAL;
 	else
-		switch (op) {
+		switch (sopt->sopt_dir) {
 #else
-	switch (op) {
+	switch (sopt->sopt_dir) {
 #endif				/* SOL_NETWORK */
-	case PRCO_SETOPT:
-		switch (optname) {
+	case SOPT_SET:
+		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 *));
-
-				if ((usr_flags & (CLNP_VFLAGS)) != usr_flags) {
-					error = EINVAL;
-				} else
-					rp->risop_flags |= usr_flags;
+			u_short         usr_flags;
+
+			/*
+			 * Insure that the data passed has exactly
+			 * one short in it
+			 */
+			m = sockopt_getmbuf(sopt);
+			if (m == NULL) {
+				error = ENOBUFS;
+				break;
+			}
+
+			usr_flags = (*mtod(m, short *));
 
-			} break;
+			/*
+			 *	Don't allow invalid flags to be set
+			 */
+			if ((usr_flags & (CLNP_VFLAGS)) != usr_flags) {
+				error = EINVAL;
+			} else
+				rp->risop_flags |= usr_flags;
 
-		case CLNPOPT_OPTS:
-			error = clnp_set_opts(&rp->risop_isop.isop_options, m);
+			break;
+			}
+
+		case CLNPOPT_OPTS: {
+			error = clnp_set_opts(&rp->risop_isop.isop_options, &m);
 			if (error)
 				break;
 			rp->risop_isop.isop_optindex = m_get(M_WAIT, MT_SOOPTS);
@@ -260,13 +266,14 @@ rclnp_ctloutput(
 					  mtod(rp->risop_isop.isop_optindex,
 					       struct clnp_optidx *));
 			break;
+			}
 		}
 		break;
 
-	case PRCO_GETOPT:
+	case SOPT_GET:
 #ifdef notdef
 		/* commented out to keep hi C quiet */
-		switch (optname) {
+		switch (sopt->sopt_name) {
 		default:
 			error = EINVAL;
 			break;
@@ -277,11 +284,6 @@ rclnp_ctloutput(
 		error = EINVAL;
 		break;
 	}
-	if (op == PRCO_SETOPT) {
-		/* note: m_freem does not barf is *m is NULL */
-		m_freem(*m);
-		*m = NULL;
-	}
 	return error;
 }
 
Index: netiso/iso.c
===================================================================
RCS file: /usr/cvs/src/sys/netiso/iso.c,v
retrieving revision 1.48
diff -u -p -r1.48 iso.c
--- netiso/iso.c	6 Dec 2007 00:28:36 -0000	1.48
+++ netiso/iso.c	7 Dec 2007 17:07:07 -0000
@@ -512,7 +512,7 @@ iso_control(struct socket *so, u_long cm
 		if (l == 0 || kauth_authorize_network(l->l_cred,
 		    KAUTH_NETWORK_INTERFACE,
 		    KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
-		    NULL))
+		    ifr))
 			return (EPERM);
 
 		if (ifp == 0)
Index: netiso/iso_pcb.c
===================================================================
RCS file: /usr/cvs/src/sys/netiso/iso_pcb.c,v
retrieving revision 1.42
diff -u -p -r1.42 iso_pcb.c
--- netiso/iso_pcb.c	14 Jan 2008 04:17:35 -0000	1.42
+++ netiso/iso_pcb.c	15 Jan 2008 11:55:36 -0000
@@ -223,8 +223,8 @@ iso_pcbbind(void *v, struct mbuf *nam, s
 		bcopy(TSEL(siso), suf.data, sizeof(suf.data));
 		suf.s = ntohs(suf.s);
 		if (suf.s < ISO_PORT_RESERVED &&
-		    (l == NULL || kauth_authorize_generic(l->l_cred,
-		     KAUTH_GENERIC_ISSUSER, NULL)))
+		    kauth_authorize_generic(l->l_cred,
+		     KAUTH_GENERIC_ISSUSER, NULL))
 			return EACCES;
 	} else {
 		char  *cp;
@@ -351,8 +351,7 @@ iso_pcbconnect(void *v, struct mbuf *nam
 		const void *oldtsel;
 		siso = isop->isop_laddr;
 		if (siso == 0 || siso->siso_tlen == 0)
-			(void) iso_pcbbind(isop, (struct mbuf *)0,
-			    (struct lwp *)0);
+			(void) iso_pcbbind(isop, (struct mbuf *)0, l);
 		/*
 		 * Here we have problem of squezeing in a definite network address
 		 * into an existing sockaddr_iso, which in fact may not have room
Index: netiso/tp_output.c
===================================================================
RCS file: /usr/cvs/src/sys/netiso/tp_output.c,v
retrieving revision 1.34
diff -u -p -r1.34 tp_output.c
--- netiso/tp_output.c	9 Nov 2007 21:00:06 -0000	1.34
+++ netiso/tp_output.c	26 Dec 2007 20:36:16 -0000
@@ -386,8 +386,7 @@ done:
  * NOTES:
  */
 int
-tp_ctloutput(int cmd, struct socket  *so, int level, int optname,
-	struct mbuf **mp)
+tp_ctloutput(struct socket  *so, struct sockopt *sopt)
 {
 	struct lwp *l = curlwp;		/* XXX */
 	struct tp_pcb  *tpcb = sototpcb(so);
@@ -395,36 +394,33 @@ tp_ctloutput(int cmd, struct socket  *so
 	void *        value;
 	unsigned        val_len;
 	int             error = 0;
+	int cmd, level, optname;
+	struct mbuf *m;
+
+	cmd = sopt->sopt_dir;
+	level = sopt->sopt_level;
+	optname = sopt->sopt_name;
+	m = sockopt_getmbuf(sopt);
+	if (m == NULL)
+		return (ENOBUFS);
 
 #ifdef TPPT
 	if (tp_traceflags[D_REQUEST]) {
 		tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp",
-			cmd, so, optname, mp);
+			cmd, so, optname);
 	}
 #endif
 #ifdef ARGO_DEBUG
 	if (argo_debug[D_REQUEST]) {
 		printf(
-		       "tp_ctloutput so %p cmd 0x%x optname 0x%x, mp %p *mp %p tpcb %p\n",
-		       so, cmd, optname, mp, mp ? *mp : 0, tpcb);
+		       "tp_ctloutput so %p cmd 0x%x optname 0x%x, tpcb %p\n",
+		       so, cmd, optname, tpcb);
 	}
 #endif
 	if (tpcb == (struct tp_pcb *) 0) {
 		error = ENOTSOCK;
 		goto done;
 	}
-	if (mp && *mp == NULL) {
-		struct mbuf *m;
-
-		MGET(m, M_DONTWAIT, TPMT_SONAME);	/* does off, type, next */
-		if (m == NULL) {
-			splx(s);
-			return ENOBUFS;
-		}
-		m->m_len = 0;
-		m->m_nextpkt = 0;
-		*mp = m;
-	}
 	/*
 	 *	Hook so one can set network options via a tp socket.
 	 */
@@ -435,10 +431,10 @@ tp_ctloutput(int cmd, struct socket  *so
 			error = EOPNOTSUPP;
 		else
 			return ((tpcb->tp_nlproto->nlp_ctloutput) (cmd, optname,
-						       tpcb->tp_npcb, *mp));
+						       tpcb->tp_npcb, m));
 		goto done;
 	} else if (level == SOL_SOCKET) {
-		if (optname == SO_RCVBUF && cmd == PRCO_SETOPT) {
+		if (optname == SO_RCVBUF && cmd == SOPT_SET) {
 			u_long          old_credit = tpcb->tp_maxlcredit;
 			tp_rsyset(tpcb);
 			if (tpcb->tp_rhiwat != so->so_rcv.sb_hiwat &&
@@ -453,7 +449,7 @@ tp_ctloutput(int cmd, struct socket  *so
 		error = EOPNOTSUPP;
 		goto done;
 	}
-	if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) {
+	if (cmd != SOPT_GET && cmd != SOPT_SET) {
 		error = EOPNOTSUPP;
 		goto done;
 	}
@@ -467,7 +463,7 @@ tp_ctloutput(int cmd, struct socket  *so
 	 */
 	if (((so->so_state & SS_ISCONNECTING) || (so->so_state & SS_ISCONNECTED))
 	    &&
-	    (cmd == PRCO_SETOPT &&
+	    (cmd == SOPT_SET &&
 	     optname != TPOPT_DISC_DATA &&
 	     optname != TPOPT_CFRM_DATA &&
 	     optname != TPOPT_PERF_MEAS &&
@@ -491,12 +487,11 @@ tp_ctloutput(int cmd, struct socket  *so
 			goto done;
 		}
 	}
-	value = mtod(*mp, void *);	/* it's aligned, don't worry, but
+	value = mtod(m, void *);	/* it's aligned, don't worry, but
 					 * lint complains about it */
-	val_len = (*mp)->m_len;
+	val_len = (m)->m_len;
 
 	switch (optname) {
-
 	case TPOPT_INTERCEPT:
 #define INA(t) (((struct inpcb *)(t->tp_npcb))->inp_laddr.s_addr)
 #define ISOA(t) (((struct isopcb *)(t->tp_npcb))->isop_laddr->siso_addr)
@@ -504,7 +499,7 @@ tp_ctloutput(int cmd, struct socket  *so
 		if (l == 0 || (error = kauth_authorize_generic(l->l_cred,
 		    KAUTH_GENERIC_ISSUSER, NULL))) {
 			error = EPERM;
-		} else if (cmd != PRCO_SETOPT || tpcb->tp_state != TP_CLOSED ||
+		} else if (cmd != SOPT_SET || tpcb->tp_state != TP_CLOSED ||
 			   (tpcb->tp_flags & TPF_GENERAL_ADDR) ||
 			   tpcb->tp_next == 0)
 			error = EINVAL;
@@ -542,14 +537,14 @@ tp_ctloutput(int cmd, struct socket  *so
 		break;
 
 	case TPOPT_MY_TSEL:
-		if (cmd == PRCO_GETOPT) {
+		if (cmd == SOPT_GET) {
 			ASSERT(tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN);
 			bcopy((void *) tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen);
-			(*mp)->m_len = tpcb->tp_lsuffixlen;
-		} else {	/* cmd == PRCO_SETOPT  */
+			(m)->m_len = tpcb->tp_lsuffixlen;
+		} else {	/* cmd == SOPT_SET  */
 			if ((val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0)) {
-				printf("val_len 0x%x (*mp)->m_len %p\n",
-				    val_len, (*mp));
+				printf("val_len 0x%x (m)->m_len %p\n",
+				    val_len, (m));
 				error = EINVAL;
 			} else {
 				bcopy(value, (void *) tpcb->tp_lsuffix, val_len);
@@ -559,14 +554,14 @@ tp_ctloutput(int cmd, struct socket  *so
 		break;
 
 	case TPOPT_PEER_TSEL:
-		if (cmd == PRCO_GETOPT) {
+		if (cmd == SOPT_GET) {
 			ASSERT(tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN);
 			bcopy((void *) tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen);
-			(*mp)->m_len = tpcb->tp_fsuffixlen;
-		} else {	/* cmd == PRCO_SETOPT  */
+			(m)->m_len = tpcb->tp_fsuffixlen;
+		} else {	/* cmd == SOPT_SET  */
 			if ((val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0)) {
-				printf("val_len 0x%x (*mp)->m_len %p\n",
-				    val_len, (*mp));
+				printf("val_len 0x%x (m)->m_len %p\n",
+				    val_len, (m));
 				error = EINVAL;
 			} else {
 				bcopy(value, (void *) tpcb->tp_fsuffix, val_len);
@@ -579,17 +574,17 @@ tp_ctloutput(int cmd, struct socket  *so
 #ifdef ARGO_DEBUG
 		if (argo_debug[D_REQUEST]) {
 			printf("%s TPOPT_FLAGS value %p *value 0x%x, flags 0x%x \n",
-			       cmd == PRCO_GETOPT ? "GET" : "SET",
+			       cmd == SOPT_GET ? "GET" : "SET",
 			       value,
 			       *(unsigned char *)value,
 			       tpcb->tp_flags);
 		}
 #endif
 
-		if (cmd == PRCO_GETOPT) {
+		if (cmd == SOPT_GET) {
 			*(int *) value = (int) tpcb->tp_flags;
-			(*mp)->m_len = sizeof(u_int);
-		} else {	/* cmd == PRCO_SETOPT  */
+			(m)->m_len = sizeof(u_int);
+		} else {	/* cmd == SOPT_SET  */
 			error = EINVAL;
 			goto done;
 		}
@@ -605,20 +600,20 @@ tp_ctloutput(int cmd, struct socket  *so
 #ifdef ARGO_DEBUG
 		if (argo_debug[D_SETPARAMS]) {
 			printf("TPOPT_PARAMS value %p, cmd %s \n", value,
-			       cmd == PRCO_GETOPT ? "GET" : "SET");
+			       cmd == SOPT_GET ? "GET" : "SET");
 		}
 #endif
 #ifdef ARGO_DEBUG
 		if (argo_debug[D_REQUEST]) {
 			printf("TPOPT_PARAMS value %p, cmd %s \n", value,
-			       cmd == PRCO_GETOPT ? "GET" : "SET");
+			       cmd == SOPT_GET ? "GET" : "SET");
 		}
 #endif
 
-		if (cmd == PRCO_GETOPT) {
+		if (cmd == SOPT_GET) {
 			*(struct tp_conn_param *) value = tpcb->_tp_param;
-			(*mp)->m_len = sizeof(tpcb->_tp_param);
-		} else {	/* cmd == PRCO_SETOPT  */
+			(m)->m_len = sizeof(tpcb->_tp_param);
+		} else {	/* cmd == SOPT_SET  */
 			if ((error =
 			     tp_consistency(tpcb, TP_STRICT | TP_FORCE,
 				    (struct tp_conn_param *) value)) == 0) {
@@ -627,24 +622,24 @@ tp_ctloutput(int cmd, struct socket  *so
 				 * of params
 				 */
 				tpcb->_tp_param = *(struct tp_conn_param *) value;
-				(*mp)->m_len = sizeof(tpcb->_tp_param);
+				(m)->m_len = sizeof(tpcb->_tp_param);
 			}
 		}
 		break;
 
 	case TPOPT_PSTATISTICS:
 #ifdef TP_PERF_MEAS
-		if (cmd == PRCO_SETOPT) {
+		if (cmd == SOPT_SET) {
 			error = EINVAL;
 			goto done;
 		}
 		if (tpcb->tp_perf_on) {
-			m_clget(*mp, M_WAIT);
-			if (((*mp)->m_flags & M_EXT) == 0) {
+			m_clget(m, M_WAIT);
+			if (((m)->m_flags & M_EXT) == 0) {
 				error = ENOBUFS; goto done;
 			}
-			(*mp)->m_len = sizeof(struct tp_pmeas);
-			bcopy(tpcb->tp_p_meas, mtod(*mp), sizeof(struct tp_pmeas));
+			(m)->m_len = sizeof(struct tp_pmeas);
+			bcopy(tpcb->tp_p_meas, mtod(m), sizeof(struct tp_pmeas));
 		}
 		else {
 			error = EINVAL;
@@ -657,7 +652,7 @@ tp_ctloutput(int cmd, struct socket  *so
 #endif				/* TP_PERF_MEAS */
 
 	case TPOPT_CDDATA_CLEAR:
-		if (cmd == PRCO_GETOPT) {
+		if (cmd == SOPT_GET) {
 			error = EINVAL;
 		} else {
 			if (tpcb->tp_ucddata) {
@@ -678,11 +673,11 @@ tp_ctloutput(int cmd, struct socket  *so
 		if (argo_debug[D_REQUEST]) {
 			printf("%s\n", optname == TPOPT_DISC_DATA ? "DISC data" : "CONN data");
 			printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%lx\n",
-			       (*mp)->m_len, val_len, so->so_snd.sb_cc);
+			       (m)->m_len, val_len, so->so_snd.sb_cc);
 			dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd ");
 		}
 #endif
-		if (cmd == PRCO_SETOPT) {
+		if (cmd == SOPT_SET) {
 			int             len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0;
 			/* can append connect data in several calls */
 			if (len + val_len >
@@ -690,12 +685,12 @@ tp_ctloutput(int cmd, struct socket  *so
 				error = EMSGSIZE;
 				goto done;
 			}
-			(*mp)->m_next = NULL;
-			(*mp)->m_nextpkt = 0;
+			(m)->m_next = NULL;
+			(m)->m_nextpkt = 0;
 			if (tpcb->tp_ucddata)
-				m_cat(tpcb->tp_ucddata, *mp);
+				m_cat(tpcb->tp_ucddata, m);
 			else
-				tpcb->tp_ucddata = *mp;
+				tpcb->tp_ucddata = m;
 #ifdef ARGO_DEBUG
 			if (argo_debug[D_REQUEST]) {
 				dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA");
@@ -707,7 +702,7 @@ tp_ctloutput(int cmd, struct socket  *so
 			      tpcb->tp_flags, so->so_snd.sb_cc, val_len, 0);
 			}
 #endif
-			*mp = NULL;
+			m = NULL;
 			if (optname == TPOPT_CFRM_DATA && (so->so_state & SS_ISCONFIRMING))
 				(void) tp_confirm(tpcb);
 		}
@@ -715,11 +710,11 @@ tp_ctloutput(int cmd, struct socket  *so
 
 	case TPOPT_PERF_MEAS:
 #ifdef TP_PERF_MEAS
-		if (cmd == PRCO_GETOPT) {
+		if (cmd == SOPT_GET) {
 			*value = (u_int) tpcb->tp_perf_on;
-			(*mp)->m_len = sizeof(u_int);
-		} else if (cmd == PRCO_SETOPT) {
-			(*mp)->m_len = 0;
+			(m)->m_len = sizeof(u_int);
+		} else if (cmd == SOPT_SET) {
+			(m)->m_len = 0;
 			if ((*value) != 0 && (*value) != 1)
 				error = EINVAL;
 			else
@@ -740,24 +735,24 @@ done:
 #ifdef ARGO_DEBUG
 	if (argo_debug[D_REQUEST]) {
 		dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end");
-		dump_mbuf(*mp, "tp_ctloutput *mp");
+		dump_mbuf(m, "tp_ctloutput m");
 	}
 #endif
 	/*
 	 * sigh: getsockopt looks only at m_len : all output data must reside
 	 * in the first mbuf
 	 */
-	if (*mp) {
-		if (cmd == PRCO_SETOPT) {
-			m_freem(*mp);
-			*mp = NULL;
+	if (m) {
+		if (cmd == SOPT_SET) {
+			m_freem(m);
+			m = NULL;
 		} else {
-			ASSERT(m_compress(*mp, mp) <= MLEN);
+			ASSERT(m_compress(m, &m) <= MLEN);
 			if (error)
-				(*mp)->m_len = 0;
+				(m)->m_len = 0;
 #ifdef ARGO_DEBUG
 			if (argo_debug[D_REQUEST]) {
-				dump_mbuf(*mp, "tp_ctloutput *mp after compress");
+				dump_mbuf(m, "tp_ctloutput m after compress");
 			}
 #endif
 		}
Index: netiso/tp_pcb.c
===================================================================
RCS file: /usr/cvs/src/sys/netiso/tp_pcb.c,v
retrieving revision 1.35
diff -u -p -r1.35 tp_pcb.c
--- netiso/tp_pcb.c	9 Nov 2007 21:00:06 -0000	1.35
+++ netiso/tp_pcb.c	13 Dec 2007 14:52:52 -0000
@@ -82,6 +82,7 @@ __KERNEL_RCSID(0, "$NetBSD: tp_pcb.c,v 1
 #include <sys/protosw.h>
 #include <sys/errno.h>
 #include <sys/time.h>
+#include <sys/kauth.h>
 
 #include <netiso/argo_debug.h>
 #include <netiso/tp_param.h>
Index: netiso/tp_usrreq.c
===================================================================
RCS file: /usr/cvs/src/sys/netiso/tp_usrreq.c,v
retrieving revision 1.33
diff -u -p -r1.33 tp_usrreq.c
--- netiso/tp_usrreq.c	9 Nov 2007 21:00:06 -0000	1.33
+++ netiso/tp_usrreq.c	26 Dec 2007 20:57:38 -0000
@@ -484,8 +484,7 @@ tp_usrreq(struct socket *so, int req, st
 		}
 #endif
 		if (tpcb->tp_lsuffixlen == 0) {
-			error = tp_pcbbind(tpcb, (struct mbuf *)0,
-			    (struct lwp *)0);
+			error = tp_pcbbind(tpcb, (struct mbuf *)0, l);
 			if (error) {
 #ifdef ARGO_DEBUG
 				if (argo_debug[D_CONN]) {
@@ -796,11 +795,19 @@ tp_snd_control(struct mbuf *m, struct so
 	int             error = 0;
 
 	if (m && m->m_len) {
+		struct sockopt sopt;
+
 		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);
+
+		memset(&sopt, 0, sizeof(sopt));
+		sopt.sopt_dir = SOPT_SET;
+		sopt.sopt_level = ch->cmsg_level;
+		sopt.sopt_name = ch->cmsg_type;
+		sockopt_set(&sopt, mtod(m, void *), m->m_len);
+		sopt.sopt_waitok = 1;
+		error = tp_ctloutput(so, &sopt);
 		if (ch->cmsg_type == TPOPT_DISC_DATA) {
 			if (data && *data) {
 				m_freem(*data);
Index: netiso/tp_var.h
===================================================================
RCS file: /usr/cvs/src/sys/netiso/tp_var.h,v
retrieving revision 1.15
diff -u -p -r1.15 tp_var.h
--- netiso/tp_var.h	4 Mar 2007 06:03:33 -0000	1.15
+++ netiso/tp_var.h	22 Dec 2007 21:14:34 -0000
@@ -118,7 +118,7 @@ void Tpmeas (u_int, u_int, struct timeva
 
 /* 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 (struct socket *, struct sockopt *);
 
 /* tp_pcb.c */
 void tp_init    (void);
Index: netsmb/smb_trantcp.c
===================================================================
RCS file: /usr/cvs/src/sys/netsmb/smb_trantcp.c,v
retrieving revision 1.31
diff -u -p -r1.31 smb_trantcp.c
--- netsmb/smb_trantcp.c	10 Jul 2007 21:05:03 -0000	1.31
+++ netsmb/smb_trantcp.c	22 Dec 2007 21:14:42 -0000
@@ -94,7 +94,7 @@ static int
 nb_setsockopt_int(struct socket *so, int level, int name, int val)
 {
 #ifdef __NetBSD__
-	return sosetopt(so, level, name, NULL); /* XXX */
+	return so_setsockopt(NULL, so, level, name, &val, sizeof(val));
 #else
 	struct sockopt sopt;
 
Index: nfs/nfs_boot.c
===================================================================
RCS file: /usr/cvs/src/sys/nfs/nfs_boot.c,v
retrieving revision 1.69
diff -u -p -r1.69 nfs_boot.c
--- nfs/nfs_boot.c	31 Aug 2007 22:02:58 -0000	1.69
+++ nfs/nfs_boot.c	16 Dec 2007 18:12:18 -0000
@@ -342,29 +342,24 @@ int
 nfs_boot_setrecvtimo(so)
 	struct socket *so;
 {
-	struct mbuf *m;
-	struct timeval *tv;
+	struct timeval tv;
+
+	tv.tv_sec = 1;
+	tv.tv_usec = 0;
 
-	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));
+	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
Index: nfs/nfs_bootdhcp.c
===================================================================
RCS file: /usr/cvs/src/sys/nfs/nfs_bootdhcp.c,v
retrieving revision 1.37
diff -u -p -r1.37 nfs_bootdhcp.c
--- nfs/nfs_bootdhcp.c	20 Dec 2007 16:19:38 -0000	1.37
+++ nfs/nfs_bootdhcp.c	21 Dec 2007 00:04:09 -0000
@@ -498,13 +498,11 @@ bootpc_call(nd, lwp)
 	 * 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 @@ bootpc_call(nd, lwp)
 	 * 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));
Index: nfs/nfs_socket.c
===================================================================
RCS file: /usr/cvs/src/sys/nfs/nfs_socket.c,v
retrieving revision 1.167
diff -u -p -r1.167 nfs_socket.c
--- nfs/nfs_socket.c	2 Jan 2008 19:26:46 -0000	1.167
+++ nfs/nfs_socket.c	7 Jan 2008 19:31:32 -0000
@@ -199,6 +199,7 @@ nfs_connect(nmp, rep, l)
 	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 @@ nfs_connect(nmp, rep, l)
 	 * 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 @@ nfs_connect(nmp, rep, l)
 	}
 #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);
@@ -320,18 +319,14 @@ nfs_connect(nmp, rep, l)
 		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;
Index: nfs/nfs_syscalls.c
===================================================================
RCS file: /usr/cvs/src/sys/nfs/nfs_syscalls.c,v
retrieving revision 1.130
diff -u -p -r1.130 nfs_syscalls.c
--- nfs/nfs_syscalls.c	2 Jan 2008 19:26:46 -0000	1.130
+++ nfs/nfs_syscalls.c	7 Jan 2008 19:31:32 -0000
@@ -388,12 +388,12 @@ nfssvc_addsock(fp, mynam)
 	struct file *fp;
 	struct mbuf *mynam;
 {
-	struct mbuf *m;
 	int siz;
 	struct nfssvc_sock *slp;
 	struct socket *so;
 	struct nfssvc_sock *tslp;
 	int error, s;
+	int val;
 
 	so = (struct socket *)fp->f_data;
 	tslp = (struct nfssvc_sock *)0;
@@ -436,11 +436,9 @@ nfssvc_addsock(fp, mynam)
 	 * 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
@@ -448,11 +446,9 @@ nfssvc_addsock(fp, mynam)
 #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));
 	}
 	so->so_rcv.sb_flags &= ~SB_NOINTR;
 	so->so_rcv.sb_timeo = 0;
Index: sys/protosw.h
===================================================================
RCS file: /usr/cvs/src/sys/sys/protosw.h,v
retrieving revision 1.42
diff -u -p -r1.42 protosw.h
--- sys/protosw.h	31 Mar 2007 18:17:13 -0000	1.42
+++ sys/protosw.h	13 Dec 2007 22:35:34 -0000
@@ -34,6 +34,8 @@
 #ifndef _SYS_PROTOSW_H_
 #define _SYS_PROTOSW_H_
 
+#include <sys/socketvar.h>	/* for struct sockopt */
+
 /*
  * Protocol switch table.
  *
@@ -78,7 +80,7 @@ struct protosw {
 	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 **);
+			(struct socket *, struct sockopt *);
 
 /* user-protocol hook */
 	int	(*pr_usrreq)		/* user request: see list below */
Index: sys/socketvar.h
===================================================================
RCS file: /usr/cvs/src/sys/sys/socketvar.h,v
retrieving revision 1.101
diff -u -p -r1.101 socketvar.h
--- sys/socketvar.h	16 Dec 2007 21:25:59 -0000	1.101
+++ sys/socketvar.h	29 Dec 2007 12:49:28 -0000
@@ -37,6 +37,7 @@
 #include <sys/select.h>
 #include <sys/selinfo.h>		/* for struct selinfo */
 #include <sys/queue.h>
+#include <sys/socket.h>			/* for socklen_t */
 
 #if !defined(_KERNEL) || defined(LKM)
 struct uio;
@@ -44,6 +45,8 @@ struct lwp;
 struct uidinfo;
 #endif
 
+struct sockopt;
+
 TAILQ_HEAD(soqhead, socket);
 
 /*
@@ -254,6 +257,20 @@ do {									\
 } while (/* CONSTCOND */ 0)
 
 #ifdef _KERNEL
+enum sopt_dir { SOPT_GET, SOPT_SET };
+struct sockopt {
+	enum sopt_dir sopt_dir;
+	int sopt_level;
+	int sopt_name;
+	union sopt_union {
+		int un_int;
+	} *sopt_un;
+	size_t sopt_size;
+	int sopt_waitok;
+	struct mbuf *sopt_m;
+	struct lwp *sopt_lwp;
+};
+
 extern u_long		sb_max;
 extern int		somaxkva;
 extern int		sock_loan_thresh;
@@ -318,7 +335,7 @@ int	socreate(int, struct socket **, int,
 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 *);
@@ -335,11 +352,22 @@ int	soreserve(struct socket *, u_long, u
 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	soshutdown(struct socket *, int);
 void	sowakeup(struct socket *, struct sockbuf *, int);
 int	sockargs(struct mbuf **, const void *, size_t, int);
 
+int	so_setsockopt(struct lwp *, struct socket *, int, int, void *, socklen_t);
+int	sockopt_setmbuf(struct sockopt *, struct mbuf *);
+struct mbuf *
+	sockopt_getmbuf(const struct sockopt *);
+int	sockopt_set(struct sockopt *, const void *, size_t);
+void *
+	sockopt_get(const struct sockopt *, size_t);
+int	sockopt_setint(struct sockopt *, int);
+int *	sockopt_getintptr(const struct sockopt *);
+void	sockopt_destroy(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 *);
Index: sys/un.h
===================================================================
RCS file: /usr/cvs/src/sys/sys/un.h,v
retrieving revision 1.40
diff -u -p -r1.40 un.h
--- sys/un.h	9 Aug 2007 15:23:01 -0000	1.40
+++ sys/un.h	18 Jan 2008 16:31:05 -0000
@@ -73,10 +73,11 @@ struct unpcbid {
 #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(struct socket *, struct sockopt *);
 
 int	unp_attach (struct socket *);
 int	unp_bind (struct unpcb *, struct mbuf *, struct lwp *);
