From: Johannes Berg <johannes@sipsolutions.net>
To: linux-wireless@vger.kernel.org
Subject: [RFT/C 2/7] mac80211: clean up skb reallocation code
Date: Sun, 11 May 2008 00:18:47 +0200 [thread overview]
Message-ID: <20080510221906.261962000@sipsolutions.net> (raw)
In-Reply-To: 20080510221845.340428000@sipsolutions.net
This cleans up the skb reallocation code to avoid problems with
skb->truesize and not resize an skb twice for a single output
path because we didn't expand it enough during the first copy.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/tx.c | 97 +++++++++++++++++++++++++++++++++++++----------------
net/mac80211/wep.c | 10 +----
net/mac80211/wpa.c | 50 ++++++++++-----------------
3 files changed, 91 insertions(+), 66 deletions(-)
--- everything.orig/net/mac80211/tx.c 2008-05-10 23:00:37.000000000 +0200
+++ everything/net/mac80211/tx.c 2008-05-10 23:06:30.000000000 +0200
@@ -1244,6 +1244,45 @@ retry:
/* device xmit handlers */
+static int ieee80211_skb_resize(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ int head_need, bool encrypt)
+{
+ int tail_need = 0;
+
+ /*
+ * This could be optimised, devices that do full hardware
+ * crypto need no tailroom... But we have no drivers for
+ * such devices currently.
+ */
+ if (encrypt) {
+ tail_need = IEEE80211_ENCRYPT_TAILROOM;
+ tail_need -= skb_tailroom(skb);
+ tail_need = max_t(int, tail_need, 0);
+ }
+
+ if (head_need || tail_need) {
+ /* Sorry. Can't account for this any more */
+ skb_orphan(skb);
+ }
+
+ if (skb_cloned(skb))
+ I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
+ else
+ I802_DEBUG_INC(local->tx_expand_skb_head);
+
+ if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) {
+ printk(KERN_DEBUG "%s: failed to reallocate TX buffer\n",
+ wiphy_name(local->hw.wiphy));
+ return -ENOMEM;
+ }
+
+ /* update truesize too */
+ skb->truesize += head_need + tail_need;
+
+ return 0;
+}
+
int ieee80211_master_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
@@ -1252,6 +1291,7 @@ int ieee80211_master_start_xmit(struct s
struct net_device *odev = NULL;
struct ieee80211_sub_if_data *osdata;
int headroom;
+ bool encrypt;
int ret;
/*
@@ -1276,13 +1316,18 @@ int ieee80211_master_start_xmit(struct s
}
osdata = IEEE80211_DEV_TO_SUB_IF(odev);
- headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM;
- if (skb_headroom(skb) < headroom) {
- if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) {
- dev_kfree_skb(skb);
- dev_put(odev);
- return 0;
- }
+ encrypt = !(pkt_data->flags & IEEE80211_TXPD_DO_NOT_ENCRYPT);
+
+ headroom = osdata->local->tx_headroom;
+ if (encrypt)
+ headroom += IEEE80211_ENCRYPT_HEADROOM;
+ headroom -= skb_headroom(skb);
+ headroom = max_t(int, 0, headroom);
+
+ if (ieee80211_skb_resize(osdata->local, skb, headroom, encrypt)) {
+ dev_kfree_skb(skb);
+ dev_put(odev);
+ return 0;
}
control.vif = &osdata->vif;
@@ -1556,32 +1601,26 @@ int ieee80211_subif_start_xmit(struct sk
* build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
* alloc_skb() (net/core/skbuff.c)
*/
- head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom;
- head_need -= skb_headroom(skb);
+ head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
- /* We are going to modify skb data, so make a copy of it if happens to
- * be cloned. This could happen, e.g., with Linux bridge code passing
- * us broadcast frames. */
+ /*
+ * So we need to modify the skb header and hence need a copy of
+ * that. The head_need variable above doesn't, so far, include
+ * the needed header space that we don't need right away. If we
+ * can, then we don't reallocate right now but only after the
+ * frame arrives at the master device (if it does...)
+ *
+ * If we cannot, however, then we will reallocate to include all
+ * the ever needed space and, if necessary, orphan the skb. Also,
+ * if the skb is cloned then copy only once.
+ */
if (head_need > 0 || skb_header_cloned(skb)) {
-#if 0
- printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes "
- "of headroom\n", dev->name, head_need);
-#endif
-
- if (skb_header_cloned(skb))
- I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
- else
- I802_DEBUG_INC(local->tx_expand_skb_head);
- /* Since we have to reallocate the buffer, make sure that there
- * is enough room for possible WEP IV/ICV and TKIP (8 bytes
- * before payload and 12 after). */
- if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8),
- 12, GFP_ATOMIC)) {
- printk(KERN_DEBUG "%s: failed to reallocate TX buffer"
- "\n", dev->name);
+ head_need += IEEE80211_ENCRYPT_HEADROOM;
+ head_need += local->tx_headroom;
+ head_need = max_t(int, 0, head_need);
+ if (ieee80211_skb_resize(local, skb, head_need, 1))
goto fail;
- }
}
if (encaps_data) {
--- everything.orig/net/mac80211/wep.c 2008-05-10 23:00:03.000000000 +0200
+++ everything/net/mac80211/wep.c 2008-05-10 23:05:44.000000000 +0200
@@ -93,13 +93,9 @@ static u8 *ieee80211_wep_add_iv(struct i
fc |= IEEE80211_FCTL_PROTECTED;
hdr->frame_control = cpu_to_le16(fc);
- if ((skb_headroom(skb) < WEP_IV_LEN ||
- skb_tailroom(skb) < WEP_ICV_LEN)) {
- I802_DEBUG_INC(local->tx_expand_skb_head);
- if (unlikely(pskb_expand_head(skb, WEP_IV_LEN, WEP_ICV_LEN,
- GFP_ATOMIC)))
- return NULL;
- }
+ if (WARN_ON(skb_tailroom(skb) < WEP_ICV_LEN ||
+ skb_headroom(skb) < WEP_IV_LEN))
+ return NULL;
hdrlen = ieee80211_get_hdrlen(fc);
newhdr = skb_push(skb, WEP_IV_LEN);
--- everything.orig/net/mac80211/wpa.c 2008-05-10 23:00:03.000000000 +0200
+++ everything/net/mac80211/wpa.c 2008-05-10 23:05:44.000000000 +0200
@@ -79,6 +79,7 @@ ieee80211_tx_h_michael_mic_add(struct ie
struct sk_buff *skb = tx->skb;
int authenticator;
int wpa_test = 0;
+ int tail;
fc = tx->fc;
@@ -98,16 +99,13 @@ ieee80211_tx_h_michael_mic_add(struct ie
return TX_CONTINUE;
}
- if (skb_tailroom(skb) < MICHAEL_MIC_LEN) {
- I802_DEBUG_INC(tx->local->tx_expand_skb_head);
- if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN,
- MICHAEL_MIC_LEN + TKIP_ICV_LEN,
- GFP_ATOMIC))) {
- printk(KERN_DEBUG "%s: failed to allocate more memory "
- "for Michael MIC\n", tx->dev->name);
- return TX_DROP;
- }
- }
+ tail = MICHAEL_MIC_LEN;
+ if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+ tail += TKIP_ICV_LEN;
+
+ if (WARN_ON(skb_tailroom(skb) < tail ||
+ skb_headroom(skb) < TKIP_IV_LEN))
+ return TX_DROP;
#if 0
authenticator = fc & IEEE80211_FCTL_FROMDS; /* FIX */
@@ -188,7 +186,7 @@ static int tkip_encrypt_skb(struct ieee8
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_key *key = tx->key;
- int hdrlen, len, tailneed;
+ int hdrlen, len, tail;
u16 fc;
u8 *pos;
@@ -197,17 +195,13 @@ static int tkip_encrypt_skb(struct ieee8
len = skb->len - hdrlen;
if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
- tailneed = 0;
+ tail = 0;
else
- tailneed = TKIP_ICV_LEN;
+ tail = TKIP_ICV_LEN;
- if ((skb_headroom(skb) < TKIP_IV_LEN ||
- skb_tailroom(skb) < tailneed)) {
- I802_DEBUG_INC(tx->local->tx_expand_skb_head);
- if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN, tailneed,
- GFP_ATOMIC)))
- return -1;
- }
+ if (WARN_ON(skb_tailroom(skb) < tail ||
+ skb_headroom(skb) < TKIP_IV_LEN))
+ return TX_DROP;
pos = skb_push(skb, TKIP_IV_LEN);
memmove(pos, pos + TKIP_IV_LEN, hdrlen);
@@ -434,7 +428,7 @@ static int ccmp_encrypt_skb(struct ieee8
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_key *key = tx->key;
- int hdrlen, len, tailneed;
+ int hdrlen, len, tail;
u16 fc;
u8 *pos, *pn, *b_0, *aad, *scratch;
int i;
@@ -448,17 +442,13 @@ static int ccmp_encrypt_skb(struct ieee8
len = skb->len - hdrlen;
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
- tailneed = 0;
+ tail = 0;
else
- tailneed = CCMP_MIC_LEN;
+ tail = CCMP_MIC_LEN;
- if ((skb_headroom(skb) < CCMP_HDR_LEN ||
- skb_tailroom(skb) < tailneed)) {
- I802_DEBUG_INC(tx->local->tx_expand_skb_head);
- if (unlikely(pskb_expand_head(skb, CCMP_HDR_LEN, tailneed,
- GFP_ATOMIC)))
- return -1;
- }
+ if (WARN_ON(skb_tailroom(skb) < tail ||
+ skb_headroom(skb) < CCMP_HDR_LEN))
+ return TX_DROP;
pos = skb_push(skb, CCMP_HDR_LEN);
memmove(pos, pos + CCMP_HDR_LEN, hdrlen);
--
next prev parent reply other threads:[~2008-05-10 22:22 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-05-10 22:18 [RFT/C 0/7] various mac80211 updates/bugfixes Johannes Berg
2008-05-10 22:18 ` [RFT/C 1/7] mac80211: use skb_header_cloned() Johannes Berg
2008-05-12 9:09 ` David Miller
2008-05-10 22:18 ` Johannes Berg [this message]
2008-05-12 9:09 ` [RFT/C 2/7] mac80211: clean up skb reallocation code David Miller
2008-05-13 8:39 ` Johannes Berg
2008-05-13 8:39 ` David Miller
2008-05-10 22:18 ` [RFT/C 3/7] mac80211: fix bugs in queue handling functions Johannes Berg
2008-05-10 22:18 ` [RFT/C 4/7] mac80211: let drivers wake but not start queues Johannes Berg
2008-05-12 9:10 ` David Miller
2008-05-10 22:18 ` [RFT/C 5/7] mac80211: use rate index in TX control Johannes Berg
2008-05-10 22:18 ` [RFT/C 6/7] mac80211: reorder some transmit handlers Johannes Berg
2008-05-10 22:18 ` [RFT/C 7/7] mac80211: move TX info into skb->cb Johannes Berg
2008-05-12 9:11 ` David Miller
2008-05-12 12:26 ` Ivo van Doorn
2008-05-13 8:40 ` Johannes Berg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080510221906.261962000@sipsolutions.net \
--to=johannes@sipsolutions.net \
--cc=linux-wireless@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.