diff options
author | tanimura <tanimura@FreeBSD.org> | 2002-05-20 05:41:09 +0000 |
---|---|---|
committer | tanimura <tanimura@FreeBSD.org> | 2002-05-20 05:41:09 +0000 |
commit | 92d8381dd544a8237b3fd68c4e7fce9bd0903fb2 (patch) | |
tree | 2465ddbcecac65f96c5c6d5cef1a4fe3f1ac03f8 /sys/netinet | |
parent | 969293170b27461145f69a538d5abd15fea34ba1 (diff) | |
download | FreeBSD-src-92d8381dd544a8237b3fd68c4e7fce9bd0903fb2.zip FreeBSD-src-92d8381dd544a8237b3fd68c4e7fce9bd0903fb2.tar.gz |
Lock down a socket, milestone 1.
o Add a mutex (sb_mtx) to struct sockbuf. This protects the data in a
socket buffer. The mutex in the receive buffer also protects the data
in struct socket.
o Determine the lock strategy for each members in struct socket.
o Lock down the following members:
- so_count
- so_options
- so_linger
- so_state
o Remove *_locked() socket APIs. Make the following socket APIs
touching the members above now require a locked socket:
- sodisconnect()
- soisconnected()
- soisconnecting()
- soisdisconnected()
- soisdisconnecting()
- sofree()
- soref()
- sorele()
- sorwakeup()
- sotryfree()
- sowakeup()
- sowwakeup()
Reviewed by: alfred
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/accf_data.c | 10 | ||||
-rw-r--r-- | sys/netinet/accf_http.c | 31 | ||||
-rw-r--r-- | sys/netinet/in_pcb.c | 77 | ||||
-rw-r--r-- | sys/netinet/ip_divert.c | 21 | ||||
-rw-r--r-- | sys/netinet/ip_input.c | 5 | ||||
-rw-r--r-- | sys/netinet/ip_mroute.c | 2 | ||||
-rw-r--r-- | sys/netinet/raw_ip.c | 52 | ||||
-rw-r--r-- | sys/netinet/tcp_input.c | 102 | ||||
-rw-r--r-- | sys/netinet/tcp_output.c | 17 | ||||
-rw-r--r-- | sys/netinet/tcp_reass.c | 102 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 14 | ||||
-rw-r--r-- | sys/netinet/tcp_timer.c | 68 | ||||
-rw-r--r-- | sys/netinet/tcp_timewait.c | 14 | ||||
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 63 | ||||
-rw-r--r-- | sys/netinet/udp_usrreq.c | 41 |
15 files changed, 499 insertions, 120 deletions
diff --git a/sys/netinet/accf_data.c b/sys/netinet/accf_data.c index 46c92e3..4470733 100644 --- a/sys/netinet/accf_data.c +++ b/sys/netinet/accf_data.c @@ -30,6 +30,8 @@ #include <sys/param.h> #include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/mutex.h> #include <sys/sysctl.h> #include <sys/signalvar.h> #include <sys/socketvar.h> @@ -57,11 +59,15 @@ static void sohasdata(struct socket *so, void *arg, int waitflag) { - if (!soreadable(so)) + SOCK_LOCK(so); + if (!soreadable(so)) { + SOCK_UNLOCK(so); return; + } so->so_upcall = NULL; so->so_rcv.sb_flags &= ~SB_UPCALL; - soisconnected_locked(so); + soisconnected(so); + SOCK_UNLOCK(so); return; } diff --git a/sys/netinet/accf_http.c b/sys/netinet/accf_http.c index 4a3e17e..4849f6b 100644 --- a/sys/netinet/accf_http.c +++ b/sys/netinet/accf_http.c @@ -31,7 +31,9 @@ #include <sys/param.h> #include <sys/kernel.h> +#include <sys/lock.h> #include <sys/mbuf.h> +#include <sys/mutex.h> #include <sys/signalvar.h> #include <sys/sysctl.h> #include <sys/socketvar.h> @@ -160,11 +162,13 @@ static void sohashttpget(struct socket *so, void *arg, int waitflag) { + SOCK_LOCK(so); if ((so->so_state & SS_CANTRCVMORE) == 0 && !sbfull(&so->so_rcv)) { struct mbuf *m; char *cmp; int cmplen, cc; + SOCK_UNLOCK(so); m = so->so_rcv.sb_mb; cc = so->so_rcv.sb_cc - 1; if (cc < 1) @@ -197,13 +201,16 @@ sohashttpget(struct socket *so, void *arg, int waitflag) return; } DPRINT("mbufstrcmp bad"); - } + } else + SOCK_UNLOCK(so); fallout: DPRINT("fallout"); + SOCK_LOCK(so); so->so_upcall = NULL; so->so_rcv.sb_flags &= ~SB_UPCALL; - soisconnected_locked(so); + soisconnected(so); + SOCK_UNLOCK(so); return; } @@ -213,8 +220,12 @@ soparsehttpvers(struct socket *so, void *arg, int waitflag) struct mbuf *m, *n; int i, cc, spaces, inspaces; - if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv)) + SOCK_LOCK(so); + if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv)) { + SOCK_UNLOCK(so); goto fallout; + } + SOCK_UNLOCK(so); m = so->so_rcv.sb_mb; cc = so->so_rcv.sb_cc; @@ -283,9 +294,11 @@ readmore: fallout: DPRINT("fallout"); + SOCK_LOCK(so); so->so_upcall = NULL; so->so_rcv.sb_flags &= ~SB_UPCALL; - soisconnected_locked(so); + soisconnected(so); + SOCK_UNLOCK(so); return; } @@ -300,8 +313,12 @@ soishttpconnected(struct socket *so, void *arg, int waitflag) int ccleft, copied; DPRINT("start"); - if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv)) + SOCK_LOCK(so); + if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv)) { + SOCK_UNLOCK(so); goto gotit; + } + SOCK_UNLOCK(so); /* * Walk the socketbuffer and copy the last NCHRS (3) into a, b, and c @@ -353,8 +370,10 @@ readmore: return; gotit: + SOCK_LOCK(so); so->so_upcall = NULL; so->so_rcv.sb_flags &= ~SB_UPCALL; - soisconnected_locked(so); + soisconnected(so); + SOCK_UNLOCK(so); return; } diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index b4de80a..bd4bac9 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -183,15 +183,20 @@ in_pcbbind(inp, nam, td) struct sockaddr_in *sin; struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; u_short lport = 0; - int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); + int wild = 0, reuseport; int error, prison = 0; + SOCK_LOCK(so); + reuseport = (so->so_options & SO_REUSEPORT); + SOCK_UNLOCK(so); if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */ return (EADDRNOTAVAIL); if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) return (EINVAL); + SOCK_LOCK(so); if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) wild = 1; + SOCK_UNLOCK(so); if (nam) { sin = (struct sockaddr_in *)nam; if (nam->sa_len != sizeof (*sin)) @@ -216,8 +221,10 @@ in_pcbbind(inp, nam, td) * and a multicast address is bound on both * new and duplicated sockets. */ + SOCK_LOCK(so); if (so->so_options & SO_REUSEADDR) reuseport = SO_REUSEADDR|SO_REUSEPORT; + SOCK_UNLOCK(so); } else if (sin->sin_addr.s_addr != INADDR_ANY) { sin->sin_port = 0; /* yech... */ bzero(&sin->sin_zero, sizeof(sin->sin_zero)); @@ -237,22 +244,26 @@ in_pcbbind(inp, nam, td) t = in_pcblookup_local(inp->inp_pcbinfo, sin->sin_addr, lport, prison ? 0 : INPLOOKUP_WILDCARD); - if (t && - (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || - ntohl(t->inp_laddr.s_addr) != INADDR_ANY || - (t->inp_socket->so_options & - SO_REUSEPORT) == 0) && - (so->so_cred->cr_uid != - t->inp_socket->so_cred->cr_uid)) { + if (t != NULL) { + SOCK_LOCK(t->inp_socket); + if ((ntohl(sin->sin_addr.s_addr) != INADDR_ANY || + ntohl(t->inp_laddr.s_addr) != INADDR_ANY || + (t->inp_socket->so_options & + SO_REUSEPORT) == 0) && + (so->so_cred->cr_uid != + t->inp_socket->so_cred->cr_uid)) { + SOCK_UNLOCK(t->inp_socket); #if defined(INET6) - if (ntohl(sin->sin_addr.s_addr) != - INADDR_ANY || - ntohl(t->inp_laddr.s_addr) != - INADDR_ANY || - INP_SOCKAF(so) == - INP_SOCKAF(t->inp_socket)) + if (ntohl(sin->sin_addr.s_addr) != + INADDR_ANY || + ntohl(t->inp_laddr.s_addr) != + INADDR_ANY || + INP_SOCKAF(so) == + INP_SOCKAF(t->inp_socket)) #endif /* defined(INET6) */ - return (EADDRINUSE); + return (EADDRINUSE); + } else + SOCK_UNLOCK(t->inp_socket); } } if (prison && @@ -260,17 +271,21 @@ in_pcbbind(inp, nam, td) return (EADDRNOTAVAIL); t = in_pcblookup_local(pcbinfo, sin->sin_addr, lport, prison ? 0 : wild); - if (t && - (reuseport & t->inp_socket->so_options) == 0) { + if (t != NULL) { + SOCK_LOCK(t->inp_socket); + if ((reuseport & t->inp_socket->so_options) == 0) { + SOCK_UNLOCK(t->inp_socket); #if defined(INET6) - if (ntohl(sin->sin_addr.s_addr) != - INADDR_ANY || - ntohl(t->inp_laddr.s_addr) != - INADDR_ANY || - INP_SOCKAF(so) == - INP_SOCKAF(t->inp_socket)) + if (ntohl(sin->sin_addr.s_addr) != + INADDR_ANY || + ntohl(t->inp_laddr.s_addr) != + INADDR_ANY || + INP_SOCKAF(so) == + INP_SOCKAF(t->inp_socket)) #endif /* defined(INET6) */ - return (EADDRINUSE); + return (EADDRINUSE); + } else + SOCK_UNLOCK(t->inp_socket); } } inp->inp_laddr = sin->sin_addr; @@ -416,17 +431,21 @@ in_pcbladdr(inp, nam, plocal_sin) * destination, in case of sharing the cache with IPv6. */ ro = &inp->inp_route; + SOCK_LOCK(inp->inp_socket); if (ro->ro_rt && (ro->ro_dst.sa_family != AF_INET || satosin(&ro->ro_dst)->sin_addr.s_addr != sin->sin_addr.s_addr || inp->inp_socket->so_options & SO_DONTROUTE)) { + SOCK_UNLOCK(inp->inp_socket); RTFREE(ro->ro_rt); ro->ro_rt = (struct rtentry *)0; + SOCK_LOCK(inp->inp_socket); } if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ (ro->ro_rt == (struct rtentry *)0 || ro->ro_rt->rt_ifp == (struct ifnet *)0)) { + SOCK_UNLOCK(inp->inp_socket); /* No route yet, so try to acquire one */ bzero(&ro->ro_dst, sizeof(struct sockaddr_in)); ro->ro_dst.sa_family = AF_INET; @@ -434,7 +453,8 @@ in_pcbladdr(inp, nam, plocal_sin) ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = sin->sin_addr; rtalloc(ro); - } + } else + SOCK_UNLOCK(inp->inp_socket); /* * If we found a route, use the address * corresponding to the outgoing interface @@ -548,8 +568,12 @@ in_pcbdisconnect(inp) inp->inp_faddr.s_addr = INADDR_ANY; inp->inp_fport = 0; in_pcbrehash(inp); - if (inp->inp_socket->so_state & SS_NOFDREF) + SOCK_LOCK(inp->inp_socket); + if (inp->inp_socket->so_state & SS_NOFDREF) { + SOCK_UNLOCK(inp->inp_socket); in_pcbdetach(inp); + } else + SOCK_UNLOCK(inp->inp_socket); } void @@ -565,6 +589,7 @@ in_pcbdetach(inp) inp->inp_gencnt = ++ipi->ipi_gencnt; in_pcbremlists(inp); so->so_pcb = 0; + SOCK_LOCK(so); sotryfree(so); if (inp->inp_options) (void)m_free(inp->inp_options); diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index 8f56d2c..e297390 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -228,8 +228,11 @@ divert_packet(struct mbuf *m, int incoming, int port) if (sbappendaddr(&sa->so_rcv, (struct sockaddr *)&divsrc, m, (struct mbuf *)0) == 0) m_freem(m); - else + else { + SOCK_LOCK(sa); sorwakeup(sa); + SOCK_UNLOCK(sa); + } } else { m_freem(m); ipstat.ips_noproto++; @@ -255,6 +258,7 @@ div_output(so, m, addr, control) register struct ip *const ip = mtod(m, struct ip *); struct sockaddr_in *sin = (struct sockaddr_in *)addr; int error = 0; + int soopts; if (control) m_freem(control); /* XXX */ @@ -300,8 +304,11 @@ div_output(so, m, addr, control) /* Send packet to output processing */ ipstat.ips_rawout++; /* XXX */ + SOCK_LOCK(so); + soopts = so->so_options & SO_DONTROUTE; + SOCK_UNLOCK(so); error = ip_output(m, inp->inp_options, &inp->inp_route, - (so->so_options & SO_DONTROUTE) | + soopts | IP_ALLOWBROADCAST | IP_RAWOUTPUT, inp->inp_moptions); } else { @@ -365,7 +372,9 @@ div_attach(struct socket *so, int proto, struct thread *td) inp->inp_flags |= INP_HDRINCL; /* The socket is always "connected" because we always know "where" to send the packet */ + SOCK_LOCK(so); so->so_state |= SS_ISCONNECTED; + SOCK_UNLOCK(so); return 0; } @@ -384,15 +393,21 @@ div_detach(struct socket *so) static int div_abort(struct socket *so) { + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); return div_detach(so); } static int div_disconnect(struct socket *so) { - if ((so->so_state & SS_ISCONNECTED) == 0) + SOCK_LOCK(so); + if ((so->so_state & SS_ISCONNECTED) == 0) { + SOCK_UNLOCK(so); return ENOTCONN; + } + SOCK_UNLOCK(so); return div_abort(so); } diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index b7a882f..3627832 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -1837,15 +1837,18 @@ ip_savecontrol(inp, mp, ip, m) register struct ip *ip; register struct mbuf *m; { + SOCK_LOCK(inp->inp_socket); if (inp->inp_socket->so_options & SO_TIMESTAMP) { struct timeval tv; + SOCK_UNLOCK(inp->inp_socket); microtime(&tv); *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), SCM_TIMESTAMP, SOL_SOCKET); if (*mp) mp = &(*mp)->m_next; - } + } else + SOCK_UNLOCK(inp->inp_socket); if (inp->inp_flags & INP_RECVDSTADDR) { *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c index 0be45ea..e2f85f2 100644 --- a/sys/netinet/ip_mroute.c +++ b/sys/netinet/ip_mroute.c @@ -1133,7 +1133,9 @@ socket_send(s, mm, src) if (sbappendaddr(&s->so_rcv, (struct sockaddr *)src, mm, (struct mbuf *)0) != 0) { + SOCK_LOCK(s); sorwakeup(s); + SOCK_UNLOCK(s); return 0; } } diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 86915fc..aaeb61c 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -153,9 +153,16 @@ rip_input(m, off) } else #endif /*IPSEC*/ if (n) { - if (last->inp_flags & INP_CONTROLOPTS || - last->inp_socket->so_options & SO_TIMESTAMP) - ip_savecontrol(last, &opts, ip, n); + if (last->inp_flags & INP_CONTROLOPTS) + ip_savecontrol(last, &opts, ip, n); + else { + SOCK_LOCK(last->inp_socket); + if(last->inp_socket->so_options & SO_TIMESTAMP) { + SOCK_UNLOCK(last->inp_socket); + ip_savecontrol(last, &opts, ip, n); + } else + SOCK_UNLOCK(last->inp_socket); + } if (sbappendaddr(&last->inp_socket->so_rcv, (struct sockaddr *)&ripsrc, n, opts) == 0) { @@ -163,8 +170,11 @@ rip_input(m, off) m_freem(n); if (opts) m_freem(opts); - } else + } else { + SOCK_LOCK(last->inp_socket); sorwakeup(last->inp_socket); + SOCK_UNLOCK(last->inp_socket); + } opts = 0; } } @@ -180,16 +190,26 @@ rip_input(m, off) } else #endif /*IPSEC*/ if (last) { - if (last->inp_flags & INP_CONTROLOPTS || - last->inp_socket->so_options & SO_TIMESTAMP) + if (last->inp_flags & INP_CONTROLOPTS) ip_savecontrol(last, &opts, ip, m); + else { + SOCK_LOCK(last->inp_socket); + if (last->inp_socket->so_options & SO_TIMESTAMP) { + SOCK_UNLOCK(last->inp_socket); + ip_savecontrol(last, &opts, ip, m); + } else + SOCK_UNLOCK(last->inp_socket); + } if (sbappendaddr(&last->inp_socket->so_rcv, (struct sockaddr *)&ripsrc, m, opts) == 0) { m_freem(m); if (opts) m_freem(opts); - } else + } else { + SOCK_LOCK(last->inp_socket); sorwakeup(last->inp_socket); + SOCK_UNLOCK(last->inp_socket); + } } else { m_freem(m); ipstat.ips_noproto++; @@ -209,8 +229,11 @@ rip_output(m, so, dst) { register struct ip *ip; register struct inpcb *inp = sotoinpcb(so); - int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; + int flags; + SOCK_LOCK(so); + flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; + SOCK_UNLOCK(so); /* * If the user handed us a complete IP packet, use it. * Otherwise, allocate an mbuf for a header and fill it in. @@ -508,15 +531,21 @@ rip_detach(struct socket *so) static int rip_abort(struct socket *so) { + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); return rip_detach(so); } static int rip_disconnect(struct socket *so) { - if ((so->so_state & SS_ISCONNECTED) == 0) + SOCK_LOCK(so); + if ((so->so_state & SS_ISCONNECTED) == 0) { + SOCK_UNLOCK(so); return ENOTCONN; + } + SOCK_UNLOCK(so); return rip_abort(so); } @@ -552,7 +581,9 @@ rip_connect(struct socket *so, struct sockaddr *nam, struct thread *td) (addr->sin_family != AF_IMPLINK)) return EAFNOSUPPORT; inp->inp_faddr = addr->sin_addr; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); return 0; } @@ -570,13 +601,16 @@ rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct inpcb *inp = sotoinpcb(so); register u_long dst; + SOCK_LOCK(so); if (so->so_state & SS_ISCONNECTED) { + SOCK_UNLOCK(so); if (nam) { m_freem(m); return EISCONN; } dst = inp->inp_faddr.s_addr; } else { + SOCK_UNLOCK(so); if (nam == NULL) { m_freem(m); return ENOTCONN; diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index b193327..b5c6daf 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -281,15 +281,21 @@ present: flags = q->tqe_th->th_flags & TH_FIN; nq = LIST_NEXT(q, tqe_q); LIST_REMOVE(q, tqe_q); - if (so->so_state & SS_CANTRCVMORE) + SOCK_LOCK(so); + if (so->so_state & SS_CANTRCVMORE) { + SOCK_UNLOCK(so); m_freem(q->tqe_m); - else + } else { + SOCK_UNLOCK(so); sbappend(&so->so_rcv, q->tqe_m); + } FREE(q, M_TSEGQ); q = nq; } while (q && q->tqe_th->th_seq == tp->rcv_nxt); ND6_HINT(tp); + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); return (flags); } @@ -638,6 +644,7 @@ findpcb: tiwin = th->th_win; so = inp->inp_socket; + SOCK_LOCK(so); if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) { struct in_conninfo inc; #ifdef TCPDEBUG @@ -654,8 +661,11 @@ findpcb: } #endif /* skip if this isn't a listen socket */ - if ((so->so_options & SO_ACCEPTCONN) == 0) + if ((so->so_options & SO_ACCEPTCONN) == 0) { + SOCK_UNLOCK(so); goto after_listen; + } + SOCK_UNLOCK(so); #ifdef INET6 inc.inc_isipv6 = isipv6; if (isipv6) { @@ -868,11 +878,14 @@ findpcb: tp->t_flags |= (TF_ACKNOW | TF_NEEDSYN); tcpstat.tcps_connects++; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); goto trimthenstep6; } goto drop; - } + } else + SOCK_UNLOCK(so); after_listen: /* XXX temp debugging */ @@ -1004,7 +1017,9 @@ after_listen: tp->t_rxtcur, tcp_timer_rexmt, tp); + SOCK_LOCK(so); sowwakeup(so); + SOCK_UNLOCK(so); if (so->so_snd.sb_cc) (void) tcp_output(tp); return; @@ -1027,7 +1042,9 @@ after_listen: */ m_adj(m, drop_hdrlen); /* delayed header drop */ sbappend(&so->so_rcv, m); + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); if (DELAY_ACK(tp)) { callout_reset(tp->tt_delack, tcp_delacktime, tcp_timer_delack, tp); @@ -1137,7 +1154,9 @@ after_listen: } else tp->t_flags &= ~TF_RCVD_CC; tcpstat.tcps_connects++; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); /* Do window scaling on this connection? */ if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == (TF_RCVD_SCALE|TF_REQ_SCALE)) { @@ -1467,13 +1486,16 @@ trimthenstep6: * If new data are received on a connection after the * user processes are gone, then RST the other end. */ + SOCK_LOCK(so); if ((so->so_state & SS_NOFDREF) && tp->t_state > TCPS_CLOSE_WAIT && tlen) { + SOCK_UNLOCK(so); tp = tcp_close(tp); tcpstat.tcps_rcvafterclose++; rstreason = BANDLIM_UNLIMITED; goto dropwithreset; } + SOCK_UNLOCK(so); /* * If segment ends after window, drop trailing data @@ -1563,7 +1585,9 @@ trimthenstep6: case TCPS_SYN_RECEIVED: tcpstat.tcps_connects++; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); /* Do window scaling? */ if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == (TF_RCVD_SCALE|TF_REQ_SCALE)) { @@ -1822,7 +1846,9 @@ process_ACK: tp->snd_wnd -= acked; ourfinisacked = 0; } + SOCK_LOCK(so); sowwakeup(so); + SOCK_UNLOCK(so); tp->snd_una = th->th_ack; if (SEQ_LT(tp->snd_nxt, tp->snd_una)) tp->snd_nxt = tp->snd_una; @@ -1843,11 +1869,14 @@ process_ACK: * specification, but if we don't get a FIN * we'll hang forever. */ + SOCK_LOCK(so); if (so->so_state & SS_CANTRCVMORE) { - soisdisconnected_locked(so); + soisdisconnected(so); + SOCK_UNLOCK(so); callout_reset(tp->tt_2msl, tcp_maxidle, tcp_timer_2msl, tp); - } + } else + SOCK_UNLOCK(so); tp->t_state = TCPS_FIN_WAIT_2; } break; @@ -1872,7 +1901,9 @@ process_ACK: else callout_reset(tp->tt_2msl, 2 * tcp_msl, tcp_timer_2msl, tp); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); } break; @@ -1956,8 +1987,11 @@ step6: tp->rcv_up = th->th_seq + th->th_urp; so->so_oobmark = so->so_rcv.sb_cc + (tp->rcv_up - tp->rcv_nxt) - 1; - if (so->so_oobmark == 0) + if (so->so_oobmark == 0) { + SOCK_LOCK(so); so->so_state |= SS_RCVATMARK; + SOCK_UNLOCK(so); + } sohasoutofband(so); tp->t_oobflags &= ~(TCPOOB_HAVEDATA | TCPOOB_HADDATA); } @@ -1967,13 +2001,19 @@ step6: * but if two URG's are pending at once, some out-of-band * data may creep in... ick. */ - if (th->th_urp <= (u_long)tlen + if (th->th_urp <= (u_long)tlen) { #ifdef SO_OOBINLINE - && (so->so_options & SO_OOBINLINE) == 0 + SOCK_LOCK(so); + if ((so->so_options & SO_OOBINLINE) == 0) { + SOCK_UNLOCK(so); #endif - ) - tcp_pulloutofband(so, th, m, - drop_hdrlen); /* hdr drop is delayed */ + tcp_pulloutofband(so, th, m, + drop_hdrlen); /* hdr drop is delayed */ +#ifdef SO_OOBINLINE + } else + SOCK_UNLOCK(so); +#endif + } } else /* * If no out of band data is expected, @@ -2019,7 +2059,9 @@ dodata: /* XXX */ tcpstat.tcps_rcvbyte += tlen; ND6_HINT(tp); sbappend(&so->so_rcv, m); + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); } else { thflags = tcp_reass(tp, th, &tlen, m); tp->t_flags |= TF_ACKNOW; @@ -2098,7 +2140,9 @@ dodata: /* XXX */ else callout_reset(tp->tt_2msl, 2 * tcp_msl, tcp_timer_2msl, tp); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); break; /* @@ -2111,9 +2155,13 @@ dodata: /* XXX */ } } #ifdef TCPDEBUG - if (so->so_options & SO_DEBUG) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG) { + SOCK_UNLOCK(so); tcp_trace(TA_INPUT, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + } else + SOCK_UNLOCK(so); #endif /* @@ -2146,9 +2194,13 @@ dropafterack: goto dropwithreset; } #ifdef TCPDEBUG - if (so->so_options & SO_DEBUG) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG) { + SOCK_UNLOCK(so); tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + } else + SOCK_UNLOCK(so); #endif m_freem(m); tp->t_flags |= TF_ACKNOW; @@ -2184,9 +2236,18 @@ dropwithreset: goto drop; #ifdef TCPDEBUG - if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + if (tp == 0) tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + else { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, + &tcp_savetcp, 0); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif if (thflags & TH_ACK) /* mtod() below is safe as long as hdr dropping is delayed */ @@ -2206,9 +2267,18 @@ drop: * Drop space held by incoming segment and return. */ #ifdef TCPDEBUG - if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + if (tp == 0) tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + else { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, + &tcp_savetcp, 0); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif m_freem(m); return; diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 40ed7ee..dd2832b 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -126,6 +126,7 @@ tcp_output(tp) #ifdef INET6 int isipv6; #endif + int soopts; #ifdef INET6 isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) != 0; @@ -819,8 +820,12 @@ send: /* * Trace. */ - if (so->so_options & SO_DEBUG) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG) { + SOCK_UNLOCK(so); tcp_trace(TA_OUTPUT, tp->t_state, tp, mtod(m, void *), th, 0); + } else + SOCK_UNLOCK(so); #endif /* @@ -854,10 +859,13 @@ send: goto out; } #endif /*IPSEC*/ + SOCK_LOCK(so); + soopts = (so->so_options & SO_DONTROUTE); + SOCK_UNLOCK(so); error = ip6_output(m, tp->t_inpcb->in6p_outputopts, &tp->t_inpcb->in6p_route, - (so->so_options & SO_DONTROUTE), NULL, NULL); + soopts, NULL, NULL); } else #endif /* INET6 */ { @@ -889,8 +897,11 @@ send: #ifdef IPSEC ipsec_setsocket(m, so); #endif /*IPSEC*/ + SOCK_LOCK(so); + soopts = (so->so_options & SO_DONTROUTE); + SOCK_UNLOCK(so); error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route, - (so->so_options & SO_DONTROUTE), 0); + soopts, 0); } if (error) { diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index b193327..b5c6daf 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -281,15 +281,21 @@ present: flags = q->tqe_th->th_flags & TH_FIN; nq = LIST_NEXT(q, tqe_q); LIST_REMOVE(q, tqe_q); - if (so->so_state & SS_CANTRCVMORE) + SOCK_LOCK(so); + if (so->so_state & SS_CANTRCVMORE) { + SOCK_UNLOCK(so); m_freem(q->tqe_m); - else + } else { + SOCK_UNLOCK(so); sbappend(&so->so_rcv, q->tqe_m); + } FREE(q, M_TSEGQ); q = nq; } while (q && q->tqe_th->th_seq == tp->rcv_nxt); ND6_HINT(tp); + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); return (flags); } @@ -638,6 +644,7 @@ findpcb: tiwin = th->th_win; so = inp->inp_socket; + SOCK_LOCK(so); if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) { struct in_conninfo inc; #ifdef TCPDEBUG @@ -654,8 +661,11 @@ findpcb: } #endif /* skip if this isn't a listen socket */ - if ((so->so_options & SO_ACCEPTCONN) == 0) + if ((so->so_options & SO_ACCEPTCONN) == 0) { + SOCK_UNLOCK(so); goto after_listen; + } + SOCK_UNLOCK(so); #ifdef INET6 inc.inc_isipv6 = isipv6; if (isipv6) { @@ -868,11 +878,14 @@ findpcb: tp->t_flags |= (TF_ACKNOW | TF_NEEDSYN); tcpstat.tcps_connects++; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); goto trimthenstep6; } goto drop; - } + } else + SOCK_UNLOCK(so); after_listen: /* XXX temp debugging */ @@ -1004,7 +1017,9 @@ after_listen: tp->t_rxtcur, tcp_timer_rexmt, tp); + SOCK_LOCK(so); sowwakeup(so); + SOCK_UNLOCK(so); if (so->so_snd.sb_cc) (void) tcp_output(tp); return; @@ -1027,7 +1042,9 @@ after_listen: */ m_adj(m, drop_hdrlen); /* delayed header drop */ sbappend(&so->so_rcv, m); + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); if (DELAY_ACK(tp)) { callout_reset(tp->tt_delack, tcp_delacktime, tcp_timer_delack, tp); @@ -1137,7 +1154,9 @@ after_listen: } else tp->t_flags &= ~TF_RCVD_CC; tcpstat.tcps_connects++; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); /* Do window scaling on this connection? */ if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == (TF_RCVD_SCALE|TF_REQ_SCALE)) { @@ -1467,13 +1486,16 @@ trimthenstep6: * If new data are received on a connection after the * user processes are gone, then RST the other end. */ + SOCK_LOCK(so); if ((so->so_state & SS_NOFDREF) && tp->t_state > TCPS_CLOSE_WAIT && tlen) { + SOCK_UNLOCK(so); tp = tcp_close(tp); tcpstat.tcps_rcvafterclose++; rstreason = BANDLIM_UNLIMITED; goto dropwithreset; } + SOCK_UNLOCK(so); /* * If segment ends after window, drop trailing data @@ -1563,7 +1585,9 @@ trimthenstep6: case TCPS_SYN_RECEIVED: tcpstat.tcps_connects++; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); /* Do window scaling? */ if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == (TF_RCVD_SCALE|TF_REQ_SCALE)) { @@ -1822,7 +1846,9 @@ process_ACK: tp->snd_wnd -= acked; ourfinisacked = 0; } + SOCK_LOCK(so); sowwakeup(so); + SOCK_UNLOCK(so); tp->snd_una = th->th_ack; if (SEQ_LT(tp->snd_nxt, tp->snd_una)) tp->snd_nxt = tp->snd_una; @@ -1843,11 +1869,14 @@ process_ACK: * specification, but if we don't get a FIN * we'll hang forever. */ + SOCK_LOCK(so); if (so->so_state & SS_CANTRCVMORE) { - soisdisconnected_locked(so); + soisdisconnected(so); + SOCK_UNLOCK(so); callout_reset(tp->tt_2msl, tcp_maxidle, tcp_timer_2msl, tp); - } + } else + SOCK_UNLOCK(so); tp->t_state = TCPS_FIN_WAIT_2; } break; @@ -1872,7 +1901,9 @@ process_ACK: else callout_reset(tp->tt_2msl, 2 * tcp_msl, tcp_timer_2msl, tp); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); } break; @@ -1956,8 +1987,11 @@ step6: tp->rcv_up = th->th_seq + th->th_urp; so->so_oobmark = so->so_rcv.sb_cc + (tp->rcv_up - tp->rcv_nxt) - 1; - if (so->so_oobmark == 0) + if (so->so_oobmark == 0) { + SOCK_LOCK(so); so->so_state |= SS_RCVATMARK; + SOCK_UNLOCK(so); + } sohasoutofband(so); tp->t_oobflags &= ~(TCPOOB_HAVEDATA | TCPOOB_HADDATA); } @@ -1967,13 +2001,19 @@ step6: * but if two URG's are pending at once, some out-of-band * data may creep in... ick. */ - if (th->th_urp <= (u_long)tlen + if (th->th_urp <= (u_long)tlen) { #ifdef SO_OOBINLINE - && (so->so_options & SO_OOBINLINE) == 0 + SOCK_LOCK(so); + if ((so->so_options & SO_OOBINLINE) == 0) { + SOCK_UNLOCK(so); #endif - ) - tcp_pulloutofband(so, th, m, - drop_hdrlen); /* hdr drop is delayed */ + tcp_pulloutofband(so, th, m, + drop_hdrlen); /* hdr drop is delayed */ +#ifdef SO_OOBINLINE + } else + SOCK_UNLOCK(so); +#endif + } } else /* * If no out of band data is expected, @@ -2019,7 +2059,9 @@ dodata: /* XXX */ tcpstat.tcps_rcvbyte += tlen; ND6_HINT(tp); sbappend(&so->so_rcv, m); + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); } else { thflags = tcp_reass(tp, th, &tlen, m); tp->t_flags |= TF_ACKNOW; @@ -2098,7 +2140,9 @@ dodata: /* XXX */ else callout_reset(tp->tt_2msl, 2 * tcp_msl, tcp_timer_2msl, tp); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); break; /* @@ -2111,9 +2155,13 @@ dodata: /* XXX */ } } #ifdef TCPDEBUG - if (so->so_options & SO_DEBUG) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG) { + SOCK_UNLOCK(so); tcp_trace(TA_INPUT, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + } else + SOCK_UNLOCK(so); #endif /* @@ -2146,9 +2194,13 @@ dropafterack: goto dropwithreset; } #ifdef TCPDEBUG - if (so->so_options & SO_DEBUG) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG) { + SOCK_UNLOCK(so); tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + } else + SOCK_UNLOCK(so); #endif m_freem(m); tp->t_flags |= TF_ACKNOW; @@ -2184,9 +2236,18 @@ dropwithreset: goto drop; #ifdef TCPDEBUG - if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + if (tp == 0) tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + else { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, + &tcp_savetcp, 0); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif if (thflags & TH_ACK) /* mtod() below is safe as long as hdr dropping is delayed */ @@ -2206,9 +2267,18 @@ drop: * Drop space held by incoming segment and return. */ #ifdef TCPDEBUG - if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + if (tp == 0) tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + else { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, + &tcp_savetcp, 0); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif m_freem(m); return; diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 13d8300..20d3bf5 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -469,8 +469,16 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); } #ifdef TCPDEBUG - if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + if (tp == NULL) tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0); + else { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif #ifdef IPSEC if (ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL) != 0) { @@ -720,7 +728,9 @@ tcp_close(tp) FREE(q, M_TSEGQ); } inp->inp_ppcb = NULL; + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); #ifdef INET6 if (INP_CHECK_SOCKAF(so, AF_INET6)) in6_pcbdetach(inp); @@ -793,9 +803,11 @@ tcp_notify(inp, error) else tp->t_softerror = error; #if 0 + SOCK_LOCK(so); wakeup((caddr_t) &so->so_timeo); sorwakeup(so); sowwakeup(so); + SOCK_UNLOCK(so); #endif } diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c index 087e243..5ee54cf 100644 --- a/sys/netinet/tcp_timer.c +++ b/sys/netinet/tcp_timer.c @@ -39,13 +39,15 @@ #include "opt_tcpdebug.h" #include <sys/param.h> -#include <sys/systm.h> #include <sys/kernel.h> +#include <sys/lock.h> #include <sys/mbuf.h> -#include <sys/sysctl.h> +#include <sys/mutex.h> +#include <sys/protosw.h> #include <sys/socket.h> #include <sys/socketvar.h> -#include <sys/protosw.h> +#include <sys/sysctl.h> +#include <sys/systm.h> #include <machine/cpu.h> /* before tcp_seq.h, for tcp_random18() */ @@ -211,9 +213,15 @@ tcp_timer_2msl(xtp) tp = tcp_close(tp); #ifdef TCPDEBUG - if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) - tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, - PRU_SLOWTIMO); + if (tp != 0) { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, + PRU_SLOWTIMO); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif splx(s); } @@ -243,9 +251,11 @@ tcp_timer_keep(xtp) tcpstat.tcps_keeptimeo++; if (tp->t_state < TCPS_ESTABLISHED) goto dropit; + SOCK_LOCK(tp->t_inpcb->inp_socket); if ((always_keepalive || tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE) && tp->t_state <= TCPS_CLOSING) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); if ((ticks - tp->t_rcvtime) >= tcp_keepidle + tcp_maxidle) goto dropit; /* @@ -269,13 +279,19 @@ tcp_timer_keep(xtp) (void) m_free(dtom(t_template)); } callout_reset(tp->tt_keep, tcp_keepintvl, tcp_timer_keep, tp); - } else + } else { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); callout_reset(tp->tt_keep, tcp_keepidle, tcp_timer_keep, tp); + } #ifdef TCPDEBUG - if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) + SOCK_LOCK(tp->t_inpcb->inp_socket); + if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, PRU_SLOWTIMO); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); #endif splx(s); return; @@ -285,9 +301,15 @@ dropit: tp = tcp_drop(tp, ETIMEDOUT); #ifdef TCPDEBUG - if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) - tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, - PRU_SLOWTIMO); + if (tp != 0) { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, + PRU_SLOWTIMO); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif splx(s); } @@ -335,9 +357,15 @@ tcp_timer_persist(xtp) out: #ifdef TCPDEBUG - if (tp && tp->t_inpcb->inp_socket->so_options & SO_DEBUG) - tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, - PRU_SLOWTIMO); + if (tp != 0) { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, + PRU_SLOWTIMO); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif splx(s); } @@ -470,9 +498,15 @@ tcp_timer_rexmt(xtp) out: #ifdef TCPDEBUG - if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) - tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, - PRU_SLOWTIMO); + if (tp != 0) { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, + PRU_SLOWTIMO); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif splx(s); } diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index 13d8300..20d3bf5 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -469,8 +469,16 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); } #ifdef TCPDEBUG - if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + if (tp == NULL) tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0); + else { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif #ifdef IPSEC if (ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL) != 0) { @@ -720,7 +728,9 @@ tcp_close(tp) FREE(q, M_TSEGQ); } inp->inp_ppcb = NULL; + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); #ifdef INET6 if (INP_CHECK_SOCKAF(so, AF_INET6)) in6_pcbdetach(inp); @@ -793,9 +803,11 @@ tcp_notify(inp, error) else tp->t_softerror = error; #if 0 + SOCK_LOCK(so); wakeup((caddr_t) &so->so_timeo); sorwakeup(so); sowwakeup(so); + SOCK_UNLOCK(so); #endif } diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index e1f4c1a..5d8934c 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -103,8 +103,17 @@ static struct tcpcb * #ifdef TCPDEBUG #define TCPDEBUG0 int ostate = 0 #define TCPDEBUG1() ostate = tp ? tp->t_state : 0 -#define TCPDEBUG2(req) if (tp && (so->so_options & SO_DEBUG)) \ - tcp_trace(TA_USER, ostate, tp, 0, 0, req) +#define TCPDEBUG2(req) \ + do { \ + if (tp != 0) { \ + SOCK_LOCK(so); \ + if (so->so_options & SO_DEBUG) { \ + SOCK_UNLOCK(so); \ + tcp_trace(TA_USER, ostate, tp, 0, 0, req); \ + } else \ + SOCK_UNLOCK(so); \ + } \ + } while(0) #else #define TCPDEBUG0 #define TCPDEBUG1() @@ -134,8 +143,10 @@ tcp_usr_attach(struct socket *so, int proto, struct thread *td) if (error) goto out; + SOCK_LOCK(so); if ((so->so_options & SO_LINGER) && so->so_linger == 0) so->so_linger = TCP_LINGERTIME; + SOCK_UNLOCK(so); tp = sototcpcb(so); out: TCPDEBUG2(PRU_ATTACH); @@ -424,10 +435,13 @@ tcp_usr_accept(struct socket *so, struct sockaddr **nam) struct tcpcb *tp = NULL; TCPDEBUG0; + SOCK_LOCK(so); if (so->so_state & SS_ISDISCONNECTED) { + SOCK_UNLOCK(so); error = ECONNABORTED; goto out; } + SOCK_UNLOCK(so); if (inp == 0) { splx(s); return (EINVAL); @@ -448,10 +462,13 @@ tcp6_usr_accept(struct socket *so, struct sockaddr **nam) struct tcpcb *tp = NULL; TCPDEBUG0; + SOCK_LOCK(so); if (so->so_state & SS_ISDISCONNECTED) { + SOCK_UNLOCK(so); error = ECONNABORTED; goto out; } + SOCK_UNLOCK(so); if (inp == 0) { splx(s); return (EINVAL); @@ -654,10 +671,16 @@ tcp_usr_rcvoob(struct socket *so, struct mbuf *m, int flags) struct tcpcb *tp; COMMON_START(); + SOCK_LOCK(so); if ((so->so_oobmark == 0 && (so->so_state & SS_RCVATMARK) == 0) || - so->so_options & SO_OOBINLINE || - tp->t_oobflags & TCPOOB_HADDATA) { + so->so_options & SO_OOBINLINE) { + SOCK_UNLOCK(so); + error = EINVAL; + goto out; + } + SOCK_UNLOCK(so); + if (tp->t_oobflags & TCPOOB_HADDATA) { error = EINVAL; goto out; } @@ -755,7 +778,9 @@ tcp_connect(tp, nam, td) (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) tp->request_r_scale++; + SOCK_LOCK(so); soisconnecting(so); + SOCK_UNLOCK(so); tcpstat.tcps_connattempt++; tp->t_state = TCPS_SYN_SENT; callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp); @@ -841,7 +866,9 @@ tcp6_connect(tp, nam, td) (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) tp->request_r_scale++; + SOCK_LOCK(so); soisconnecting(so); + SOCK_UNLOCK(so); tcpstat.tcps_connattempt++; tp->t_state = TCPS_SYN_SENT; callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp); @@ -1039,16 +1066,21 @@ tcp_attach(so, td) inp->inp_vflag |= INP_IPV4; tp = tcp_newtcpcb(inp); if (tp == 0) { - int nofd = so->so_state & SS_NOFDREF; /* XXX */ + int nofd; + SOCK_LOCK(so); + nofd = so->so_state & SS_NOFDREF; /* XXX */ so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */ + SOCK_UNLOCK(so); #ifdef INET6 if (isipv6) in6_pcbdetach(inp); else #endif in_pcbdetach(inp); + SOCK_LOCK(so); so->so_state |= nofd; + SOCK_UNLOCK(so); return (ENOBUFS); } tp->t_state = TCPS_CLOSED; @@ -1071,14 +1103,19 @@ tcp_disconnect(tp) if (tp->t_state < TCPS_ESTABLISHED) tp = tcp_close(tp); - else if ((so->so_options & SO_LINGER) && so->so_linger == 0) - tp = tcp_drop(tp, 0); else { - soisdisconnecting(so); - sbflush(&so->so_rcv); - tp = tcp_usrclosed(tp); - if (tp) - (void) tcp_output(tp); + SOCK_LOCK(so); + if ((so->so_options & SO_LINGER) && so->so_linger == 0) { + SOCK_UNLOCK(so); + tp = tcp_drop(tp, 0); + } else { + soisdisconnecting(so); + SOCK_UNLOCK(so); + sbflush(&so->so_rcv); + tp = tcp_usrclosed(tp); + if (tp) + (void) tcp_output(tp); + } } return (tp); } @@ -1120,7 +1157,9 @@ tcp_usrclosed(tp) break; } if (tp && tp->t_state >= TCPS_FIN_WAIT_2) { + SOCK_LOCK(tp->t_inpcb->inp_socket); soisdisconnected(tp->t_inpcb->inp_socket); + SOCK_UNLOCK(tp->t_inpcb->inp_socket); /* To prevent the connection hanging in FIN_WAIT_2 forever. */ if (tp->t_state == TCPS_FIN_WAIT_2) callout_reset(tp->tt_2msl, tcp_maxidle, diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index af4769f..1522966 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -319,8 +319,12 @@ udp_input(m, off) * port. It * assumes that an application will never * clear these options after setting them. */ - if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0) + SOCK_LOCK(last->inp_socket); + if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0) { + SOCK_UNLOCK(last->inp_socket); break; + } else + SOCK_UNLOCK(last->inp_socket); } if (last == NULL) { @@ -384,8 +388,10 @@ udp_input(m, off) */ udp_in.sin_port = uh->uh_sport; udp_in.sin_addr = ip->ip_src; + SOCK_LOCK(inp->inp_socket); if (inp->inp_flags & INP_CONTROLOPTS || inp->inp_socket->so_options & SO_TIMESTAMP) { + SOCK_UNLOCK(inp->inp_socket); #ifdef INET6 if (inp->inp_vflag & INP_IPV6) { int savedflags; @@ -398,7 +404,8 @@ udp_input(m, off) } else #endif ip_savecontrol(inp, &opts, ip, m); - } + } else + SOCK_UNLOCK(inp->inp_socket); m_adj(m, iphlen + sizeof(struct udphdr)); #ifdef INET6 if (inp->inp_vflag & INP_IPV6) { @@ -411,7 +418,9 @@ udp_input(m, off) udpstat.udps_fullsock++; goto bad; } + SOCK_LOCK(inp->inp_socket); sorwakeup(inp->inp_socket); + SOCK_UNLOCK(inp->inp_socket); return; bad: m_freem(m); @@ -453,8 +462,10 @@ udp_append(last, ip, n, off) struct sockaddr *append_sa; struct mbuf *opts = 0; + SOCK_LOCK(last->inp_socket); if (last->inp_flags & INP_CONTROLOPTS || last->inp_socket->so_options & SO_TIMESTAMP) { + SOCK_UNLOCK(last->inp_socket); #ifdef INET6 if (last->inp_vflag & INP_IPV6) { int savedflags; @@ -470,7 +481,8 @@ udp_append(last, ip, n, off) } else #endif ip_savecontrol(last, &opts, ip, n); - } + } else + SOCK_UNLOCK(last->inp_socket); #ifdef INET6 if (last->inp_vflag & INP_IPV6) { if (udp_in6.uin6_init_done == 0) { @@ -487,8 +499,11 @@ udp_append(last, ip, n, off) if (opts) m_freem(opts); udpstat.udps_fullsock++; - } else + } else { + SOCK_LOCK(last->inp_socket); sorwakeup(last->inp_socket); + SOCK_UNLOCK(last->inp_socket); + } } /* @@ -501,8 +516,10 @@ udp_notify(inp, errno) int errno; { inp->inp_socket->so_error = errno; + SOCK_LOCK(inp->inp_socket); sorwakeup(inp->inp_socket); sowwakeup(inp->inp_socket); + SOCK_UNLOCK(inp->inp_socket); } void @@ -678,7 +695,7 @@ udp_output(inp, m, addr, control, td) register int len = m->m_pkthdr.len; struct in_addr laddr; struct sockaddr_in *sin; - int s = 0, error = 0; + int s = 0, error = 0, soopts; if (control) m_freem(control); /* XXX */ @@ -759,8 +776,11 @@ udp_output(inp, m, addr, control, td) goto release; } #endif /*IPSEC*/ + SOCK_LOCK(inp->inp_socket); + soopts = inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST); + SOCK_UNLOCK(inp->inp_socket); error = ip_output(m, inp->inp_options, &inp->inp_route, - (inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)), + soopts, inp->inp_moptions); if (addr) { @@ -799,7 +819,9 @@ udp_abort(struct socket *so) inp = sotoinpcb(so); if (inp == 0) return EINVAL; /* ??? possible? panic instead? */ + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); s = splnet(); in_pcbdetach(inp); splx(s); @@ -864,8 +886,11 @@ udp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) prison_remote_ip(td->td_ucred, 0, &sin->sin_addr.s_addr); error = in_pcbconnect(inp, nam, td); splx(s); - if (error == 0) + if (error == 0) { + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); + } return error; } @@ -900,7 +925,9 @@ udp_disconnect(struct socket *so) in_pcbdisconnect(inp); inp->inp_laddr.s_addr = INADDR_ANY; splx(s); + SOCK_LOCK(so); so->so_state &= ~SS_ISCONNECTED; /* XXX */ + SOCK_UNLOCK(so); return 0; } |