PERFORCE change 134732 for review
Andre Oppermann
andre at FreeBSD.org
Sun Feb 3 10:33:48 PST 2008
http://perforce.freebsd.org/chv.cgi?CH=134732
Change 134732 by andre at 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 */
More information about the p4-projects
mailing list