Date: Tue, 4 Aug 1998 21:47:05 -0400 (EDT) From: Garrett Wollman <wollman@khavrinen.lcs.mit.edu> To: net@FreeBSD.ORG Subject: Socket option processing changes Message-ID: <199808050147.VAA05270@khavrinen.lcs.mit.edu>
next in thread | raw e-mail | index | archive | help
Here's a patch I am presently developing. It works on my machine (or, rather, hasn't crashed yet). It does not include support for anything that isn't included in my laptop's config file. This is the last of the ``easy'' mbuf types to remove... The standard behavior of returning EINVAL when the provided option buffer is too short ought to be documented. If you have a patch for your favorite protocol or option set, please send it to me. Obviously, I'd like some other reports of success or failure. -GAWollman Index: kern/uipc_proto.c =================================================================== RCS file: /home/cvs/src/sys/kern/uipc_proto.c,v retrieving revision 1.16 diff -u -r1.16 uipc_proto.c --- uipc_proto.c 1998/06/21 14:53:18 1.16 +++ uipc_proto.c 1998/08/05 01:25:02 @@ -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> Index: kern/uipc_socket.c =================================================================== RCS file: /home/cvs/src/sys/kern/uipc_socket.c,v retrieving revision 1.42 diff -u -r1.42 uipc_socket.c --- uipc_socket.c 1998/07/18 18:48:45 1.42 +++ uipc_socket.c 1998/08/05 01:25:02 @@ -898,31 +898,69 @@ 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 (level != SOL_SOCKET) { + /* + * 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)); + + 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 @@ 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 @@ 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 @@ break; } break; - } default: error = ENOPROTOOPT; @@ -1030,42 +1056,69 @@ } 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; +} - if (level != SOL_SOCKET) { +int +sogetopt(so, sopt) + struct socket *so; + struct sockopt *sopt; +{ + int error, optval; + struct linger l; + struct timeval tv; + + 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 @@ 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); } } Index: kern/uipc_syscalls.c =================================================================== RCS file: /home/cvs/src/sys/kern/uipc_syscalls.c,v retrieving revision 1.40 diff -u -r1.40 uipc_syscalls.c --- uipc_syscalls.c 1998/06/10 10:30:23 1.40 +++ uipc_syscalls.c 1998/08/05 01:25:02 @@ -981,34 +981,26 @@ } */ *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 @@ 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 @@ 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); } Index: net/if_vlan.c =================================================================== RCS file: /home/cvs/src/sys/net/if_vlan.c,v retrieving revision 1.2 diff -u -r1.2 if_vlan.c --- if_vlan.c 1998/05/15 20:02:47 1.2 +++ if_vlan.c 1998/08/05 01:25:06 @@ -80,7 +80,7 @@ static void vlan_start(struct ifnet *ifp); static void vlan_ifinit(void *foo); -static int vlan_ioctl(struct ifnet *ifp, int cmd, caddr_t addr); +static int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr); static void vlaninit(void *dummy) @@ -262,7 +262,7 @@ } static int -vlan_ioctl(struct ifnet *ifp, int cmd, caddr_t data) +vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ifaddr *ifa; struct ifnet *p; Index: netinet/in.h =================================================================== RCS file: /home/cvs/src/sys/netinet/in.h,v retrieving revision 1.36 diff -u -r1.36 in.h --- in.h 1998/07/06 03:20:12 1.36 +++ in.h 1998/08/05 01:25:07 @@ -429,21 +429,6 @@ int in_localaddr __P((struct in_addr)); char *inet_ntoa __P((struct in_addr)); /* in libkern */ -/* Firewall hooks */ -struct ip; -typedef int ip_fw_chk_t __P((struct ip**, int, struct ifnet*, u_int16_t*, struct mbuf**, struct sockaddr_in**)); -typedef int ip_fw_ctl_t __P((int, struct mbuf**)); -extern ip_fw_chk_t *ip_fw_chk_ptr; -extern ip_fw_ctl_t *ip_fw_ctl_ptr; - -/* IP NAT hooks */ -typedef int ip_nat_t __P((struct ip**, struct mbuf**, struct ifnet*, int)); -typedef int ip_nat_ctl_t __P((int, struct mbuf**)); -extern ip_nat_t *ip_nat_ptr; -extern ip_nat_ctl_t *ip_nat_ctl_ptr; -#define IP_NAT_IN 0x00000001 -#define IP_NAT_OUT 0x00000002 - #endif /* KERNEL */ #endif Index: netinet/in_proto.c =================================================================== RCS file: /home/cvs/src/sys/netinet/in_proto.c,v retrieving revision 1.46 diff -u -r1.46 in_proto.c --- in_proto.c 1998/03/21 11:33:57 1.46 +++ in_proto.c 1998/08/05 01:25:07 @@ -71,15 +71,6 @@ #include <netns/ns_if.h> #endif -#ifdef TPIP -void tpip_input(), tpip_ctlinput(), tp_init(), tp_slowtimo(), tp_drain(); -int tp_ctloutput(), tp_usrreq(); -#endif - -#ifdef EON -void eoninput(), eonctlinput(), eonprotoinit(); -#endif /* EON */ - extern struct domain inetdomain; static struct pr_usrreqs nousrreqs; Index: netinet/ip_fw.h =================================================================== RCS file: /home/cvs/src/sys/netinet/ip_fw.h,v retrieving revision 1.33 diff -u -r1.33 ip_fw.h --- ip_fw.h 1998/07/06 03:20:15 1.33 +++ ip_fw.h 1998/08/05 01:25:07 @@ -184,6 +184,23 @@ */ void ip_fw_init __P((void)); +/* Firewall hooks */ +struct ip; +struct sockopt; +typedef int ip_fw_chk_t __P((struct ip **, int, struct ifnet *, u_int16_t *, + struct mbuf **, struct sockaddr_in **)); +typedef int ip_fw_ctl_t __P((struct sockopt *)); +extern ip_fw_chk_t *ip_fw_chk_ptr; +extern ip_fw_ctl_t *ip_fw_ctl_ptr; + +/* IP NAT hooks */ +typedef int ip_nat_t __P((struct ip **, struct mbuf **, struct ifnet *, int)); +typedef int ip_nat_ctl_t __P((struct sockopt *)); +extern ip_nat_t *ip_nat_ptr; +extern ip_nat_ctl_t *ip_nat_ctl_ptr; +#define IP_NAT_IN 0x00000001 +#define IP_NAT_OUT 0x00000002 + #endif /* KERNEL */ #endif /* _IP_FW_H */ Index: netinet/ip_input.c =================================================================== RCS file: /home/cvs/src/sys/netinet/ip_input.c,v retrieving revision 1.97 diff -u -r1.97 ip_input.c --- ip_input.c 1998/07/13 12:12:24 1.97 +++ ip_input.c 1998/08/05 01:25:09 @@ -142,6 +142,9 @@ #endif #ifdef COMPAT_IPFW + +#include <netinet/ip_fw.h> + /* Firewall hooks */ ip_fw_chk_t *ip_fw_chk_ptr; ip_fw_ctl_t *ip_fw_ctl_ptr; @@ -1234,7 +1237,7 @@ if (ip_nhops == 0) return ((struct mbuf *)0); - m = m_get(M_DONTWAIT, MT_SOOPTS); + m = m_get(M_DONTWAIT, MT_HEADER); if (m == 0) return ((struct mbuf *)0); Index: netinet/ip_mroute.c =================================================================== RCS file: /home/cvs/src/sys/netinet/ip_mroute.c,v retrieving revision 1.47 diff -u -r1.47 ip_mroute.c --- ip_mroute.c 1998/06/30 10:56:31 1.47 +++ ip_mroute.c 1998/08/05 01:25:14 @@ -54,10 +54,8 @@ extern int _ip_mforward __P((struct ip *ip, struct ifnet *ifp, struct mbuf *m, struct ip_moptions *imo)); extern int _ip_mrouter_done __P((void)); -extern int _ip_mrouter_get __P((int cmd, struct socket *so, - struct mbuf **m)); -extern int _ip_mrouter_set __P((int cmd, struct socket *so, - struct mbuf *m)); +extern int _ip_mrouter_get __P((struct socket *so, struct sockopt *sopt)); +extern int _ip_mrouter_set __P((struct socket *so, struct sockopt *sopt)); extern int _mrt_ioctl __P((int req, caddr_t data, struct proc *p)); /* @@ -70,27 +68,25 @@ u_int rsvpdebug = 0; int -_ip_mrouter_set(cmd, so, m) - int cmd; +_ip_mrouter_set(so, sopt) struct socket *so; - struct mbuf *m; + struct sockopt *sopt; { return(EOPNOTSUPP); } -int (*ip_mrouter_set)(int, struct socket *, struct mbuf *) = _ip_mrouter_set; +int (*ip_mrouter_set)(struct socket *, struct sockopt *) = _ip_mrouter_set; int -_ip_mrouter_get(cmd, so, m) - int cmd; +_ip_mrouter_get(so, sopt) struct socket *so; - struct mbuf **m; + struct sockopt *sopt; { return(EOPNOTSUPP); } -int (*ip_mrouter_get)(int, struct socket *, struct mbuf **) = _ip_mrouter_get; +int (*ip_mrouter_get)(struct socket *, struct sockopt *) = _ip_mrouter_get; int _ip_mrouter_done() @@ -161,17 +157,17 @@ u_long (*ip_mcast_src)(int) = _ip_mcast_src; int -ip_rsvp_vif_init(so, m) +ip_rsvp_vif_init(so, sopt) struct socket *so; - struct mbuf *m; + struct sockopt *sopt; { return(EINVAL); } int -ip_rsvp_vif_done(so, m) +ip_rsvp_vif_done(so, sopt) struct socket *so; - struct mbuf *m; + struct sockopt *sopt; { return(EINVAL); } Index: netinet/ip_mroute.h =================================================================== RCS file: /home/cvs/src/sys/netinet/ip_mroute.h,v retrieving revision 1.13 diff -u -r1.13 ip_mroute.h --- ip_mroute.h 1997/02/22 09:41:35 1.13 +++ ip_mroute.h 1998/08/05 01:25:15 @@ -248,8 +248,10 @@ #ifdef KERNEL -extern int (*ip_mrouter_set) __P((int, struct socket *, struct mbuf *)); -extern int (*ip_mrouter_get) __P((int, struct socket *, struct mbuf **)); +struct sockopt; + +extern int (*ip_mrouter_set) __P((struct socket *, struct sockopt *)); +extern int (*ip_mrouter_get) __P((struct socket *, struct sockopt *)); extern int (*ip_mrouter_done) __P((void)); #ifdef MROUTING extern int (*mrt_ioctl) __P((int, caddr_t)); Index: netinet/ip_output.c =================================================================== RCS file: /home/cvs/src/sys/netinet/ip_output.c,v retrieving revision 1.79 diff -u -r1.79 ip_output.c --- ip_output.c 1998/07/13 12:12:25 1.79 +++ ip_output.c 1998/08/05 01:25:19 @@ -72,6 +72,10 @@ #undef COMPAT_IPFW #endif +#ifdef COMPAT_IPFW +#include <netinet/ip_fw.h> +#endif + #ifdef IPFIREWALL_FORWARD_DEBUG #define print_ip(a) printf("%ld.%ld.%ld.%ld",(ntohl(a.s_addr)>>24)&0xFF,\ (ntohl(a.s_addr)>>16)&0xFF,\ @@ -85,10 +89,10 @@ static void ip_mloopback __P((struct ifnet *, struct mbuf *, struct sockaddr_in *, int)); static int ip_getmoptions - __P((int, struct ip_moptions *, struct mbuf **)); -static int ip_pcbopts __P((struct mbuf **, struct mbuf *)); + __P((struct sockopt *, struct ip_moptions *)); +static int ip_pcbopts __P((int, struct mbuf **, struct mbuf *)); static int ip_setmoptions - __P((int, struct ip_moptions **, struct mbuf *)); + __P((struct sockopt *, struct ip_moptions **)); #if defined(IPFILTER_LKM) || defined(IPFILTER) int ip_optcopy __P((struct ip *, struct ip *)); @@ -743,33 +747,43 @@ * IP socket option processing. */ int -ip_ctloutput(op, so, level, optname, mp, p) - int op; +ip_ctloutput(so, sopt) struct socket *so; - int level, optname; - struct mbuf **mp; - struct proc *p; + struct sockopt *sopt; { - register struct inpcb *inp = sotoinpcb(so); - register struct mbuf *m = *mp; - register int optval = 0; - int error = 0; + struct inpcb *inp = sotoinpcb(so); + int error, optval; - if (level != IPPROTO_IP) { - error = EINVAL; - if (op == PRCO_SETOPT && *mp) - (void) m_free(*mp); - } else switch (op) { + error = optval = 0; + if (sopt->sopt_level != IPPROTO_IP) { + return (EINVAL); + } - case PRCO_SETOPT: - switch (optname) { + switch (sopt->sopt_dir) { + 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; + if (sopt->sopt_valsize > MLEN) { + error = EMSGSIZE; + break; + } + MGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT, MT_HEADER); + if (m == 0) { + error = ENOBUFS; + break; + } + m->m_len = sopt->sopt_valsize; + error = sooptcopyin(sopt, mtod(m, char *), m->m_len, + m->m_len); + + return (ip_pcbopts(sopt->sopt_name, &inp->inp_options, + m)); + } case IP_TOS: case IP_TTL: @@ -777,41 +791,40 @@ case IP_RECVRETOPTS: case IP_RECVDSTADDR: case IP_RECVIF: - if (m == 0 || m->m_len != sizeof(int)) - error = EINVAL; - else { - optval = *mtod(m, int *); - switch (optname) { + error = sooptcopyin(sopt, &optval, sizeof optval, + sizeof optval); + if (error) + break; - case IP_TOS: - inp->inp_ip_tos = optval; - break; + switch (sopt->sopt_name) { + case IP_TOS: + inp->inp_ip_tos = optval; + break; - case IP_TTL: - inp->inp_ip_ttl = optval; - break; + case IP_TTL: + inp->inp_ip_ttl = optval; + break; #define OPTSET(bit) \ if (optval) \ inp->inp_flags |= bit; \ else \ inp->inp_flags &= ~bit; - case IP_RECVOPTS: - OPTSET(INP_RECVOPTS); - break; + case IP_RECVOPTS: + OPTSET(INP_RECVOPTS); + break; - case IP_RECVRETOPTS: - OPTSET(INP_RECVRETOPTS); - break; + case IP_RECVRETOPTS: + OPTSET(INP_RECVRETOPTS); + break; - case IP_RECVDSTADDR: - OPTSET(INP_RECVDSTADDR); - break; + case IP_RECVDSTADDR: + OPTSET(INP_RECVDSTADDR); + break; - case IP_RECVIF: - OPTSET(INP_RECVIF); - break; - } + case IP_RECVIF: + OPTSET(INP_RECVIF); + break; } break; #undef OPTSET @@ -822,36 +835,34 @@ case IP_MULTICAST_LOOP: case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: - error = ip_setmoptions(optname, &inp->inp_moptions, m); + error = ip_setmoptions(sopt, &inp->inp_moptions); break; case IP_PORTRANGE: - if (m == 0 || m->m_len != sizeof(int)) - error = EINVAL; - else { - optval = *mtod(m, int *); - - switch (optval) { + error = sooptcopyin(sopt, &optval, sizeof optval, + sizeof optval); + if (error) + break; - case IP_PORTRANGE_DEFAULT: - inp->inp_flags &= ~(INP_LOWPORT); - inp->inp_flags &= ~(INP_HIGHPORT); - break; + switch (optval) { + case IP_PORTRANGE_DEFAULT: + inp->inp_flags &= ~(INP_LOWPORT); + inp->inp_flags &= ~(INP_HIGHPORT); + break; - case IP_PORTRANGE_HIGH: - inp->inp_flags &= ~(INP_LOWPORT); - inp->inp_flags |= INP_HIGHPORT; - break; + case IP_PORTRANGE_HIGH: + inp->inp_flags &= ~(INP_LOWPORT); + inp->inp_flags |= INP_HIGHPORT; + break; - case IP_PORTRANGE_LOW: - inp->inp_flags &= ~(INP_HIGHPORT); - inp->inp_flags |= INP_LOWPORT; - break; + case IP_PORTRANGE_LOW: + inp->inp_flags &= ~(INP_HIGHPORT); + inp->inp_flags |= INP_LOWPORT; + break; - default: - error = EINVAL; - break; - } + default: + error = EINVAL; + break; } break; @@ -859,21 +870,19 @@ 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); - if (inp->inp_options) { - m->m_len = inp->inp_options->m_len; - bcopy(mtod(inp->inp_options, void *), - mtod(m, void *), m->m_len); - } else - m->m_len = 0; + if (inp->inp_options) + error = sooptcopyout(sopt, + mtod(inp->inp_options, + char *), + inp->inp_options->m_len); + else + sopt->sopt_valsize = 0; break; case IP_TOS: @@ -882,9 +891,8 @@ case IP_RECVRETOPTS: case IP_RECVDSTADDR: case IP_RECVIF: - *mp = m = m_get(M_WAIT, MT_SOOPTS); - m->m_len = sizeof(int); - switch (optname) { + case IP_PORTRANGE: + switch (sopt->sopt_name) { case IP_TOS: optval = inp->inp_ip_tos; @@ -911,8 +919,17 @@ case IP_RECVIF: optval = OPTBIT(INP_RECVIF); break; + + case IP_PORTRANGE: + if (inp->inp_flags & INP_HIGHPORT) + optval = IP_PORTRANGE_HIGH; + else if (inp->inp_flags & INP_LOWPORT) + optval = IP_PORTRANGE_LOW; + else + optval = 0; + break; } - *mtod(m, int *) = optval; + error = sooptcopyout(sopt, &optval, sizeof optval); break; case IP_MULTICAST_IF: @@ -921,21 +938,7 @@ case IP_MULTICAST_LOOP: case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: - error = ip_getmoptions(optname, inp->inp_moptions, mp); - break; - - case IP_PORTRANGE: - *mp = m = m_get(M_WAIT, MT_SOOPTS); - m->m_len = sizeof(int); - - if (inp->inp_flags & INP_HIGHPORT) - optval = IP_PORTRANGE_HIGH; - else if (inp->inp_flags & INP_LOWPORT) - optval = IP_PORTRANGE_LOW; - else - optval = 0; - - *mtod(m, int *) = optval; + error = ip_getmoptions(sopt, inp->inp_moptions); break; default: @@ -953,12 +956,8 @@ * with destination address if source routed. */ static int -#ifdef notyet ip_pcbopts(optname, pcbopt, m) int optname; -#else -ip_pcbopts(pcbopt, m) -#endif struct mbuf **pcbopt; register struct mbuf *m; { @@ -1055,23 +1054,28 @@ } /* + * XXX + * The whole multicast option thing needs to be re-thought. + * Several of these options are equally applicable to non-multicast + * transmission, and one (IP_MULTICAST_TTL) totally duplicates a + * standard option (IP_TTL). + */ +/* * Set the IP multicast options in response to user setsockopt(). */ static int -ip_setmoptions(optname, imop, m) - int optname; +ip_setmoptions(sopt, imop) + struct sockopt *sopt; struct ip_moptions **imop; - struct mbuf *m; { - register int error = 0; - u_char loop; - register int i; + int error = 0; + int i; struct in_addr addr; - register struct ip_mreq *mreq; - register struct ifnet *ifp; - register struct ip_moptions *imo = *imop; + struct ip_mreq mreq; + struct ifnet *ifp; + struct ip_moptions *imo = *imop; struct route ro; - register struct sockaddr_in *dst; + struct sockaddr_in *dst; int s; if (imo == NULL) { @@ -1092,18 +1096,16 @@ imo->imo_num_memberships = 0; } - switch (optname) { + switch (sopt->sopt_name) { /* store an index number for the vif you wanna use in the send */ case IP_MULTICAST_VIF: - if (!legal_vif_num) { + if (legal_vif_num == 0) { error = EOPNOTSUPP; break; } - if (m == NULL || m->m_len != sizeof(int)) { - error = EINVAL; + error = sooptcopyin(sopt, &i, sizeof i, sizeof i); + if (error) break; - } - i = *(mtod(m, int *)); if (!legal_vif_num(i) && (i != -1)) { error = EINVAL; break; @@ -1115,11 +1117,9 @@ /* * Select the interface for outgoing multicast packets. */ - if (m == NULL || m->m_len != sizeof(struct in_addr)) { - error = EINVAL; + error = sooptcopyin(sopt, &addr, sizeof addr, sizeof addr); + if (error) break; - } - addr = *(mtod(m, struct in_addr *)); /* * INADDR_ANY is used to remove a previous selection. * When no interface is selected, a default one is @@ -1148,25 +1148,50 @@ case IP_MULTICAST_TTL: /* * Set the IP time-to-live for outgoing multicast packets. - */ - if (m == NULL || m->m_len != 1) { - error = EINVAL; - break; + * The original multicast API required a char argument, + * which is inconsistent with the rest of the socket API. + * We allow either a char or an int. + */ + if (sopt->sopt_valsize == 1) { + u_char ttl; + error = sooptcopyin(sopt, &ttl, 1, 1); + if (error) + break; + imo->imo_multicast_ttl = ttl; + } else { + u_int ttl; + error = sooptcopyin(sopt, &ttl, sizeof ttl, + sizeof ttl); + if (error) + break; + if (ttl > 255) + error = EINVAL; + else + imo->imo_multicast_ttl = ttl; } - imo->imo_multicast_ttl = *(mtod(m, u_char *)); break; case IP_MULTICAST_LOOP: /* * Set the loopback flag for outgoing multicast packets. - * Must be zero or one. - */ - if (m == NULL || m->m_len != 1 || - (loop = *(mtod(m, u_char *))) > 1) { - error = EINVAL; - break; + * Must be zero or one. The original multicast API required a + * char argument, which is inconsistent with the rest + * of the socket API. We allow either a char or an int. + */ + if (sopt->sopt_valsize == 1) { + u_char loop; + error = sooptcopyin(sopt, &loop, 1, 1); + if (error) + break; + imo->imo_multicast_loop = !!loop; + } else { + u_int loop; + error = sooptcopyin(sopt, &loop, sizeof loop, + sizeof loop); + if (error) + break; + imo->imo_multicast_loop = !!loop; } - imo->imo_multicast_loop = loop; break; case IP_ADD_MEMBERSHIP: @@ -1174,12 +1199,11 @@ * Add a multicast group membership. * Group must be a valid IP multicast address. */ - if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { - error = EINVAL; + error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq); + if (error) break; - } - mreq = mtod(m, struct ip_mreq *); - if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { + + if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) { error = EINVAL; break; } @@ -1188,12 +1212,12 @@ * If no interface address was provided, use the interface of * the route to the given multicast address. */ - if (mreq->imr_interface.s_addr == INADDR_ANY) { + if (mreq.imr_interface.s_addr == INADDR_ANY) { bzero((caddr_t)&ro, sizeof(ro)); dst = (struct sockaddr_in *)&ro.ro_dst; dst->sin_len = sizeof(*dst); dst->sin_family = AF_INET; - dst->sin_addr = mreq->imr_multiaddr; + dst->sin_addr = mreq.imr_multiaddr; rtalloc(&ro); if (ro.ro_rt == NULL) { error = EADDRNOTAVAIL; @@ -1204,7 +1228,7 @@ rtfree(ro.ro_rt); } else { - INADDR_TO_IFP(mreq->imr_interface, ifp); + INADDR_TO_IFP(mreq.imr_interface, ifp); } /* @@ -1223,7 +1247,7 @@ for (i = 0; i < imo->imo_num_memberships; ++i) { if (imo->imo_membership[i]->inm_ifp == ifp && imo->imo_membership[i]->inm_addr.s_addr - == mreq->imr_multiaddr.s_addr) + == mreq.imr_multiaddr.s_addr) break; } if (i < imo->imo_num_memberships) { @@ -1241,7 +1265,7 @@ * address list for the given interface. */ if ((imo->imo_membership[i] = - in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) { + in_addmulti(&mreq.imr_multiaddr, ifp)) == NULL) { error = ENOBUFS; splx(s); break; @@ -1255,12 +1279,11 @@ * Drop a multicast group membership. * Group must be a valid IP multicast address. */ - if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { - error = EINVAL; + error = sooptcopyin(sopt, &mreq, sizeof mreq, sizeof mreq); + if (error) break; - } - mreq = mtod(m, struct ip_mreq *); - if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { + + if (!IN_MULTICAST(ntohl(mreq.imr_multiaddr.s_addr))) { error = EINVAL; break; } @@ -1270,10 +1293,10 @@ * If an interface address was specified, get a pointer * to its ifnet structure. */ - if (mreq->imr_interface.s_addr == INADDR_ANY) + if (mreq.imr_interface.s_addr == INADDR_ANY) ifp = NULL; else { - INADDR_TO_IFP(mreq->imr_interface, ifp); + INADDR_TO_IFP(mreq.imr_interface, ifp); if (ifp == NULL) { error = EADDRNOTAVAIL; splx(s); @@ -1287,7 +1310,7 @@ if ((ifp == NULL || imo->imo_membership[i]->inm_ifp == ifp) && imo->imo_membership[i]->inm_addr.s_addr == - mreq->imr_multiaddr.s_addr) + mreq.imr_multiaddr.s_addr) break; } if (i == imo->imo_num_memberships) { @@ -1333,57 +1356,63 @@ * Return the IP multicast options in response to user getsockopt(). */ static int -ip_getmoptions(optname, imo, mp) - int optname; +ip_getmoptions(sopt, imo) + struct sockopt *sopt; register struct ip_moptions *imo; - register struct mbuf **mp; { - u_char *ttl; - u_char *loop; - struct in_addr *addr; + struct in_addr addr; struct in_ifaddr *ia; + int error, optval; + u_char coptval; - *mp = m_get(M_WAIT, MT_SOOPTS); - - switch (optname) { - + error = 0; + switch (sopt->sopt_name) { case IP_MULTICAST_VIF: if (imo != NULL) - *(mtod(*mp, int *)) = imo->imo_multicast_vif; + optval = imo->imo_multicast_vif; else - *(mtod(*mp, int *)) = -1; - (*mp)->m_len = sizeof(int); - return(0); + optval = -1; + error = sooptcopyout(sopt, &optval, sizeof optval); + break; 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->s_addr = INADDR_ANY; + addr.s_addr = INADDR_ANY; else { IFP_TO_IA(imo->imo_multicast_ifp, ia); - addr->s_addr = (ia == NULL) ? INADDR_ANY - : IA_SIN(ia)->sin_addr.s_addr; + addr.s_addr = (ia == NULL) ? INADDR_ANY + : IA_SIN(ia)->sin_addr.s_addr; } - return (0); + error = sooptcopyout(sopt, &addr, sizeof addr); + break; case IP_MULTICAST_TTL: - ttl = mtod(*mp, u_char *); - (*mp)->m_len = 1; - *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL - : imo->imo_multicast_ttl; - return (0); + if (imo == 0) + optval = coptval = IP_DEFAULT_MULTICAST_TTL; + else + optval = coptval = imo->imo_multicast_ttl; + if (sopt->sopt_valsize == 1) + error = sooptcopyout(sopt, &coptval, 1); + else + error = sooptcopyout(sopt, &optval, sizeof optval); + break; case IP_MULTICAST_LOOP: - loop = mtod(*mp, u_char *); - (*mp)->m_len = 1; - *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP - : imo->imo_multicast_loop; - return (0); + if (imo == 0) + optval = coptval = IP_DEFAULT_MULTICAST_LOOP; + else + optval = coptval = imo->imo_multicast_loop; + if (sopt->sopt_valsize == 1) + error = sooptcopyout(sopt, &coptval, 1); + else + error = sooptcopyout(sopt, &optval, sizeof optval); + break; default: - return (EOPNOTSUPP); + error = ENOPROTOOPT; + break; } + return (error); } /* Index: netinet/ip_var.h =================================================================== RCS file: /home/cvs/src/sys/netinet/ip_var.h,v retrieving revision 1.43 diff -u -r1.43 ip_var.h --- ip_var.h 1998/07/13 12:20:07 1.43 +++ ip_var.h 1998/08/05 01:25:19 @@ -160,6 +160,7 @@ #define IP_ROUTETOIF SO_DONTROUTE /* bypass routing tables */ #define IP_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */ +struct ip; struct inpcb; struct route; @@ -175,8 +176,7 @@ extern int rsvp_on; extern struct pr_usrreqs rip_usrreqs; -int ip_ctloutput __P((int, struct socket *, int, int, struct mbuf **, - struct proc *)); +int ip_ctloutput __P((struct socket *, struct sockopt *sopt)); void ip_drain __P((void)); void ip_freemoptions __P((struct ip_moptions *)); void ip_init __P((void)); @@ -190,8 +190,7 @@ struct mbuf * ip_srcroute __P((void)); void ip_stripoptions __P((struct mbuf *, struct mbuf *)); -int rip_ctloutput __P((int, struct socket *, int, int, struct mbuf **, - struct proc *p)); +int rip_ctloutput __P((struct socket *, struct sockopt *)); void rip_ctlinput __P((int, struct sockaddr *, void *)); void rip_init __P((void)); void rip_input __P((struct mbuf *, int)); @@ -200,8 +199,8 @@ void rsvp_input __P((struct mbuf *, int)); int ip_rsvp_init __P((struct socket *)); int ip_rsvp_done __P((void)); -int ip_rsvp_vif_init __P((struct socket *, struct mbuf *)); -int ip_rsvp_vif_done __P((struct socket *, struct mbuf *)); +int ip_rsvp_vif_init __P((struct socket *, struct sockopt *)); +int ip_rsvp_vif_done __P((struct socket *, struct sockopt *)); void ip_rsvp_force_done __P((struct socket *)); #ifdef IPDIVERT Index: netinet/raw_ip.c =================================================================== RCS file: /home/cvs/src/sys/netinet/raw_ip.c,v retrieving revision 1.54 diff -u -r1.54 raw_ip.c --- raw_ip.c 1998/05/15 20:11:34 1.54 +++ raw_ip.c 1998/08/05 01:25:21 @@ -225,101 +225,127 @@ * Raw IP socket option processing. */ int -rip_ctloutput(op, so, level, optname, m, p) - int op; +rip_ctloutput(so, sopt) struct socket *so; - int level, optname; - struct mbuf **m; - struct proc *p; + struct sockopt *sopt; { - register struct inpcb *inp = sotoinpcb(so); - register int error; + struct inpcb *inp = sotoinpcb(so); + int error, optval; - if (level != IPPROTO_IP) { - if (op == PRCO_SETOPT && *m) - (void)m_free(*m); + if (sopt->sopt_level != IPPROTO_IP) return (EINVAL); - } - switch (optname) { + error = 0; - case IP_HDRINCL: - error = 0; - if (op == PRCO_SETOPT) { - if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) - error = EINVAL; - else if (*mtod(*m, int *)) - inp->inp_flags |= INP_HDRINCL; - else - inp->inp_flags &= ~INP_HDRINCL; - if (*m) - (void)m_free(*m); - } else { - *m = m_get(M_WAIT, MT_SOOPTS); - (*m)->m_len = sizeof (int); - *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; - } - return (error); + switch (sopt->sopt_dir) { + case SOPT_GET: + switch (sopt->sopt_name) { + case IP_HDRINCL: + optval = inp->inp_flags & INP_HDRINCL; + error = sooptcopyout(sopt, &optval, sizeof optval); + break; #ifdef COMPAT_IPFW - case IP_FW_GET: - if (ip_fw_ctl_ptr == NULL || op == PRCO_SETOPT) { - if (*m) (void)m_free(*m); - return(EINVAL); - } - return (*ip_fw_ctl_ptr)(optname, m); - - case IP_FW_ADD: - case IP_FW_DEL: - case IP_FW_FLUSH: - case IP_FW_ZERO: - if (ip_fw_ctl_ptr == NULL || op != PRCO_SETOPT) { - if (*m) (void)m_free(*m); - return(EINVAL); - } - return (*ip_fw_ctl_ptr)(optname, m); + case IP_FW_GET: + if (ip_fw_ctl_ptr == 0) + error = ENOPROTOOPT; + else + error = ip_fw_ctl_ptr(sopt); + break; - case IP_NAT: - if (ip_nat_ctl_ptr == NULL) { - if (*m) (void)m_free(*m); - return(EINVAL); + case IP_NAT: + if (ip_nat_ctl_ptr == 0) + error = ENOPROTOOPT; + else + error = ip_nat_ctl_ptr(sopt); + break; +#endif /* COMPAT_IPFW */ + + case MRT_INIT: + case MRT_DONE: + case MRT_ADD_VIF: + case MRT_DEL_VIF: + case MRT_ADD_MFC: + case MRT_DEL_MFC: + case MRT_VERSION: + case MRT_ASSERT: + error = ip_mrouter_get(so, sopt); + break; + + default: + error = ip_ctloutput(so, sopt); + break; } - return (*ip_nat_ctl_ptr)(op, m); - -#endif - case IP_RSVP_ON: - return ip_rsvp_init(so); break; - case IP_RSVP_OFF: - return ip_rsvp_done(); - break; - - case IP_RSVP_VIF_ON: - return ip_rsvp_vif_init(so, *m); + case SOPT_SET: + switch (sopt->sopt_name) { + case IP_HDRINCL: + error = sooptcopyin(sopt, &optval, sizeof optval, + sizeof optval); + if (error) + break; + if (optval) + inp->inp_flags |= INP_HDRINCL; + else + inp->inp_flags &= ~INP_HDRINCL; + break; - case IP_RSVP_VIF_OFF: - return ip_rsvp_vif_done(so, *m); +#ifdef COMPAT_IPFW + case IP_FW_ADD: + case IP_FW_DEL: + case IP_FW_FLUSH: + case IP_FW_ZERO: + if (ip_fw_ctl_ptr == 0) + error = ENOPROTOOPT; + else + error = ip_fw_ctl_ptr(sopt); + break; - case MRT_INIT: - case MRT_DONE: - case MRT_ADD_VIF: - case MRT_DEL_VIF: - case MRT_ADD_MFC: - case MRT_DEL_MFC: - case MRT_VERSION: - case MRT_ASSERT: - if (op == PRCO_SETOPT) { - error = ip_mrouter_set(optname, so, *m); - if (*m) - (void)m_free(*m); - } else if (op == PRCO_GETOPT) { - error = ip_mrouter_get(optname, so, m); - } else - error = EINVAL; - return (error); + case IP_NAT: + if (ip_nat_ctl_ptr == 0) + error = ENOPROTOOPT; + else + error = ip_nat_ctl_ptr(sopt); + break; +#endif /* COMPAT_IPFW */ + + case IP_RSVP_ON: + error = ip_rsvp_init(so); + break; + + case IP_RSVP_OFF: + error = ip_rsvp_done(); + break; + + /* XXX - should be combined */ + case IP_RSVP_VIF_ON: + error = ip_rsvp_vif_init(so, sopt); + break; + + case IP_RSVP_VIF_OFF: + error = ip_rsvp_vif_done(so, sopt); + break; + + case MRT_INIT: + case MRT_DONE: + case MRT_ADD_VIF: + case MRT_DEL_VIF: + case MRT_ADD_MFC: + case MRT_DEL_MFC: + case MRT_VERSION: + case MRT_ASSERT: + error = ip_mrouter_set(so, sopt); + break; + + default: + error = ip_ctloutput(so, sopt); + break; + } + break; } - return (ip_ctloutput(op, so, level, optname, m, p)); + + return (error); } /* @@ -340,7 +366,7 @@ int err; int flags; - switch(cmd) { + switch (cmd) { case PRC_IFDOWN: for (ia = in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) { Index: netinet/tcp_usrreq.c =================================================================== RCS file: /home/cvs/src/sys/netinet/tcp_usrreq.c,v retrieving revision 1.37 diff -u -r1.37 tcp_usrreq.c --- tcp_usrreq.c 1998/01/27 09:15:11 1.37 +++ tcp_usrreq.c 1998/08/05 01:25:23 @@ -560,104 +560,107 @@ return 0; } +/* + * The new sockopt interface makes it possible for us to block in the + * copyin/out step (if we take a page fault). Taking a page fault at + * splnet() is probably a Bad Thing. (Since sockets and pcbs both now + * use TSM, there probably isn't any need for this function to run at + * splnet() any more. This needs more examination.) + */ int -tcp_ctloutput(op, so, level, optname, mp, p) - int op; +tcp_ctloutput(so, sopt) struct socket *so; - int level, optname; - struct mbuf **mp; - struct proc *p; + struct sockopt *sopt; { - int error = 0, s; - struct inpcb *inp; - register struct tcpcb *tp; - register struct mbuf *m; - register int i; + int error, opt, optval, s; + struct inpcb *inp; + struct tcpcb *tp; + struct mbuf *m; - s = splnet(); + error = 0; + s = splnet(); /* XXX */ inp = sotoinpcb(so); if (inp == NULL) { splx(s); - if (op == PRCO_SETOPT && *mp) - (void) m_free(*mp); return (ECONNRESET); } - if (level != IPPROTO_TCP) { - error = ip_ctloutput(op, so, level, optname, mp, p); + if (sopt->sopt_level != IPPROTO_TCP) { + error = ip_ctloutput(so, sopt); splx(s); return (error); } tp = intotcpcb(inp); - switch (op) { - - case PRCO_SETOPT: - m = *mp; - switch (optname) { - + switch (sopt->sopt_dir) { + case SOPT_SET: + switch (sopt->sopt_name) { case TCP_NODELAY: - if (m == NULL || m->m_len < sizeof (int)) - error = EINVAL; - else if (*mtod(m, int *)) - tp->t_flags |= TF_NODELAY; + case TCP_NOOPT: + case TCP_NOPUSH: + error = sooptcopyin(sopt, &optval, sizeof optval, + sizeof optval); + if (error) + break; + + switch (sopt->sopt_name) { + case TCP_NODELAY: + opt = TF_NODELAY; + break; + case TCP_NOOPT: + opt = TF_NOOPT; + break; + case TCP_NOPUSH: + opt = TF_NOPUSH; + break; + default: + opt = 0; /* dead code to fool gcc */ + break; + } + + if (optval) + tp->t_flags |= opt; else - tp->t_flags &= ~TF_NODELAY; + tp->t_flags &= ~opt; break; case TCP_MAXSEG: - if (m && (i = *mtod(m, int *)) > 0 && i <= tp->t_maxseg) - tp->t_maxseg = i; - else - error = EINVAL; - break; + error = sooptcopyin(sopt, &optval, sizeof optval, + sizeof optval); + if (error) + break; - case TCP_NOOPT: - if (m == NULL || m->m_len < sizeof (int)) - error = EINVAL; - else if (*mtod(m, int *)) - tp->t_flags |= TF_NOOPT; + if (optval > 0 && optval <= tp->t_maxseg) + tp->t_maxseg = optval; else - tp->t_flags &= ~TF_NOOPT; - break; - - case TCP_NOPUSH: - if (m == NULL || m->m_len < sizeof (int)) error = EINVAL; - else if (*mtod(m, int *)) - tp->t_flags |= TF_NOPUSH; - else - tp->t_flags &= ~TF_NOPUSH; break; default: error = ENOPROTOOPT; break; } - if (m) - (void) m_free(m); break; - case PRCO_GETOPT: - *mp = m = m_get(M_WAIT, MT_SOOPTS); - m->m_len = sizeof(int); - - switch (optname) { + case SOPT_GET: + switch (sopt->sopt_name) { case TCP_NODELAY: - *mtod(m, int *) = tp->t_flags & TF_NODELAY; + optval = tp->t_flags & TF_NODELAY; break; case TCP_MAXSEG: - *mtod(m, int *) = tp->t_maxseg; + optval = tp->t_maxseg; break; case TCP_NOOPT: - *mtod(m, int *) = tp->t_flags & TF_NOOPT; + optval = tp->t_flags & TF_NOOPT; break; case TCP_NOPUSH: - *mtod(m, int *) = tp->t_flags & TF_NOPUSH; + optval = tp->t_flags & TF_NOPUSH; break; default: error = ENOPROTOOPT; break; } + if (error == 0) + error = sooptcopyout(sopt, &optval, sizeof optval); break; } splx(s); Index: netinet/tcp_var.h =================================================================== RCS file: /home/cvs/src/sys/netinet/tcp_var.h,v retrieving revision 1.46 diff -u -r1.46 tcp_var.h --- tcp_var.h 1998/07/13 11:09:52 1.46 +++ tcp_var.h 1998/08/05 01:25:24 @@ -344,8 +344,7 @@ struct tcpcb * tcp_close __P((struct tcpcb *)); void tcp_ctlinput __P((int, struct sockaddr *, void *)); -int tcp_ctloutput __P((int, struct socket *, int, int, struct mbuf **, - struct proc *)); +int tcp_ctloutput __P((struct socket *, struct sockopt *)); struct tcpcb * tcp_drop __P((struct tcpcb *, int)); void tcp_drain __P((void)); Index: nfs/nfs_socket.c =================================================================== RCS file: /home/cvs/src/sys/nfs/nfs_socket.c,v retrieving revision 1.42 diff -u -r1.42 nfs_socket.c --- nfs_socket.c 1998/07/15 02:32:24 1.42 +++ nfs_socket.c 1998/08/05 01:25:30 @@ -282,16 +282,28 @@ if (nmp->nm_sotype != SOCK_STREAM) panic("nfscon sotype"); if (so->so_proto->pr_flags & PR_CONNREQUIRED) { - MGET(m, M_WAIT, MT_SOOPTS); - *mtod(m, int32_t *) = 1; - m->m_len = sizeof(int32_t); - sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m, p); + struct sockopt sopt; + int val; + + bzero(&sopt, sizeof sopt); + sopt.sopt_level = SOL_SOCKET; + sopt.sopt_name = SO_KEEPALIVE; + sopt.sopt_val = &val; + sopt.sopt_valsize = sizeof val; + val = 1; + sosetopt(so, &sopt); } if (so->so_proto->pr_protocol == IPPROTO_TCP) { - MGET(m, M_WAIT, MT_SOOPTS); - *mtod(m, int32_t *) = 1; - m->m_len = sizeof(int32_t); - sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m, p); + struct sockopt sopt; + int val; + + bzero(&sopt, sizeof sopt); + sopt.sopt_level = IPPROTO_TCP; + sopt.sopt_name = TCP_NODELAY; + sopt.sopt_val = &val; + sopt.sopt_valsize = sizeof val; + val = 1; + sosetopt(so, &sopt); } sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR + sizeof (u_int32_t)) * 2; Index: nfs/nfs_syscalls.c =================================================================== RCS file: /home/cvs/src/sys/nfs/nfs_syscalls.c,v retrieving revision 1.41 diff -u -r1.41 nfs_syscalls.c --- nfs_syscalls.c 1998/05/31 20:08:55 1.41 +++ nfs_syscalls.c 1998/08/05 01:25:33 @@ -400,17 +400,29 @@ * repeatedly for the same socket, but that isn't harmful. */ if (so->so_type == SOCK_STREAM) { - MGET(m, M_WAIT, MT_SOOPTS); - *mtod(m, int32_t *) = 1; - m->m_len = sizeof(int32_t); - sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m, p); + struct sockopt sopt; + int val; + + bzero(&sopt, sizeof sopt); + sopt.sopt_level = SOL_SOCKET; + sopt.sopt_name = SO_KEEPALIVE; + sopt.sopt_val = &val; + sopt.sopt_valsize = sizeof val; + val = 1; + sosetopt(so, &sopt); } if (so->so_proto->pr_domain->dom_family == AF_INET && so->so_proto->pr_protocol == IPPROTO_TCP) { - MGET(m, M_WAIT, MT_SOOPTS); - *mtod(m, int32_t *) = 1; - m->m_len = sizeof(int32_t); - sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m, p); + struct sockopt sopt; + int val; + + bzero(&sopt, sizeof sopt); + sopt.sopt_level = IPPROTO_TCP; + sopt.sopt_name = TCP_NODELAY; + sopt.sopt_val = &val; + sopt.sopt_valsize = sizeof val; + val = 1; + sosetopt(so, &sopt); } so->so_rcv.sb_flags &= ~SB_NOINTR; so->so_rcv.sb_timeo = 0; Index: sys/mbuf.h =================================================================== RCS file: /home/cvs/src/sys/sys/mbuf.h,v retrieving revision 1.27 diff -u -r1.27 mbuf.h --- mbuf.h 1998/07/15 04:17:53 1.27 +++ mbuf.h 1998/08/05 01:25:37 @@ -138,7 +138,7 @@ /*efine MT_HTABLE 6*/ /* IMP host tables */ /*efine MT_ATABLE 7*/ /* address resolution tables */ #define MT_SONAME 8 /* socket name */ -#define MT_SOOPTS 10 /* socket options */ +/*efine MT_SOOPTS 10*/ /* socket options */ #define MT_FTABLE 11 /* fragment reassembly header */ /*efine MT_RIGHTS 12*/ /* access rights */ /*efine MT_IFADDR 13*/ /* interface address */ @@ -168,10 +168,10 @@ * drivers. */ #define MBUFLOCK(code) \ - { int ms = splimp(); \ + do { int ms = splimp(); \ { code } \ splx(ms); \ - } + } while(0) /* * mbuf allocation/deallocation macros: Index: sys/protosw.h =================================================================== RCS file: /home/cvs/src/sys/sys/protosw.h,v retrieving revision 1.24 diff -u -r1.24 protosw.h --- protosw.h 1998/06/07 17:13:03 1.24 +++ protosw.h 1998/08/05 01:25:37 @@ -42,6 +42,7 @@ struct proc; struct sockaddr; struct socket; +struct sockopt; /*#ifdef KERNEL*/ /* @@ -58,13 +59,13 @@ * * Protocols pass data between themselves as chains of mbufs using * the pr_input and pr_output hooks. Pr_input passes data up (towards - * UNIX) and pr_output passes it down (towards the imps); control + * the users) and pr_output passes it down (towards the interfaces); control * information passes up and down on pr_ctlinput and pr_ctloutput. * The protocol is responsible for the space occupied by any the * arguments to these entries and must dispose it. * - * The userreq routine interfaces protocols to the system and is - * described below. + * In retrospect, it would be a lot nicer to use an interface + * similar to the vnode VOP interface. */ struct protosw { short pr_type; /* socket type used for */ @@ -78,8 +79,7 @@ /* output to protocol (from above) */ void (*pr_ctlinput)__P((int, struct sockaddr *, void *)); /* control input (from below) */ - int (*pr_ctloutput)__P((int, struct socket *, int, int, - struct mbuf **, struct proc *)); + int (*pr_ctloutput)__P((struct socket *, struct sockopt *)); /* control output (from above) */ /* user-protocol hook */ void *pr_ousrreq; Index: sys/socketvar.h =================================================================== RCS file: /home/cvs/src/sys/sys/socketvar.h,v retrieving revision 1.28 diff -u -r1.28 socketvar.h --- socketvar.h 1998/06/07 17:13:03 1.28 +++ socketvar.h 1998/08/05 01:25:38 @@ -102,9 +102,10 @@ #define SB_UPCALL 0x20 /* someone wants an upcall */ #define SB_NOINTR 0x40 /* operations not interruptible */ - void (*so_upcall) __P((struct socket *so, caddr_t arg, int waitf)); - caddr_t so_upcallarg; /* Arg for above */ + void (*so_upcall) __P((struct socket *, void *, int)); + void *so_upcallarg; uid_t so_uid; /* who opened the socket */ + /* NB: generation count must not be first; easiest to make it last. */ so_gen_t so_gencnt; /* generation count */ }; @@ -119,7 +120,6 @@ #define SS_CANTRCVMORE 0x0020 /* can't receive more data from peer */ #define SS_RCVATMARK 0x0040 /* at mark on input */ -/*efine SS_PRIV 0x0080 privileged for broadcast, raw... */ #define SS_NBIO 0x0100 /* non-blocking ops */ #define SS_ASYNC 0x0200 /* async i/o notify */ #define SS_ISCONFIRMING 0x0400 /* deciding to accept connection req */ @@ -242,6 +242,20 @@ #ifdef KERNEL +/* + * Argument structure for sosetopt et seq. This is in the KERNEL + * section because it will never be visible to user code. + */ +enum sopt_dir { SOPT_GET, SOPT_SET }; +struct sockopt { + enum sopt_dir sopt_dir; /* is this a get or a set? */ + int sopt_level; /* second arg of [gs]etsockopt */ + int sopt_name; /* third arg of [gs]etsockopt */ + void *sopt_val; /* fourth arg of [gs]etsockopt */ + size_t sopt_valsize; /* (almost) fifth arg of [gs]etsockopt */ + struct proc *sopt_p; /* calling process or null if kernel */ +}; + #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_PCB); MALLOC_DECLARE(M_SONAME); @@ -309,8 +323,7 @@ void sodealloc __P((struct socket *so)); int sodisconnect __P((struct socket *so)); void sofree __P((struct socket *so)); -int sogetopt __P((struct socket *so, int level, int optname, - struct mbuf **mp, struct proc *p)); +int sogetopt __P((struct socket *so, struct sockopt *sopt)); void sohasoutofband __P((struct socket *so)); void soisconnected __P((struct socket *so)); void soisconnecting __P((struct socket *so)); @@ -321,6 +334,9 @@ sodropablereq __P((struct socket *head)); struct socket * sonewconn __P((struct socket *head, int connstatus)); +int sooptcopyin __P((struct sockopt *sopt, void *buf, size_t len, + size_t minlen)); +int sooptcopyout __P((struct sockopt *sopt, void *buf, size_t len)); int sopoll __P((struct socket *so, int events, struct ucred *cred, struct proc *p)); int soreceive __P((struct socket *so, struct sockaddr **paddr, @@ -331,8 +347,7 @@ int sosend __P((struct socket *so, struct sockaddr *addr, struct uio *uio, struct mbuf *top, struct mbuf *control, int flags, struct proc *p)); -int sosetopt __P((struct socket *so, int level, int optname, - struct mbuf *m0, struct proc *p)); +int sosetopt __P((struct socket *so, struct sockopt *sopt)); int soshutdown __P((struct socket *so, int how)); void sotoxsocket __P((struct socket *so, struct xsocket *xso)); void sowakeup __P((struct socket *so, struct sockbuf *sb)); To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-net" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199808050147.VAA05270>