Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 3 Feb 2008 18:33:47 GMT
From:      Andre Oppermann <andre@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 134732 for review
Message-ID:  <200802031833.m13IXlJp034327@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=134732

Change 134732 by andre@andre_flirtbox on 2008/02/03 18:33:20

	Handle FIN queueing in reassembly queue and cover all edge
	cases.  Sprinkle appropriate KASSERTs.

Affected files ...

.. //depot/projects/tcp_new/netinet/tcp_input.c#3 edit
.. //depot/projects/tcp_reass/netinet/tcp_input.c#4 edit
.. //depot/projects/tcp_reass/netinet/tcp_reass.c#16 edit
.. //depot/projects/tcp_reass/netinet/tcp_var.h#7 edit

Differences ...

==== //depot/projects/tcp_new/netinet/tcp_input.c#3 (text+ko) ====


==== //depot/projects/tcp_reass/netinet/tcp_input.c#4 (text+ko) ====

@@ -2254,7 +2254,7 @@
 			 * m_adj() doesn't actually frees any mbufs
 			 * when trimming from the head.
 			 */
-			thflags = tcp_reass(tp, th, &tlen, m);
+			thflags |= tcp_reass(tp, th, &tlen, m);
 			tp->t_flags |= TF_ACKNOW;
 		}
 #if 0

==== //depot/projects/tcp_reass/netinet/tcp_reass.c#16 (text+ko) ====

@@ -174,7 +174,7 @@
 	struct trq *tqe, *tqen;
 	struct socket *so = tp->t_inpcb->inp_socket;
 	struct mbuf *n;
-	int i, flags = 0, mcnt;
+	int i, thflags = 0, mcnt;
 	struct trq tqes;
 
 	INP_LOCK_ASSERT(tp->t_inpcb);
@@ -192,6 +192,7 @@
 			return (0);
 		goto present;
 	}
