/* Given the OR values of all fragments, apply RFC 3168 5.3 requirements *Value:0xffifframeshouldbedropped. *0orINET_ECN_CEvalue,tobeORedintofinaliph->tosfield
*/ const u8 ip_frag_ecn_table[16] = { /* at least one fragment had CE, and others ECT_0 or ECT_1 */
[IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0] = INET_ECN_CE,
[IPFRAG_ECN_CE | IPFRAG_ECN_ECT_1] = INET_ECN_CE,
[IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = INET_ECN_CE,
/* Atomically snapshot the list of fqdirs to free */
kill_list = llist_del_all(&fqdir_free_list);
/* We need to make sure all ongoing call_rcu(..., inet_frag_destroy_rcu) *havecompleted,sincetheyneedtodereferencefqdir. *Woulditnotbenicetohavekfree_rcu_barrier()?:)
*/
rcu_barrier();
llist_for_each_entry_safe(fqdir, tmp, kill_list, free_list) {
f = fqdir->f; if (refcount_dec_and_test(&f->refcnt))
complete(&f->completion);
timer_setup(&q->timer, f->frag_expire, 0);
spin_lock_init(&q->lock); /* One reference for the timer, one for the hash table. */
refcount_set(&q->refcnt, 2);
*prev = rhashtable_lookup_get_insert_key(&fqdir->rhashtable, &q->key,
&q->node, f->rhash_params); if (*prev) { /* We could not insert in the hash table, *weneedtocancelwhatinet_frag_alloc() *anticipated.
*/ int refs = 1;
int inet_frag_queue_insert(struct inet_frag_queue *q, struct sk_buff *skb, int offset, int end)
{ struct sk_buff *last = q->fragments_tail;
/* RFC5722, Section 4, amended by Errata ID : 3089 *WhenreassemblinganIPv6datagram,if *oneormoreitsconstituentfragmentsisdeterminedtobean *overlappingfragment,theentiredatagram(andanyconstituent *fragments)MUSTbesilentlydiscarded. * *Duplicates,however,shouldbeignored(i.e.skbdropped,butthe *queue/fragmentskeptforlaterreassembly).
*/ if (!last)
fragrun_create(q, skb); /* First fragment. */ elseif (FRAG_CB(last)->ip_defrag_offset + last->len < end) { /* This is the common case: skb goes to the end. */ /* Detect and discard overlaps. */ if (offset < FRAG_CB(last)->ip_defrag_offset + last->len) return IPFRAG_OVERLAP; if (offset == FRAG_CB(last)->ip_defrag_offset + last->len)
fragrun_append_to_last(q, skb); else
fragrun_create(q, skb);
} else { /* Binary search. Note that skb can become the first fragment, *butnotthelast(coveredabove).
*/ struct rb_node **rbn, *parent;
rbn = &q->rb_fragments.rb_node; do { struct sk_buff *curr; int curr_run_end;
parent = *rbn;
curr = rb_to_skb(parent);
curr_run_end = FRAG_CB(curr)->ip_defrag_offset +
FRAG_CB(curr)->frag_run_len; if (end <= FRAG_CB(curr)->ip_defrag_offset)
rbn = &parent->rb_left; elseif (offset >= curr_run_end)
rbn = &parent->rb_right; elseif (offset >= FRAG_CB(curr)->ip_defrag_offset &&
end <= curr_run_end) return IPFRAG_DUP; else return IPFRAG_OVERLAP;
} while (*rbn); /* Here we have parent properly set, and rbn pointing to *oneofitsNULLleft/rightchildren.Insertskb.
*/
fragcb_clear(skb);
rb_link_node(&skb->rbnode, parent, rbn);
rb_insert_color(&skb->rbnode, &q->rb_fragments);
}
if (sk && is_skb_wmem(skb)) { /* TX: skb->sk might have been passed as argument to *dst->outputandmustremainvaliduntiltxcompletes. * *Movesktoreassembledskbandfixupwmemaccounting.
*/
orig_truesize = skb->truesize;
destructor = skb->destructor;
}
if (head != skb) {
fp = skb_clone(skb, GFP_ATOMIC); if (!fp) {
head = skb; goto out_restore_sk;
}
FRAG_CB(fp)->next_frag = FRAG_CB(skb)->next_frag; if (RB_EMPTY_NODE(&skb->rbnode))
FRAG_CB(parent)->next_frag = fp; else
rb_replace_node(&skb->rbnode, &fp->rbnode,
&q->rb_fragments); if (q->fragments_tail == skb)
q->fragments_tail = fp;
if (orig_truesize) { /* prevent skb_morph from releasing sk */
skb->sk = NULL;
skb->destructor = NULL;
}
skb_morph(skb, head);
FRAG_CB(skb)->next_frag = FRAG_CB(head)->next_frag;
rb_replace_node(&head->rbnode, &skb->rbnode,
&q->rb_fragments);
consume_skb(head);
head = skb;
}
WARN_ON(FRAG_CB(head)->ip_defrag_offset != 0);
delta = -head->truesize;
/* Head of list must not be cloned. */ if (skb_unclone(head, GFP_ATOMIC)) goto out_restore_sk;
delta += head->truesize; if (delta)
add_frag_mem_limit(q->fqdir, delta);
/* If the first fragment is fragmented itself, we split *ittotwochunks:thefirstwithdataandpagedpart *andthesecond,holdingonlyfragments.
*/ if (skb_has_frag_list(head)) { struct sk_buff *clone; int i, plen = 0;
/* Traverse the tree in order, to build frag_list. */
fp = FRAG_CB(head)->next_frag;
rbn = rb_next(&head->rbnode);
rb_erase(&head->rbnode, &q->rb_fragments);
sum_truesize = head->truesize; while (rbn || fp) { /* fp points to the next sk_buff in the current run; *rbnpointstothenextrun.
*/ /* Go through the current run. */ while (fp) { struct sk_buff *next_frag = FRAG_CB(fp)->next_frag; bool stolen; int delta;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.