* context. */
static DefragContext *defrag_context;
+RB_GENERATE(IP_FRAGMENTS, Frag_, rb, DefragRbFragCompare);
+
/**
* Utility/debugging function to dump the frags associated with a
* tracker. Only enable when unit tests are enabled.
void
DefragTrackerFreeFrags(DefragTracker *tracker)
{
- Frag *frag;
+ Frag *frag, *tmp;
/* Lock the frag pool as we'll be return items to it. */
SCMutexLock(&defrag_context->frag_pool_lock);
- while ((frag = TAILQ_FIRST(&tracker->frags)) != NULL) {
- TAILQ_REMOVE(&tracker->frags, frag, next);
-
- /* Don't SCFree the frag, just give it back to its pool. */
+ RB_FOREACH_SAFE(frag, IP_FRAGMENTS, &tracker->fragment_tree, tmp) {
+ RB_REMOVE(IP_FRAGMENTS, &tracker->fragment_tree, frag);
DefragFragReset(frag);
PoolReturn(defrag_context->frag_pool, frag);
}
/* Check that we have all the data. Relies on the fact that
* fragments are inserted if frag_offset order. */
- Frag *frag;
+ Frag *frag = NULL;
int len = 0;
- TAILQ_FOREACH(frag, &tracker->frags, next) {
- if (frag->skip)
- continue;
-
- if (frag == TAILQ_FIRST(&tracker->frags)) {
- if (frag->offset != 0) {
- goto done;
- }
- len = frag->data_len;
+ RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
+ if (frag->offset > len) {
+ /* This fragment starts after the end of the previous
+ * fragment. We have a hole. */
+ goto done;
}
else {
- if (frag->offset > len) {
- /* This fragment starts after the end of the previous
- * fragment. We have a hole. */
- goto done;
- }
- else {
- len += frag->data_len;
- }
+ len += frag->data_len;
}
}
int fragmentable_len = 0;
int hlen = 0;
int ip_hdr_offset = 0;
- TAILQ_FOREACH(frag, &tracker->frags, next) {
+
+ RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
SCLogDebug("frag %p, data_len %u, offset %u, pcap_cnt %"PRIu64,
frag, frag->data_len, frag->offset, frag->pcap_cnt);
/* Check that we have all the data. Relies on the fact that
* fragments are inserted if frag_offset order. */
- Frag *frag;
int len = 0;
- TAILQ_FOREACH(frag, &tracker->frags, next) {
- if (frag->skip)
+ Frag *first = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
+ Frag *frag = NULL;
+ RB_FOREACH_FROM(frag, IP_FRAGMENTS, first) {
+ if (frag->skip) {
continue;
+ }
- if (frag == TAILQ_FIRST(&tracker->frags)) {
+ if (frag == first) {
if (frag->offset != 0) {
goto done;
}
int fragmentable_len = 0;
int ip_hdr_offset = 0;
uint8_t next_hdr = 0;
- TAILQ_FOREACH(frag, &tracker->frags, next) {
+ RB_FOREACH(frag, IP_FRAGMENTS, &tracker->fragment_tree) {
if (frag->skip)
continue;
if (frag->data_len - frag->ltrim <= 0)
return NULL;
}
+/**
+ * The RB_TREE compare function for fragments.
+ *
+ * When it comes to adding fragments, we want subsequent ones with the
+ * same offset to be treated as greater than, so we don't have an
+ * equal return value here.
+ */
+int DefragRbFragCompare(struct Frag_ *a, struct Frag_ *b) {
+ if (a->offset < b->offset) {
+ return -1;
+ }
+ return 1;
+}
+
/**
* Insert a new IPv4/IPv6 fragment into a tracker.
*
tracker->timeout.tv_sec = p->ts.tv_sec + tracker->host_timeout;
tracker->timeout.tv_usec = p->ts.tv_usec;
- Frag *prev = NULL, *next;
+ Frag *prev = NULL, *next = NULL;
int overlap = 0;
ltrim = 0;
- if (!TAILQ_EMPTY(&tracker->frags)) {
- TAILQ_FOREACH(prev, &tracker->frags, next) {
+
+ if (!RB_EMPTY(&tracker->fragment_tree)) {
+ Frag key = {
+ .offset = frag_offset - 1,
+ };
+ next = RB_NFIND(IP_FRAGMENTS, &tracker->fragment_tree, &key);
+ if (next == NULL) {
+ prev = RB_MIN(IP_FRAGMENTS, &tracker->fragment_tree);
+ next = IP_FRAGMENTS_RB_NEXT(prev);
+ } else {
+ prev = IP_FRAGMENTS_RB_PREV(next);
+ if (prev == NULL) {
+ prev = next;
+ next = IP_FRAGMENTS_RB_NEXT(prev);
+ }
+ }
+ while (prev != NULL) {
if (prev->skip) {
- continue;
+ goto next;
}
- next = TAILQ_NEXT(prev, next);
switch (tracker->policy) {
case DEFRAG_POLICY_BSD:
default:
break;
}
+
+ next:
+ prev = next;
+ if (next != NULL) {
+ next = IP_FRAGMENTS_RB_NEXT(next);
+ }
}
}
new->pcap_cnt = pcap_cnt;
#endif
- Frag *frag;
- TAILQ_FOREACH(frag, &tracker->frags, next) {
- if (new->offset < frag->offset)
- break;
- }
- if (frag == NULL) {
- TAILQ_INSERT_TAIL(&tracker->frags, new, next);
- }
- else {
- TAILQ_INSERT_BEFORE(frag, new, next);
- }
+ IP_FRAGMENTS_RB_INSERT(&tracker->fragment_tree, new);
if (!more_frags) {
tracker->seen_last = 1;