Index: tcp_usrreq.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp_usrreq.c,v retrieving revision 1.141 diff -u -2 -0 -r1.141 tcp_usrreq.c --- tcp_usrreq.c 17 Sep 2006 13:39:35 -0000 1.141 +++ tcp_usrreq.c 10 Nov 2006 17:28:11 -0000 @@ -1240,188 +1240,179 @@ ti->tcpi_snd_wscale = tp->snd_scale; ti->tcpi_rcv_wscale = tp->rcv_scale; } ti->tcpi_snd_ssthresh = tp->snd_ssthresh; ti->tcpi_snd_cwnd = tp->snd_cwnd; /* * FreeBSD-specific extension fields for tcp_info. */ ti->tcpi_rcv_space = tp->rcv_wnd; ti->tcpi_snd_wnd = tp->snd_wnd; ti->tcpi_snd_bwnd = tp->snd_bwnd; } /* * 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.) - * - * XXXRW: The locking here is wrong; we may take a page fault while holding - * the inpcb lock. */ int tcp_ctloutput(so, sopt) struct socket *so; struct sockopt *sopt; { int error, opt, optval; struct inpcb *inp; struct tcpcb *tp; struct tcp_info ti; error = 0; inp = sotoinpcb(so); KASSERT(inp != NULL, ("tcp_ctloutput: inp == NULL")); INP_LOCK(inp); if (sopt->sopt_level != IPPROTO_TCP) { INP_UNLOCK(inp); #ifdef INET6 if (INP_CHECK_SOCKAF(so, AF_INET6)) error = ip6_ctloutput(so, sopt); else #endif /* INET6 */ error = ip_ctloutput(so, sopt); return (error); } + if (sopt->sopt_dir == SOPT_SET) { + INP_UNLOCK(inp); + error = sooptcopyin(sopt, &optval, sizeof optval, + sizeof optval); + if (error) + return (error); + INP_LOCK(inp); + } if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) { - error = ECONNRESET; - goto out; + INP_UNLOCK(inp); + return (ECONNRESET); } tp = intotcpcb(inp); switch (sopt->sopt_dir) { case SOPT_SET: switch (sopt->sopt_name) { #ifdef TCP_SIGNATURE case TCP_MD5SIG: - error = sooptcopyin(sopt, &optval, sizeof optval, - sizeof optval); - if (error) - break; - if (optval > 0) tp->t_flags |= TF_SIGNATURE; else tp->t_flags &= ~TF_SIGNATURE; break; #endif /* TCP_SIGNATURE */ case TCP_NODELAY: case TCP_NOOPT: - 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; default: opt = 0; /* dead code to fool gcc */ break; } if (optval) tp->t_flags |= opt; else tp->t_flags &= ~opt; break; case TCP_NOPUSH: - error = sooptcopyin(sopt, &optval, sizeof optval, - sizeof optval); - if (error) - break; - if (optval) tp->t_flags |= TF_NOPUSH; else { tp->t_flags &= ~TF_NOPUSH; error = tcp_output(tp); } break; case TCP_MAXSEG: - error = sooptcopyin(sopt, &optval, sizeof optval, - sizeof optval); - if (error) - break; - if (optval > 0 && optval <= tp->t_maxseg && optval + 40 >= tcp_minmss) tp->t_maxseg = optval; else error = EINVAL; break; case TCP_INFO: error = EINVAL; break; default: error = ENOPROTOOPT; break; } + INP_UNLOCK(inp); break; case SOPT_GET: switch (sopt->sopt_name) { #ifdef TCP_SIGNATURE case TCP_MD5SIG: optval = (tp->t_flags & TF_SIGNATURE) ? 1 : 0; + INP_UNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof optval); break; #endif case TCP_NODELAY: optval = tp->t_flags & TF_NODELAY; + INP_UNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof optval); break; case TCP_MAXSEG: optval = tp->t_maxseg; + INP_UNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof optval); break; case TCP_NOOPT: optval = tp->t_flags & TF_NOOPT; + INP_UNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof optval); break; case TCP_NOPUSH: optval = tp->t_flags & TF_NOPUSH; + INP_UNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof optval); break; case TCP_INFO: tcp_fill_info(tp, &ti); + INP_UNLOCK(inp); error = sooptcopyout(sopt, &ti, sizeof ti); break; default: + INP_UNLOCK(inp); error = ENOPROTOOPT; break; } break; } -out: - INP_UNLOCK(inp); return (error); } /* * tcp_sendspace and tcp_recvspace are the default send and receive window * sizes, respectively. These are obsolescent (this information should * be set by the route). */ u_long tcp_sendspace = 1024*32; SYSCTL_ULONG(_net_inet_tcp, TCPCTL_SENDSPACE, sendspace, CTLFLAG_RW, &tcp_sendspace , 0, "Maximum outgoing TCP datagram size"); u_long tcp_recvspace = 1024*64; SYSCTL_ULONG(_net_inet_tcp, TCPCTL_RECVSPACE, recvspace, CTLFLAG_RW, &tcp_recvspace , 0, "Maximum incoming TCP datagram size"); /* * Attach TCP protocol to socket, allocating * internet protocol control block, tcp control block, * bufer space, and entering LISTEN state if to accept connections. */