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); }