diff options
| author | Garrett Wollman <wollman@FreeBSD.org> | 1998-08-23 03:07:17 +0000 |
|---|---|---|
| committer | Garrett Wollman <wollman@FreeBSD.org> | 1998-08-23 03:07:17 +0000 |
| commit | cfe8b629f1f13b06fa1aec801248b7e431e48aba (patch) | |
| tree | 3eeab04394efe1f50741907aeba96200abbaf6d2 /sys/kern | |
| parent | bdad325c19fcba9b0c6bd42495fa1ae0eda6c2fb (diff) | |
Notes
Diffstat (limited to 'sys/kern')
| -rw-r--r-- | sys/kern/uipc_proto.c | 3 | ||||
| -rw-r--r-- | sys/kern/uipc_socket.c | 243 | ||||
| -rw-r--r-- | sys/kern/uipc_syscalls.c | 78 |
3 files changed, 183 insertions, 141 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 (level != SOL_SOCKET) { + if (sopt->sopt_p != 0) + return (copyin(sopt->sopt_val, buf, valsize)); + + 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); + 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; - break; - } + 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); } |
