summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorwollman <wollman@FreeBSD.org>1998-08-23 03:07:17 +0000
committerwollman <wollman@FreeBSD.org>1998-08-23 03:07:17 +0000
commita76fb5eefabdc9418c911bf0b61768d533c15cbd (patch)
tree02b1e59b8833c25c113cc2a72ebb74ec057423bb /sys/kern
parent3846bf0ec8c81eca47577791dff72e8b96928749 (diff)
downloadFreeBSD-src-a76fb5eefabdc9418c911bf0b61768d533c15cbd.zip
FreeBSD-src-a76fb5eefabdc9418c911bf0b61768d533c15cbd.tar.gz
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.
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 d87e148..094d1bf 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 5abd6fe..f429434 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 db764de..a841bfa 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);
}
OpenPOWER on IntegriCloud