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@xxxxxxxxxxxxxxxx> --- 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); -- -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html