There's no need to walk the entire fragment list to determine
if we have all the bytes of the unfragmented packet if we keep
a running count on how much we've seen already.
Please to be testing as we need to make sure that our userbase
remains unmolested.
- Bert
Index: pf_norm.c
===================================================================
RCS file: /cvs/src/sys/net/pf_norm.c,v
retrieving revision 1.132
diff -u -p -r1.132 pf_norm.c
--- pf_norm.c 23 Apr 2011 10:00:36 -0000 1.132
+++ pf_norm.c 16 May 2011 15:35:20 -0000
@@ -97,6 +97,7 @@ struct pf_fragment {
TAILQ_ENTRY(pf_fragment) frag_next;
u_int32_t fr_timeout;
u_int16_t fr_maxlen; /* maximum length of single fragment */
+ u_int16_t fr_qlen; /* length of current queue */
TAILQ_HEAD(pf_fragq, pf_frent) fr_queue;
};
@@ -322,6 +323,7 @@ pf_fillup_fragment(struct pf_fragment_cm
*(struct pf_fragment_cmp *)frag = *key;
frag->fr_timeout = time_second;
frag->fr_maxlen = frent->fe_len;
+ frag->fr_qlen = frent->fe_len;
TAILQ_INIT(&frag->fr_queue);
RB_INSERT(pf_frag_tree, &pf_frag_tree, frag);
@@ -401,6 +403,9 @@ pf_fillup_fragment(struct pf_fragment_cm
pf_nfrents--;
}
+ /* Adjust queue length */
+ frag->fr_qlen += frent->fe_len;
+
if (prev == NULL)
TAILQ_INSERT_HEAD(&frag->fr_queue, frent, fr_next);
else
@@ -419,8 +424,7 @@ pf_fillup_fragment(struct pf_fragment_cm
int
pf_isfull_fragment(struct pf_fragment *frag)
{
- struct pf_frent *frent, *next;
- u_int16_t off, total;
+ u_int16_t total;
/* Check if we are completely reassembled */
if (TAILQ_LAST(&frag->fr_queue, pf_fragq)->fe_mff)
@@ -431,22 +435,14 @@ pf_isfull_fragment(struct pf_fragment *f
TAILQ_LAST(&frag->fr_queue, pf_fragq)->fe_len;
/* Check if we have all the data */
- off = 0;
- for (frent = TAILQ_FIRST(&frag->fr_queue); frent; frent = next) {
- next = TAILQ_NEXT(frent, fr_next);
-
- off += frent->fe_len;
- if (off < total && (next == NULL || next->fe_off != off)) {
- DPFPRINTF(LOG_NOTICE,
- "missing fragment at %d, next %d, total %d",
- off, next == NULL ? -1 : next->fe_off, total);
- return (0);
- }
- }
- DPFPRINTF(LOG_NOTICE, "%d < %d?", off, total);
- if (off < total)
+ if (frag->fr_qlen < total) {
+ DPFPRINTF(LOG_NOTICE,
+ "missing fragment: need %d have %d", total, frag->fr_qlen);
return (0);
- KASSERT(off == total);
+ }
+
+ DPFPRINTF(LOG_NOTICE, "%d < %d?", frag->fr_qlen, total);
+ KASSERT(frag->fr_qlen == total);
return (1);
}