diff options
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/key.c | 51 | ||||
-rw-r--r-- | net/mac80211/tx.c | 14 |
3 files changed, 57 insertions, 11 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 25c15cc63319..4f2e424e8b1b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -544,6 +544,9 @@ struct ieee80211_sub_if_data { | |||
544 | /* keys */ | 544 | /* keys */ |
545 | struct list_head key_list; | 545 | struct list_head key_list; |
546 | 546 | ||
547 | /* count for keys needing tailroom space allocation */ | ||
548 | int crypto_tx_tailroom_needed_cnt; | ||
549 | |||
547 | struct net_device *dev; | 550 | struct net_device *dev; |
548 | struct ieee80211_local *local; | 551 | struct ieee80211_local *local; |
549 | 552 | ||
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index f825e2f0a57e..0af958c74342 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -61,6 +61,36 @@ static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key) | |||
61 | return NULL; | 61 | return NULL; |
62 | } | 62 | } |
63 | 63 | ||
64 | static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata) | ||
65 | { | ||
66 | /* | ||
67 | * When this count is zero, SKB resizing for allocating tailroom | ||
68 | * for IV or MMIC is skipped. But, this check has created two race | ||
69 | * cases in xmit path while transiting from zero count to one: | ||
70 | * | ||
71 | * 1. SKB resize was skipped because no key was added but just before | ||
72 | * the xmit key is added and SW encryption kicks off. | ||
73 | * | ||
74 | * 2. SKB resize was skipped because all the keys were hw planted but | ||
75 | * just before xmit one of the key is deleted and SW encryption kicks | ||
76 | * off. | ||
77 | * | ||
78 | * In both the above case SW encryption will find not enough space for | ||
79 | * tailroom and exits with WARN_ON. (See WARN_ONs at wpa.c) | ||
80 | * | ||
81 | * Solution has been explained at | ||
82 | * http://mid.gmane.org/1308590980.4322.19.camel@jlt3.sipsolutions.net | ||
83 | */ | ||
84 | |||
85 | if (!sdata->crypto_tx_tailroom_needed_cnt++) { | ||
86 | /* | ||
87 | * Flush all XMIT packets currently using HW encryption or no | ||
88 | * encryption at all if the count transition is from 0 -> 1. | ||
89 | */ | ||
90 | synchronize_net(); | ||
91 | } | ||
92 | } | ||
93 | |||
64 | static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | 94 | static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) |
65 | { | 95 | { |
66 | struct ieee80211_sub_if_data *sdata; | 96 | struct ieee80211_sub_if_data *sdata; |
@@ -101,6 +131,11 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
101 | 131 | ||
102 | if (!ret) { | 132 | if (!ret) { |
103 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; | 133 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; |
134 | |||
135 | if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || | ||
136 | (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))) | ||
137 | sdata->crypto_tx_tailroom_needed_cnt--; | ||
138 | |||
104 | return 0; | 139 | return 0; |
105 | } | 140 | } |
106 | 141 | ||
@@ -142,6 +177,10 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
142 | sta = get_sta_for_key(key); | 177 | sta = get_sta_for_key(key); |
143 | sdata = key->sdata; | 178 | sdata = key->sdata; |
144 | 179 | ||
180 | if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || | ||
181 | (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))) | ||
182 | increment_tailroom_need_count(sdata); | ||
183 | |||
145 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 184 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
146 | sdata = container_of(sdata->bss, | 185 | sdata = container_of(sdata->bss, |
147 | struct ieee80211_sub_if_data, | 186 | struct ieee80211_sub_if_data, |
@@ -394,8 +433,10 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) | |||
394 | ieee80211_aes_key_free(key->u.ccmp.tfm); | 433 | ieee80211_aes_key_free(key->u.ccmp.tfm); |
395 | if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) | 434 | if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) |
396 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); | 435 | ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); |
397 | if (key->local) | 436 | if (key->local) { |
398 | ieee80211_debugfs_key_remove(key); | 437 | ieee80211_debugfs_key_remove(key); |
438 | key->sdata->crypto_tx_tailroom_needed_cnt--; | ||
439 | } | ||
399 | 440 | ||
400 | kfree(key); | 441 | kfree(key); |
401 | } | 442 | } |
@@ -452,6 +493,8 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
452 | else | 493 | else |
453 | old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); | 494 | old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
454 | 495 | ||
496 | increment_tailroom_need_count(sdata); | ||
497 | |||
455 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); | 498 | __ieee80211_key_replace(sdata, sta, pairwise, old_key, key); |
456 | __ieee80211_key_destroy(old_key); | 499 | __ieee80211_key_destroy(old_key); |
457 | 500 | ||
@@ -498,8 +541,12 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) | |||
498 | 541 | ||
499 | mutex_lock(&sdata->local->key_mtx); | 542 | mutex_lock(&sdata->local->key_mtx); |
500 | 543 | ||
501 | list_for_each_entry(key, &sdata->key_list, list) | 544 | sdata->crypto_tx_tailroom_needed_cnt = 0; |
545 | |||
546 | list_for_each_entry(key, &sdata->key_list, list) { | ||
547 | increment_tailroom_need_count(sdata); | ||
502 | ieee80211_key_enable_hw_accel(key); | 548 | ieee80211_key_enable_hw_accel(key); |
549 | } | ||
503 | 550 | ||
504 | mutex_unlock(&sdata->local->key_mtx); | 551 | mutex_unlock(&sdata->local->key_mtx); |
505 | } | 552 | } |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3104c844b544..e8d0d2d22665 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1474,18 +1474,14 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
1474 | 1474 | ||
1475 | /* device xmit handlers */ | 1475 | /* device xmit handlers */ |
1476 | 1476 | ||
1477 | static int ieee80211_skb_resize(struct ieee80211_local *local, | 1477 | static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, |
1478 | struct sk_buff *skb, | 1478 | struct sk_buff *skb, |
1479 | int head_need, bool may_encrypt) | 1479 | int head_need, bool may_encrypt) |
1480 | { | 1480 | { |
1481 | struct ieee80211_local *local = sdata->local; | ||
1481 | int tail_need = 0; | 1482 | int tail_need = 0; |
1482 | 1483 | ||
1483 | /* | 1484 | if (may_encrypt && sdata->crypto_tx_tailroom_needed_cnt) { |
1484 | * This could be optimised, devices that do full hardware | ||
1485 | * crypto (including TKIP MMIC) need no tailroom... But we | ||
1486 | * have no drivers for such devices currently. | ||
1487 | */ | ||
1488 | if (may_encrypt) { | ||
1489 | tail_need = IEEE80211_ENCRYPT_TAILROOM; | 1485 | tail_need = IEEE80211_ENCRYPT_TAILROOM; |
1490 | tail_need -= skb_tailroom(skb); | 1486 | tail_need -= skb_tailroom(skb); |
1491 | tail_need = max_t(int, tail_need, 0); | 1487 | tail_need = max_t(int, tail_need, 0); |
@@ -1578,7 +1574,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
1578 | headroom -= skb_headroom(skb); | 1574 | headroom -= skb_headroom(skb); |
1579 | headroom = max_t(int, 0, headroom); | 1575 | headroom = max_t(int, 0, headroom); |
1580 | 1576 | ||
1581 | if (ieee80211_skb_resize(local, skb, headroom, may_encrypt)) { | 1577 | if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) { |
1582 | dev_kfree_skb(skb); | 1578 | dev_kfree_skb(skb); |
1583 | rcu_read_unlock(); | 1579 | rcu_read_unlock(); |
1584 | return; | 1580 | return; |
@@ -1945,7 +1941,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1945 | head_need += IEEE80211_ENCRYPT_HEADROOM; | 1941 | head_need += IEEE80211_ENCRYPT_HEADROOM; |
1946 | head_need += local->tx_headroom; | 1942 | head_need += local->tx_headroom; |
1947 | head_need = max_t(int, 0, head_need); | 1943 | head_need = max_t(int, 0, head_need); |
1948 | if (ieee80211_skb_resize(local, skb, head_need, true)) | 1944 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) |
1949 | goto fail; | 1945 | goto fail; |
1950 | } | 1946 | } |
1951 | 1947 | ||