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(-)
240090e43ed16ad95dd2c7865a681b26f739efc0
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 7b0b4c1..1494603 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -2824,10 +2824,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",
@@ -2836,16 +2836,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;
}
@@ -2869,12 +2870,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) ||
@@ -2883,8 +2884,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;
@@ -2901,6 +2901,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);
@@ -2968,30 +2969,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)
@@ -4392,6 +4393,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