aboutsummaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorGarrett Wollman <wollman@FreeBSD.org>1998-08-23 03:07:17 +0000
committerGarrett Wollman <wollman@FreeBSD.org>1998-08-23 03:07:17 +0000
commitcfe8b629f1f13b06fa1aec801248b7e431e48aba (patch)
tree3eeab04394efe1f50741907aeba96200abbaf6d2 /sys/kern
parentbdad325c19fcba9b0c6bd42495fa1ae0eda6c2fb (diff)
downloadsrc-cfe8b629f1f13b06fa1aec801248b7e431e48aba.tar.gz
src-cfe8b629f1f13b06fa1aec801248b7e431e48aba.zip
Yow! Completely change the way socket options are handled, eliminating
another specialized mbuf type in the process. Also clean up some of the cruft surrounding IPFW, multicast routing, RSVP, and other ill-explored corners.
Notes
Notes: svn path=/head/; revision=38482
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/uipc_proto.c3
-rw-r--r--sys/kern/uipc_socket.c245
-rw-r--r--sys/kern/uipc_syscalls.c78
3 files changed, 184 insertions, 142 deletions
diff --git a/sys/kern/uipc_proto.c b/sys/kern/uipc_proto.c
index d87e14826b09..094d1bf16bbb 100644
--- a/sys/kern/uipc_proto.c
+++ b/sys/kern/uipc_proto.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)uipc_proto.c 8.1 (Berkeley) 6/10/93
- * $Id: uipc_proto.c,v 1.15 1998/05/15 20:11:29 wollman Exp $
+ * $Id: uipc_proto.c,v 1.16 1998/06/21 14:53:18 bde Exp $
*/
#include <sys/param.h>
@@ -41,6 +41,7 @@
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/un.h>
+#include <sys/unpcb.h>
#include <net/raw_cb.h>
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index 5abd6fe48e33..f429434fea12 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)uipc_socket.c 8.3 (Berkeley) 4/15/94
- * $Id: uipc_socket.c,v 1.41 1998/07/06 19:27:14 fenner Exp $
+ * $Id: uipc_socket.c,v 1.42 1998/07/18 18:48:45 fenner Exp $
*/
#include <sys/param.h>
@@ -898,31 +898,69 @@ sorflush(so)
sbrelease(&asb);
}
+/*
+ * Perhaps this routine, and sooptcopyout(), below, ought to come in
+ * an additional variant to handle the case where the option value needs
+ * to be some kind of integer, but not a specific size.
+ * In addition to their use here, these functions are also called by the
+ * protocol-level pr_ctloutput() routines.
+ */
int
-sosetopt(so, level, optname, m0, p)
- register struct socket *so;
- int level, optname;
- struct mbuf *m0;
- struct proc *p;
+sooptcopyin(sopt, buf, len, minlen)
+ struct sockopt *sopt;
+ void *buf;
+ size_t len;
+ size_t minlen;
{
- int error = 0;
- register struct mbuf *m = m0;
+ size_t valsize;
+
+ /*
+ * If the user gives us more than we wanted, we ignore it,
+ * but if we don't get the minimum length the caller
+ * wants, we return EINVAL. On success, sopt->sopt_valsize
+ * is set to however much we actually retrieved.
+ */
+ if ((valsize = sopt->sopt_valsize) < minlen)
+ return EINVAL;
+ if (valsize > len)
+ sopt->sopt_valsize = valsize = len;
+
+ if (sopt->sopt_p != 0)
+ return (copyin(sopt->sopt_val, buf, valsize));
- if (level != SOL_SOCKET) {
+ bcopy(sopt->sopt_val, buf, valsize);
+ return 0;
+}
+
+int
+sosetopt(so, sopt)
+ struct socket *so;
+ struct sockopt *sopt;
+{
+ int error, optval;
+ struct linger l;
+ struct timeval tv;
+ short val;
+
+ error = 0;
+ if (sopt->sopt_level != SOL_SOCKET) {
if (so->so_proto && so->so_proto->pr_ctloutput)
return ((*so->so_proto->pr_ctloutput)
- (PRCO_SETOPT, so, level, optname, &m0, p));
+ (so, sopt));
error = ENOPROTOOPT;
} else {
- switch (optname) {
-
+ switch (sopt->sopt_name) {
case SO_LINGER:
- if (m == NULL || m->m_len != sizeof (struct linger)) {
- error = EINVAL;
+ error = sooptcopyin(sopt, &l, sizeof l, sizeof l);
+ if (error)
goto bad;
- }
- so->so_linger = mtod(m, struct linger *)->l_linger;
- /* fall thru... */
+
+ so->so_linger = l.l_linger;
+ if (l.l_onoff)
+ so->so_options |= SO_LINGER;
+ else
+ so->so_options &= ~SO_LINGER;
+ break;
case SO_DEBUG:
case SO_KEEPALIVE:
@@ -933,45 +971,40 @@ sosetopt(so, level, optname, m0, p)
case SO_REUSEPORT:
case SO_OOBINLINE:
case SO_TIMESTAMP:
- if (m == NULL || m->m_len < sizeof (int)) {
- error = EINVAL;
+ error = sooptcopyin(sopt, &optval, sizeof optval,
+ sizeof optval);
+ if (error)
goto bad;
- }
- if (*mtod(m, int *))
- so->so_options |= optname;
+ 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:
- {
- int optval;
-
- if (m == NULL || m->m_len < sizeof (int)) {
- error = EINVAL;
+ error = sooptcopyin(sopt, &optval, sizeof optval,
+ sizeof optval);
+ if (error)
goto bad;
- }
/*
* Values < 1 make no sense for any of these
* options, so disallow them.
*/
- optval = *mtod(m, int *);
if (optval < 1) {
error = EINVAL;
goto bad;
}
- switch (optname) {
-
+ switch (sopt->sopt_name) {
case SO_SNDBUF:
case SO_RCVBUF:
- if (sbreserve(optname == SO_SNDBUF ?
- &so->so_snd : &so->so_rcv,
- (u_long) optval) == 0) {
+ if (sbreserve(sopt->sopt_name == SO_SNDBUF ?
+ &so->so_snd : &so->so_rcv,
+ (u_long) optval) == 0) {
error = ENOBUFS;
goto bad;
}
@@ -993,27 +1026,21 @@ sosetopt(so, level, optname, m0, p)
break;
}
break;
- }
case SO_SNDTIMEO:
case SO_RCVTIMEO:
- {
- struct timeval *tv;
- short val;
-
- if (m == NULL || m->m_len < sizeof (*tv)) {
- error = EINVAL;
+ error = sooptcopyin(sopt, &tv, sizeof tv,
+ sizeof tv);
+ if (error)
goto bad;
- }
- tv = mtod(m, struct timeval *);
- if (tv->tv_sec > SHRT_MAX / hz - hz) {
+
+ if (tv.tv_sec > SHRT_MAX / hz - hz) {
error = EDOM;
goto bad;
}
- val = tv->tv_sec * hz + tv->tv_usec / tick;
-
- switch (optname) {
+ val = tv.tv_sec * hz + tv.tv_usec / tick;
+ switch (sopt->sopt_name) {
case SO_SNDTIMEO:
so->so_snd.sb_timeo = val;
break;
@@ -1022,7 +1049,6 @@ sosetopt(so, level, optname, m0, p)
break;
}
break;
- }
default:
error = ENOPROTOOPT;
@@ -1030,42 +1056,69 @@ sosetopt(so, level, optname, m0, p)
}
if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) {
(void) ((*so->so_proto->pr_ctloutput)
- (PRCO_SETOPT, so, level, optname, &m0, p));
- m = NULL; /* freed by protocol */
+ (so, sopt));
}
}
bad:
- if (m)
- (void) m_free(m);
return (error);
}
+/* Helper routine for getsockopt */
int
-sogetopt(so, level, optname, mp, p)
- register struct socket *so;
- int level, optname;
- struct mbuf **mp;
- struct proc *p;
+sooptcopyout(sopt, buf, len)
+ struct sockopt *sopt;
+ void *buf;
+ size_t len;
{
- register struct mbuf *m;
+ int error;
+ size_t valsize;
+
+ error = 0;
+
+ /*
+ * Documented get behavior is that we always return a value,
+ * possibly truncated to fit in the user's buffer.
+ * We leave the correct length in sopt->sopt_valsize,
+ * to be copied out in getsockopt(). Note that this
+ * interface is not idempotent; the entire answer must
+ * generated ahead of time.
+ */
+ valsize = len;
+ if (sopt->sopt_valsize < valsize) {
+ valsize = sopt->sopt_valsize;
+ sopt->sopt_valsize = len;
+ }
+ if (sopt->sopt_val != 0) {
+ if (sopt->sopt_p != 0)
+ error = copyout(buf, sopt->sopt_val, valsize);
+ else
+ bcopy(buf, sopt->sopt_val, valsize);
+ }
+ return error;
+}
+
+int
+sogetopt(so, sopt)
+ struct socket *so;
+ struct sockopt *sopt;
+{
+ int error, optval;
+ struct linger l;
+ struct timeval tv;
- if (level != SOL_SOCKET) {
+ error = 0;
+ 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, p));
+ (so, sopt));
} else
return (ENOPROTOOPT);
} else {
- m = m_get(M_WAIT, MT_SOOPTS);
- m->m_len = sizeof (int);
-
- switch (optname) {
-
+ switch (sopt->sopt_name) {
case SO_LINGER:
- m->m_len = sizeof (struct linger);
- mtod(m, struct linger *)->l_onoff =
- so->so_options & SO_LINGER;
- mtod(m, struct linger *)->l_linger = so->so_linger;
+ l.l_onoff = so->so_options & SO_LINGER;
+ l.l_linger = so->so_linger;
+ error = sooptcopyout(sopt, &l, sizeof l);
break;
case SO_USELOOPBACK:
@@ -1077,53 +1130,51 @@ sogetopt(so, level, optname, mp, p)
case SO_BROADCAST:
case SO_OOBINLINE:
case SO_TIMESTAMP:
- *mtod(m, int *) = so->so_options & optname;
+ optval = so->so_options & sopt->sopt_name;
+integer:
+ error = sooptcopyout(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 ?
- so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
-
- m->m_len = sizeof(struct timeval);
- mtod(m, struct timeval *)->tv_sec = val / hz;
- mtod(m, struct timeval *)->tv_usec =
- (val % hz) * tick;
- break;
- }
+ optval = (sopt->sopt_name == SO_SNDTIMEO ?
+ so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
+
+ tv.tv_sec = optval / hz;
+ tv.tv_usec = (optval % hz) * tick;
+ error = sooptcopyout(sopt, &tv, sizeof tv);
+ break;
default:
- (void)m_free(m);
- return (ENOPROTOOPT);
+ error = ENOPROTOOPT;
+ break;
}
- *mp = m;
- return (0);
+ return (error);
}
}
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index db764de593a9..a841bfad18c7 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94
- * $Id: uipc_syscalls.c,v 1.39 1998/04/14 06:24:43 phk Exp $
+ * $Id: uipc_syscalls.c,v 1.40 1998/06/10 10:30:23 dfr Exp $
*/
#include "opt_compat.h"
@@ -981,34 +981,26 @@ setsockopt(p, uap)
} */ *uap;
{
struct file *fp;
- struct mbuf *m = NULL;
+ struct sockopt sopt;
int error;
+ if (uap->val == 0 && uap->valsize != 0)
+ return (EFAULT);
+ if (uap->valsize < 0)
+ return (EINVAL);
+
error = getsock(p->p_fd, uap->s, &fp);
if (error)
return (error);
- if (uap->valsize > MCLBYTES)
- return (EINVAL);
- if (uap->val) {
- m = m_get(M_WAIT, MT_SOOPTS);
- if (m == NULL)
- return (ENOBUFS);
- if (uap->valsize > MLEN) {
- MCLGET(m, M_WAIT);
- if(!(m->m_flags & M_EXT)) {
- m_free(m);
- return (ENOBUFS);
- }
- }
- error = copyin(uap->val, mtod(m, caddr_t), (u_int)uap->valsize);
- if (error) {
- (void) m_free(m);
- return (error);
- }
- m->m_len = uap->valsize;
- }
- return (sosetopt((struct socket *)fp->f_data, uap->level,
- uap->name, m, p));
+
+ sopt.sopt_dir = SOPT_SET;
+ sopt.sopt_level = uap->level;
+ sopt.sopt_name = uap->name;
+ sopt.sopt_val = uap->val;
+ sopt.sopt_valsize = uap->valsize;
+ sopt.sopt_p = p;
+
+ return (sosetopt((struct socket *)fp->f_data, &sopt));
}
/* ARGSUSED */
@@ -1023,9 +1015,9 @@ getsockopt(p, uap)
int *avalsize;
} */ *uap;
{
- struct file *fp;
- struct mbuf *m = NULL, *m0;
- int op, i, valsize, error;
+ int valsize, error;
+ struct file *fp;
+ struct sockopt sopt;
error = getsock(p->p_fd, uap->s, &fp);
if (error)
@@ -1035,26 +1027,24 @@ getsockopt(p, uap)
sizeof (valsize));
if (error)
return (error);
+ if (valsize < 0)
+ return (EINVAL);
} else
valsize = 0;
- if ((error = sogetopt((struct socket *)fp->f_data, uap->level,
- uap->name, &m, p)) == 0 && uap->val && valsize && m != NULL) {
- op = 0;
- while (m && !error && op < valsize) {
- i = min(m->m_len, (valsize - op));
- error = copyout(mtod(m, caddr_t), uap->val, (u_int)i);
- op += i;
- uap->val += i;
- m0 = m;
- MFREE(m0,m);
- }
- valsize = op;
- if (error == 0)
- error = copyout((caddr_t)&valsize,
- (caddr_t)uap->avalsize, sizeof (valsize));
+
+ sopt.sopt_dir = SOPT_GET;
+ sopt.sopt_level = uap->level;
+ sopt.sopt_name = uap->name;
+ sopt.sopt_val = uap->val;
+ sopt.sopt_valsize = (size_t)valsize; /* checked non-negative above */
+ sopt.sopt_p = p;
+
+ error = sogetopt((struct socket *)fp->f_data, &sopt);
+ if (error == 0) {
+ valsize = sopt.sopt_valsize;
+ error = copyout((caddr_t)&valsize,
+ (caddr_t)uap->avalsize, sizeof (valsize));
}
- if (m != NULL)
- (void) m_free(m);
return (error);
}