kernel - MPSAFE the protocol drain routines
[dragonfly.git] / sys / netinet / tcp_input.c
index 9bcc360..3069521 100644 (file)
@@ -69,6 +69,7 @@
  */
 
 #include "opt_ipfw.h"          /* for ipfw_fwd         */
+#include "opt_inet.h"
 #include "opt_inet6.h"
 #include "opt_ipsec.h"
 #include "opt_tcpdebug.h"
@@ -307,7 +308,7 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m)
                tp->reportblk.rblk_start = tp->reportblk.rblk_end;
                return (0);
        }
-       tcp_reass_qsize++;
+       atomic_add_int(&tcp_reass_qsize, 1);
 
        /*
         * Find a segment which begins after this one does.
@@ -340,7 +341,7 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m)
                                tcpstat.tcps_rcvdupbyte += *tlenp;
                                m_freem(m);
                                kfree(te, M_TSEGQ);
-                               tcp_reass_qsize--;
+                               atomic_add_int(&tcp_reass_qsize, -1);
                                /*
                                 * Try to present any queued data
                                 * at the left window edge to the user.
@@ -395,7 +396,7 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m)
                LIST_REMOVE(q, tqe_q);
                m_freem(q->tqe_m);
                kfree(q, M_TSEGQ);
-               tcp_reass_qsize--;
+               atomic_add_int(&tcp_reass_qsize, -1);
                q = nq;
        }
 
@@ -421,7 +422,7 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m)
                        tp->reportblk.rblk_end = tend;
                LIST_REMOVE(q, tqe_q);
                kfree(q, M_TSEGQ);
-               tcp_reass_qsize--;
+               atomic_add_int(&tcp_reass_qsize, -1);
        }
 
        if (p == NULL) {
@@ -439,9 +440,10 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m)
                        if (!(tp->t_flags & TF_DUPSEG))
                                tp->reportblk.rblk_start = p->tqe_th->th_seq;
                        kfree(te, M_TSEGQ);
-                       tcp_reass_qsize--;
-               } else
+                       atomic_add_int(&tcp_reass_qsize, -1);
+               } else {
                        LIST_INSERT_AFTER(p, te, tqe_q);
+               }
        }
 
 present:
@@ -471,7 +473,7 @@ present:
        else
                ssb_appendstream(&so->so_rcv, q->tqe_m);
        kfree(q, M_TSEGQ);
-       tcp_reass_qsize--;
+       atomic_add_int(&tcp_reass_qsize, -1);
        ND6_HINT(tp);
        sorwakeup(so);
        return (flags);
@@ -520,7 +522,8 @@ tcp_input(struct mbuf *m, ...)
        struct inpcb *inp = NULL;
        u_char *optp = NULL;
        int optlen = 0;
-       int len, tlen, off;
+       int tlen, off;
+       int len = 0;
        int drop_hdrlen;
        struct tcpcb *tp = NULL;
        int thflags;
@@ -892,13 +895,21 @@ findpcb:
                                        rstreason = BANDLIM_RST_OPENPORT;
                                        goto dropwithreset;
                                }
+
+                               /*
+                                * Could not complete 3-way handshake,
+                                * connection is being closed down, and
+                                * syncache will free mbuf.
+                                */
                                if (so == NULL)
-                                       /*
-                                        * Could not complete 3-way handshake,
-                                        * connection is being closed down, and
-                                        * syncache will free mbuf.
-                                        */
                                        return;
+
+                               /*
+                                * We must be in the correct protocol thread
+                                * for this connection.
+                                */
+                               KKASSERT(so->so_port == &curthread->td_msgport);
+
                                /*
                                 * Socket is created in state SYN_RECEIVED.
                                 * Continue processing segment.
@@ -1022,12 +1033,20 @@ findpcb:
                        tcp_dooptions(&to, optp, optlen, TRUE);
                        if (!syncache_add(&inc, &to, th, &so, m))
                                goto drop;
+
+                       /*
+                        * Entry added to syncache, mbuf used to
+                        * send SYN,ACK packet.
+                        */
                        if (so == NULL)
-                               /*
-                                * Entry added to syncache, mbuf used to
-                                * send SYN,ACK packet.
-                                */
                                return;
+
+                       /*
+                        * We must be in the correct protocol thread for
+                        * this connection.
+                        */
+                       KKASSERT(so->so_port == &curthread->td_msgport);
+
                        inp = so->so_pcb;
                        tp = intotcpcb(inp);
                        tp->snd_wnd = tiwin;
@@ -1059,10 +1078,16 @@ findpcb:
                }
                goto drop;
        }
-after_listen:
 
-       /* should not happen - syncache should pick up these connections */
+after_listen:
+       /*
+        * Should not happen - syncache should pick up these connections.
+        *
+        * Once we are past handling listen sockets we must be in the
+        * correct protocol processing thread.
+        */
        KASSERT(tp->t_state != TCPS_LISTEN, ("tcp_input: TCPS_LISTEN state"));
+       KKASSERT(so->so_port == &curthread->td_msgport);
 
        /*
         * This is the second part of the MSS DoS prevention code (after
@@ -1343,11 +1368,11 @@ after_listen:
                                        tp->t_flags |= TF_RXRESIZED;
                                        if (!ssb_reserve(&so->so_rcv, newsize,
                                                         so, NULL)) {
-                                               so->so_rcv.ssb_flags &= ~SSB_AUTOSIZE;
+                                               atomic_clear_int(&so->so_rcv.ssb_flags, SSB_AUTOSIZE);
                                        }
                                        if (newsize >=
                                            (TCP_MAXWIN << tp->rcv_scale)) {
-                                               so->so_rcv.ssb_flags &= ~SSB_AUTOSIZE;
+                                               atomic_clear_int(&so->so_rcv.ssb_flags, SSB_AUTOSIZE);
                                        }
                                }
                                m_adj(m, drop_hdrlen); /* delayed header drop */
@@ -2701,6 +2726,19 @@ tcp_dooptions(struct tcpopt *to, u_char *cp, int cnt, boolean_t is_syn)
                                r->rblk_end = ntohl(r->rblk_end);
                        }
                        break;
+#ifdef TCP_SIGNATURE
+               /*
+                * XXX In order to reply to a host which has set the
+                * TCP_SIGNATURE option in its initial SYN, we have to
+                * record the fact that the option was observed here
+                * for the syncache code to perform the correct response.
+                */
+               case TCPOPT_SIGNATURE:
+                       if (optlen != TCPOLEN_SIGNATURE)
+                               continue;
+                       to->to_flags |= (TOF_SIGNATURE | TOF_SIGLEN);
+                       break;
+#endif /* TCP_SIGNATURE */
                default:
                        continue;
                }