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

Reply via email to