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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).