Optimize defragmentation by storing all fragments in skb queue and reallocating skb only once all fragments are received.
Signed-off-by: Jiri Benc <[EMAIL PROTECTED]> --- net/d80211/ieee80211.c | 46 ++++++++++++++++++++++-------------------- net/d80211/ieee80211_i.h | 3 ++- net/d80211/ieee80211_iface.c | 19 ++++++++++++++--- 3 files changed, 41 insertions(+), 27 deletions(-) 162a9ab0920090224f0af03b4a79b45b35dd437f diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c index ac2c03f..cc06675 100644 --- a/net/d80211/ieee80211.c +++ b/net/d80211/ieee80211.c @@ -2822,10 +2822,10 @@ ieee80211_reassemble_add(struct ieee8021 if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX) sdata->fragment_next = 0; - if (entry->skb) { + if (!skb_queue_empty(&entry->skb_list)) { #ifdef CONFIG_D80211_DEBUG struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) entry->skb->data; + (struct ieee80211_hdr *) entry->skb_list.next->data; printk(KERN_DEBUG "%s: RX reassembly removed oldest " "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " "addr1=" MACSTR " addr2=" MACSTR "\n", @@ -2834,16 +2834,17 @@ #ifdef CONFIG_D80211_DEBUG entry->last_frag, MAC2STR(hdr->addr1), MAC2STR(hdr->addr2)); #endif /* CONFIG_D80211_DEBUG */ - dev_kfree_skb(entry->skb); + __skb_queue_purge(&entry->skb_list); } - entry->skb = *skb; + __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */ *skb = NULL; entry->first_frag_time = jiffies; entry->seq = seq; entry->rx_queue = rx_queue; entry->last_frag = frag; entry->ccmp = 0; + entry->extra_len = 0; return entry; } @@ -2867,12 +2868,12 @@ ieee80211_reassemble_find(struct ieee802 idx = IEEE80211_FRAGMENT_MAX - 1; entry = &sdata->fragments[idx]; - if (!entry->skb || entry->seq != seq || + if (skb_queue_empty(&entry->skb_list) || entry->seq != seq || entry->rx_queue != rx_queue || entry->last_frag + 1 != frag) continue; - f_hdr = (struct ieee80211_hdr *) entry->skb->data; + f_hdr = (struct ieee80211_hdr *) entry->skb_list.next->data; f_fc = le16_to_cpu(f_hdr->frame_control); if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_GET_TYPE(f_fc) || @@ -2881,8 +2882,7 @@ ieee80211_reassemble_find(struct ieee802 continue; if (entry->first_frag_time + 2 * HZ < jiffies) { - dev_kfree_skb(entry->skb); - entry->skb = NULL; + __skb_queue_purge(&entry->skb_list); continue; } return entry; @@ -2899,6 +2899,7 @@ ieee80211_rx_h_defragment(struct ieee802 u16 sc; unsigned int frag, seq; struct ieee80211_fragment_entry *entry; + struct sk_buff *skb; hdr = (struct ieee80211_hdr *) rx->skb->data; sc = le16_to_cpu(hdr->seq_ctrl); @@ -2966,30 +2967,30 @@ ieee80211_rx_h_defragment(struct ieee802 memcpy(entry->last_pn, pn, CCMP_PN_LEN); } - /* TODO: could gather list of skb's and reallocate data buffer only - * after finding out the total length of the frame */ skb_pull(rx->skb, ieee80211_get_hdrlen(rx->fc)); - if (skb_tailroom(entry->skb) < rx->skb->len) { + __skb_queue_tail(&entry->skb_list, rx->skb); + entry->last_frag = frag; + entry->extra_len += rx->skb->len; + if (rx->fc & WLAN_FC_MOREFRAG) { + rx->skb = NULL; + return TXRX_QUEUED; + } + + rx->skb = __skb_dequeue(&entry->skb_list); + if (skb_tailroom(rx->skb) < entry->extra_len) { I802_DEBUG_INC(rx->local->rx_expand_skb_head2); - if (unlikely(pskb_expand_head(entry->skb, 0, rx->skb->len, + if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len, GFP_ATOMIC))) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); + __skb_queue_purge(&entry->skb_list); return TXRX_DROP; } } - memcpy(skb_put(entry->skb, rx->skb->len), rx->skb->data, rx->skb->len); - entry->last_frag = frag; - dev_kfree_skb(rx->skb); - - if (rx->fc & WLAN_FC_MOREFRAG) { - rx->skb = NULL; - return TXRX_QUEUED; - } + while ((skb = __skb_dequeue(&entry->skb_list))) + memcpy(skb_put(rx->skb, skb->len), skb->data, skb->len); /* Complete frame has been reassembled - process it now */ - rx->skb = entry->skb; rx->fragmented = 1; - entry->skb = NULL; out: if (rx->sta) @@ -4390,6 +4391,7 @@ struct net_device *ieee80211_alloc_hw(si sdata->dev = mdev; sdata->master = mdev; sdata->local = local; + ieee80211_if_sdata_init(sdata); list_add_tail(&sdata->list, &local->sub_if_list); tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h index 6a952bd..b4e294c 100644 --- a/net/d80211/ieee80211_i.h +++ b/net/d80211/ieee80211_i.h @@ -62,7 +62,8 @@ struct ieee80211_fragment_entry { unsigned int seq; unsigned int rx_queue; unsigned int last_frag; - struct sk_buff *skb; + unsigned int extra_len; + struct sk_buff_head skb_list; int ccmp; /* Whether fragments were encrypted with CCMP */ u8 last_pn[6]; /* PN of the last fragment if CCMP was used */ }; diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c index f49ce8a..f64b4de 100644 --- a/net/d80211/ieee80211_iface.c +++ b/net/d80211/ieee80211_iface.c @@ -18,9 +18,22 @@ #include "sta_info.h" void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) { + int i; + /* Default values for sub-interface parameters */ sdata->drop_unencrypted = 0; sdata->eapol = 1; + for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) + skb_queue_head_init(&sdata->fragments[i].skb_list); +} + +static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata) +{ + int i; + + for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) { + __skb_queue_purge(&sdata->fragments[i].skb_list); + } } /* Must be called with rtnl lock held. */ @@ -212,6 +225,7 @@ void ieee80211_if_reinit(struct net_devi int i; ASSERT_RTNL(); + ieee80211_if_sdata_deinit(sdata); for (i = 0; i < NUM_DEFAULT_KEYS; i++) { if (!sdata->keys[i]) continue; @@ -337,13 +351,10 @@ void ieee80211_if_free(struct net_device { struct ieee80211_local *local = dev->ieee80211_ptr; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int i; /* local->apdev must be NULL when freeing management interface */ BUG_ON(dev == local->apdev); - for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) - if (sdata->fragments[i].skb) - dev_kfree_skb(sdata->fragments[i].skb); + ieee80211_if_sdata_deinit(sdata); free_netdev(dev); } -- 1.3.0 - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html