aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-05-29 04:38:53 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-06-03 15:00:14 -0400
commit23c0752a25d73ccc4547700e8a57d5ae2f2edf56 (patch)
tree225631645bf52c07931adc7aeb766344b05be7eb
parentf622360bce6facb05fdce4bce5ee4beb2432222d (diff)
mac80211: clean up skb reallocation code
This cleans up the skb reallocation code to avoid problems with skb->truesize, not resize an skb twice for a single output path because we didn't expand it enough during the first copy and also removes the code to further expand it during crypto operations which will no longer be necessary. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--net/mac80211/tx.c97
-rw-r--r--net/mac80211/wep.c10
-rw-r--r--net/mac80211/wpa.c58
3 files changed, 95 insertions, 70 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index baa1be0671e5..dac44cbd036f 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1215,6 +1215,45 @@ retry:
1215 1215
1216/* device xmit handlers */ 1216/* device xmit handlers */
1217 1217
1218static int ieee80211_skb_resize(struct ieee80211_local *local,
1219 struct sk_buff *skb,
1220 int head_need, bool may_encrypt)
1221{
1222 int tail_need = 0;
1223
1224 /*
1225 * This could be optimised, devices that do full hardware
1226 * crypto (including TKIP MMIC) need no tailroom... But we
1227 * have no drivers for such devices currently.
1228 */
1229 if (may_encrypt) {
1230 tail_need = IEEE80211_ENCRYPT_TAILROOM;
1231 tail_need -= skb_tailroom(skb);
1232 tail_need = max_t(int, tail_need, 0);
1233 }
1234
1235 if (head_need || tail_need) {
1236 /* Sorry. Can't account for this any more */
1237 skb_orphan(skb);
1238 }
1239
1240 if (skb_header_cloned(skb))
1241 I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
1242 else
1243 I802_DEBUG_INC(local->tx_expand_skb_head);
1244
1245 if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) {
1246 printk(KERN_DEBUG "%s: failed to reallocate TX buffer\n",
1247 wiphy_name(local->hw.wiphy));
1248 return -ENOMEM;
1249 }
1250
1251 /* update truesize too */
1252 skb->truesize += head_need + tail_need;
1253
1254 return 0;
1255}
1256
1218int ieee80211_master_start_xmit(struct sk_buff *skb, 1257int ieee80211_master_start_xmit(struct sk_buff *skb,
1219 struct net_device *dev) 1258 struct net_device *dev)
1220{ 1259{
@@ -1222,6 +1261,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
1222 struct net_device *odev = NULL; 1261 struct net_device *odev = NULL;
1223 struct ieee80211_sub_if_data *osdata; 1262 struct ieee80211_sub_if_data *osdata;
1224 int headroom; 1263 int headroom;
1264 bool may_encrypt;
1225 int ret; 1265 int ret;
1226 1266
1227 if (info->control.ifindex) 1267 if (info->control.ifindex)
@@ -1241,13 +1281,18 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
1241 1281
1242 osdata = IEEE80211_DEV_TO_SUB_IF(odev); 1282 osdata = IEEE80211_DEV_TO_SUB_IF(odev);
1243 1283
1244 headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM; 1284 may_encrypt = !(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT);
1245 if (skb_headroom(skb) < headroom) { 1285
1246 if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { 1286 headroom = osdata->local->tx_headroom;
1247 dev_kfree_skb(skb); 1287 if (may_encrypt)
1248 dev_put(odev); 1288 headroom += IEEE80211_ENCRYPT_HEADROOM;
1249 return 0; 1289 headroom -= skb_headroom(skb);
1250 } 1290 headroom = max_t(int, 0, headroom);
1291
1292 if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) {
1293 dev_kfree_skb(skb);
1294 dev_put(odev);
1295 return 0;
1251 } 1296 }
1252 1297
1253 info->control.vif = &osdata->vif; 1298 info->control.vif = &osdata->vif;
@@ -1509,32 +1554,26 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
1509 * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and 1554 * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
1510 * alloc_skb() (net/core/skbuff.c) 1555 * alloc_skb() (net/core/skbuff.c)
1511 */ 1556 */
1512 head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom; 1557 head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
1513 head_need -= skb_headroom(skb);
1514 1558
1515 /* We are going to modify skb data, so make a copy of it if happens to 1559 /*
1516 * be cloned. This could happen, e.g., with Linux bridge code passing 1560 * So we need to modify the skb header and hence need a copy of
1517 * us broadcast frames. */ 1561 * that. The head_need variable above doesn't, so far, include
1562 * the needed header space that we don't need right away. If we
1563 * can, then we don't reallocate right now but only after the
1564 * frame arrives at the master device (if it does...)
1565 *
1566 * If we cannot, however, then we will reallocate to include all
1567 * the ever needed space. Also, if we need to reallocate it anyway,
1568 * make it big enough for everything we may ever need.
1569 */
1518 1570
1519 if (head_need > 0 || skb_header_cloned(skb)) { 1571 if (head_need > 0 || skb_header_cloned(skb)) {
1520#if 0 1572 head_need += IEEE80211_ENCRYPT_HEADROOM;
1521 printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes " 1573 head_need += local->tx_headroom;
1522 "of headroom\n", dev->name, head_need); 1574 head_need = max_t(int, 0, head_need);
1523#endif 1575 if (ieee80211_skb_resize(local, skb, head_need, true))
1524
1525 if (skb_header_cloned(skb))
1526 I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
1527 else
1528 I802_DEBUG_INC(local->tx_expand_skb_head);
1529 /* Since we have to reallocate the buffer, make sure that there
1530 * is enough room for possible WEP IV/ICV and TKIP (8 bytes
1531 * before payload and 12 after). */
1532 if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8),
1533 12, GFP_ATOMIC)) {
1534 printk(KERN_DEBUG "%s: failed to reallocate TX buffer"
1535 "\n", dev->name);
1536 goto fail; 1576 goto fail;
1537 }
1538 } 1577 }
1539 1578
1540 if (encaps_data) { 1579 if (encaps_data) {
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index 1e7f03dd8f6b..c9fd1291b19d 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -93,13 +93,9 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
93 fc |= IEEE80211_FCTL_PROTECTED; 93 fc |= IEEE80211_FCTL_PROTECTED;
94 hdr->frame_control = cpu_to_le16(fc); 94 hdr->frame_control = cpu_to_le16(fc);
95 95
96 if ((skb_headroom(skb) < WEP_IV_LEN || 96 if (WARN_ON(skb_tailroom(skb) < WEP_ICV_LEN ||
97 skb_tailroom(skb) < WEP_ICV_LEN)) { 97 skb_headroom(skb) < WEP_IV_LEN))
98 I802_DEBUG_INC(local->tx_expand_skb_head); 98 return NULL;
99 if (unlikely(pskb_expand_head(skb, WEP_IV_LEN, WEP_ICV_LEN,
100 GFP_ATOMIC)))
101 return NULL;
102 }
103 99
104 hdrlen = ieee80211_get_hdrlen(fc); 100 hdrlen = ieee80211_get_hdrlen(fc);
105 newhdr = skb_push(skb, WEP_IV_LEN); 101 newhdr = skb_push(skb, WEP_IV_LEN);
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index d6635f6e5618..9f6fd20374e1 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -79,6 +79,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
79 struct sk_buff *skb = tx->skb; 79 struct sk_buff *skb = tx->skb;
80 int authenticator; 80 int authenticator;
81 int wpa_test = 0; 81 int wpa_test = 0;
82 int tail;
82 83
83 fc = tx->fc; 84 fc = tx->fc;
84 85
@@ -98,16 +99,13 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
98 return TX_CONTINUE; 99 return TX_CONTINUE;
99 } 100 }
100 101
101 if (skb_tailroom(skb) < MICHAEL_MIC_LEN) { 102 tail = MICHAEL_MIC_LEN;
102 I802_DEBUG_INC(tx->local->tx_expand_skb_head); 103 if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
103 if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN, 104 tail += TKIP_ICV_LEN;
104 MICHAEL_MIC_LEN + TKIP_ICV_LEN, 105
105 GFP_ATOMIC))) { 106 if (WARN_ON(skb_tailroom(skb) < tail ||
106 printk(KERN_DEBUG "%s: failed to allocate more memory " 107 skb_headroom(skb) < TKIP_IV_LEN))
107 "for Michael MIC\n", tx->dev->name); 108 return TX_DROP;
108 return TX_DROP;
109 }
110 }
111 109
112#if 0 110#if 0
113 authenticator = fc & IEEE80211_FCTL_FROMDS; /* FIX */ 111 authenticator = fc & IEEE80211_FCTL_FROMDS; /* FIX */
@@ -188,7 +186,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
188 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 186 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
189 struct ieee80211_key *key = tx->key; 187 struct ieee80211_key *key = tx->key;
190 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 188 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
191 int hdrlen, len, tailneed; 189 int hdrlen, len, tail;
192 u16 fc; 190 u16 fc;
193 u8 *pos; 191 u8 *pos;
194 192
@@ -199,7 +197,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
199 !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { 197 !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
200 /* hwaccel - with no need for preallocated room for IV/ICV */ 198 /* hwaccel - with no need for preallocated room for IV/ICV */
201 info->control.hw_key = &tx->key->conf; 199 info->control.hw_key = &tx->key->conf;
202 return TX_CONTINUE; 200 return 0;
203 } 201 }
204 202
205 fc = le16_to_cpu(hdr->frame_control); 203 fc = le16_to_cpu(hdr->frame_control);
@@ -207,17 +205,13 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
207 len = skb->len - hdrlen; 205 len = skb->len - hdrlen;
208 206
209 if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) 207 if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
210 tailneed = 0; 208 tail = 0;
211 else 209 else
212 tailneed = TKIP_ICV_LEN; 210 tail = TKIP_ICV_LEN;
213 211
214 if ((skb_headroom(skb) < TKIP_IV_LEN || 212 if (WARN_ON(skb_tailroom(skb) < tail ||
215 skb_tailroom(skb) < tailneed)) { 213 skb_headroom(skb) < TKIP_IV_LEN))
216 I802_DEBUG_INC(tx->local->tx_expand_skb_head); 214 return -1;
217 if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN, tailneed,
218 GFP_ATOMIC)))
219 return -1;
220 }
221 215
222 pos = skb_push(skb, TKIP_IV_LEN); 216 pos = skb_push(skb, TKIP_IV_LEN);
223 memmove(pos, pos + TKIP_IV_LEN, hdrlen); 217 memmove(pos, pos + TKIP_IV_LEN, hdrlen);
@@ -432,7 +426,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
432 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 426 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
433 struct ieee80211_key *key = tx->key; 427 struct ieee80211_key *key = tx->key;
434 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 428 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
435 int hdrlen, len, tailneed; 429 int hdrlen, len, tail;
436 u16 fc; 430 u16 fc;
437 u8 *pos, *pn, *b_0, *aad, *scratch; 431 u8 *pos, *pn, *b_0, *aad, *scratch;
438 int i; 432 int i;
@@ -445,7 +439,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
445 /* hwaccel - with no need for preallocated room for CCMP " 439 /* hwaccel - with no need for preallocated room for CCMP "
446 * header or MIC fields */ 440 * header or MIC fields */
447 info->control.hw_key = &tx->key->conf; 441 info->control.hw_key = &tx->key->conf;
448 return TX_CONTINUE; 442 return 0;
449 } 443 }
450 444
451 scratch = key->u.ccmp.tx_crypto_buf; 445 scratch = key->u.ccmp.tx_crypto_buf;
@@ -457,17 +451,13 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
457 len = skb->len - hdrlen; 451 len = skb->len - hdrlen;
458 452
459 if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) 453 if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
460 tailneed = 0; 454 tail = 0;
461 else 455 else
462 tailneed = CCMP_MIC_LEN; 456 tail = CCMP_MIC_LEN;
463 457
464 if ((skb_headroom(skb) < CCMP_HDR_LEN || 458 if (WARN_ON(skb_tailroom(skb) < tail ||
465 skb_tailroom(skb) < tailneed)) { 459 skb_headroom(skb) < CCMP_HDR_LEN))
466 I802_DEBUG_INC(tx->local->tx_expand_skb_head); 460 return -1;
467 if (unlikely(pskb_expand_head(skb, CCMP_HDR_LEN, tailneed,
468 GFP_ATOMIC)))
469 return -1;
470 }
471 461
472 pos = skb_push(skb, CCMP_HDR_LEN); 462 pos = skb_push(skb, CCMP_HDR_LEN);
473 memmove(pos, pos + CCMP_HDR_LEN, hdrlen); 463 memmove(pos, pos + CCMP_HDR_LEN, hdrlen);