+	thflags = (th->th_flags & TH_FIN);
 
 	/* Check if it is really neccessary to do all the work. */
 	if (!tcp_reass_enabled && TAILQ_EMPTY(&tp->t_trq)) {
@@ -221,6 +222,8 @@
 		KASSERT(tqen == NULL ||
 		    SEQ_LT(tqe->trq_seq + tqe->trq_len, tqen->trq_seq),
 		    ("%s: overlapping blocks", __func__));
+		KASSERT(!(thflags & TH_FIN) || tqe == TAILQ_LAST(&tp->t_trq, trq_head),
+		    ("%s: FIN on block before last one", __func__));
 		i++;
 	}
 	LIST_FOREACH(tqe, &tp->t_trq_sack, trq_s) {
@@ -276,8 +279,33 @@
 		mcnt += (n->m_flags & M_EXT) ?
 		    n->m_ext.ext_size + MSIZE : MSIZE;
 
-	/* Check if this segment attaches to the end. */
+	/* Check if we've already received FIN; we can't accept data beyond it. */
 	tqe = TAILQ_LAST(&tp->t_trq, trq_head);
+	if (tqe && (tqe->trq_thflags & TH_FIN) && SEQ_LEQ(tqe->trq_seq, th->th_seq)) {
+		/* Properly count retransmitted perfect matching FIN. */
+		if (tqe->trq_seq == th->th_seq && *tlenp > 0)
+			tcpstat.tcps_rcvoopack++;
+		else {
+			tcpstat.tcps_rcvpackafterfin++;
+			tcpstat.tcps_rcvbyteafterfin += *tlenp;
+		}
+		m_freem(m);
+		*tlenp = 0;
+		return (0);
+	}
+
+	/* Check if this segments FIN is before the end of the last block. */
+	if (tqe && (thflags & TH_FIN) &&
+	    SEQ_GT(tqe->trq_seq + tqe->trq_len, th->th_seq + *tlenp)) {
+		/* TCP statistics. */
+		tcpstat.tcps_rcvpackafterfin++;
+		tcpstat.tcps_rcvbyteafterfin += *tlenp;
+		m_freem(m);
+		*tlenp = 0;
+		return (0);
+	}
+
+	/* Check if this segment directly attaches to the end. */
 	if (tqe && tqe->trq_seq + tqe->trq_len == th->th_seq) {
 		tqe->trq_len += *tlenp;
 		tqe->trq_mcnt += mcnt;
@@ -285,6 +313,7 @@
 		tcp_reass_mcnt += mcnt;
 		tqe->trq_ml->m_next = m;
 		tqe->trq_ml = m_last(m);
+		tqe->trq_thflags |= thflags;
 		if (LIST_FIRST(&tp->t_trq_sack) != tqe) {
 			LIST_REMOVE(tqe, trq_s);
 			LIST_INSERT_HEAD(&tp->t_trq_sack, tqe, trq_s);
@@ -355,6 +384,7 @@
 			tcpstat.tcps_rcvduppack++;
 			tcpstat.tcps_rcvdupbyte += *tlenp;
 			tcpstat.tcps_reass_covered++;
+			tqe->trq_thflags |= thflags;
 			/* XXXAO: What to SACK report when duplicate? */
 			if (LIST_FIRST(&tp->t_trq_sack) != tqe) {
 				LIST_REMOVE(tqe, trq_s);
@@ -378,6 +408,7 @@
 			tqe->trq_seq = th->th_seq;
 			tqe->trq_m = m;
 			tqe->trq_ml = m_last(m);
+			tqe->trq_thflags |= thflags;
 			/* Check if segment bridges next block to merge. */
 			if (tqen != NULL &&
 			    SEQ_GEQ(tqe->trq_seq + tqe->trq_len, tqen->trq_seq))
@@ -394,6 +425,8 @@
 		if (SEQ_GT(tqe->trq_seq, th->th_seq) &&
 		    SEQ_LEQ(tqe->trq_seq, th->th_seq + *tlenp) &&
 		    SEQ_GEQ(tqe->trq_seq + tqe->trq_len, th->th_seq + *tlenp)) {
+			KASSERT(!(thflags & TH_FIN),
+			    ("%s: new segment with FIN can't prepend", __func__));
 			/* Trim tail of segment. */
 			if ((i = SEQ_DELTA(tqe->trq_seq, th->th_seq + *tlenp))) {
 				m_adj(m, -i);
@@ -440,6 +473,7 @@
 			tcp_reass_mcnt += mcnt;
 			tqe->trq_ml->m_next = m;
 			tqe->trq_ml = m_last(m);
+			tqe->trq_thflags |= thflags;
 			/* Check if segment bridges two blocks to merge. */
 			if (tqen != NULL &&
 			    SEQ_GEQ(tqe->trq_seq + tqe->trq_len, tqen->trq_seq))
@@ -480,6 +514,7 @@
 	tcp_reass_mcnt += mcnt;
 	tqen->trq_m = m;
 	tqen->trq_ml = m_last(m);
+	tqen->trq_thflags |= thflags;
 
 	/* Where to insert. */
 	if (tqe != NULL && SEQ_LT(tqe->trq_seq + tqe->trq_len, th->th_seq))
@@ -521,15 +556,14 @@
 		    ("%s: block overlaps into next one", __func__));
 		if (tqe->trq_seq != tp->rcv_nxt)
 			break;
-#if 1
-		/* XXX: This is bogus if we had a FIN. */
-		flags = tqe->trq_flags;
-#endif
 		if (so->so_rcv.sb_state & SBS_CANTRCVMORE)
 			m_freem(tqe->trq_m);
 		else
 			sbappendstream_locked(&so->so_rcv, tqe->trq_m);
 		tp->rcv_nxt += tqe->trq_len;
+		thflags = tqe->trq_thflags;
+		KASSERT(!(thflags & TH_FIN) || tqe == TAILQ_LAST(&tp->t_trq, trq_head),
+		    ("%s: FIN not on last block", __func__));
 		tp->t_trqmcnt -= tqe->trq_mcnt;
 		tcp_reass_mcnt -= tqe->trq_mcnt;
 		TAILQ_REMOVE(&tp->t_trq, tqe, trq_q);
@@ -552,11 +586,7 @@
 		tcp_timer_activate(tp, TT_REASS, 0);
 
 	ND6_HINT(tp);
-#if 1
-	return (flags);
-#else
-	return (0);
-#endif
+	return (thflags);
 }
 
 /*

==== //depot/projects/tcp_reass/netinet/tcp_var.h#7 (text+ko) ====

@@ -47,8 +47,7 @@
 	tcp_seq		trq_seq;	/* start of block */
 	int		trq_len;	/* length of block */
 	int		trq_mcnt;	/* gross mbuf size of block */
-	int		trq_flags;	/* flags for segment chain */
-#define TRQ_FIN		0x01		/* FIN was on last segment */
+	int		trq_thflags;	/* thflags for segment chain */
 	struct mbuf	*trq_m;		/* mbuf chain of data */
 	struct mbuf	*trq_ml;	/* last mbuf in chain of data */
 };
@@ -387,6 +386,8 @@
 	u_long	tcps_rcvpackafterwin;	/* packets with data after window */
 	u_long	tcps_rcvbyteafterwin;	/* bytes rcvd after window */
 	u_long	tcps_rcvafterclose;	/* packets rcvd after "close" */
+	u_long	tcps_rcvpackafterfin;	/* packets rcvd after FIN */
+	u_long	tcps_rcvbyteafterfin;	/* bytes rcvd after FIN */
 	u_long	tcps_rcvwinprobe;	/* rcvd window probe packets */
 	u_long	tcps_rcvdupack;		/* rcvd duplicate acks */
 	u_long	tcps_rcvacktoomuch;	/* rcvd acks for unsent data */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200802031833.m13IXlJp034327>