diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-11-16 09:28:55 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-21 16:20:42 -0500 |
commit | 252b86c43225d067468dd182e9ae616ad2532bc8 (patch) | |
tree | d584ef11ebd143960c1890e361a89653fb9812c9 /net | |
parent | 83c76570961573e56a238d84ba18f2581ef1e6b5 (diff) |
mac80211: use skb list for fragments
We are currently linking the skbs by using skb->next
directly. This works, but the preferred way is to use
a struct sk_buff_head instead. That also prepares for
passing that to drivers directly.
While at it I noticed we calculate the duration for
fragments twice -- remove one of them.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/tx.c | 116 | ||||
-rw-r--r-- | net/mac80211/util.c | 6 | ||||
-rw-r--r-- | net/mac80211/wep.c | 5 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 25 |
5 files changed, 82 insertions, 71 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 068cc92d16aa..f2785056d8d9 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -142,6 +142,7 @@ typedef unsigned __bitwise__ ieee80211_tx_result; | |||
142 | 142 | ||
143 | struct ieee80211_tx_data { | 143 | struct ieee80211_tx_data { |
144 | struct sk_buff *skb; | 144 | struct sk_buff *skb; |
145 | struct sk_buff_head skbs; | ||
145 | struct ieee80211_local *local; | 146 | struct ieee80211_local *local; |
146 | struct ieee80211_sub_if_data *sdata; | 147 | struct ieee80211_sub_if_data *sdata; |
147 | struct sta_info *sta; | 148 | struct sta_info *sta; |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 431988361553..26a7cfb80b7c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -35,7 +35,8 @@ | |||
35 | 35 | ||
36 | /* misc utils */ | 36 | /* misc utils */ |
37 | 37 | ||
38 | static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, | 38 | static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, |
39 | struct sk_buff *skb, int group_addr, | ||
39 | int next_frag_len) | 40 | int next_frag_len) |
40 | { | 41 | { |
41 | int rate, mrate, erp, dur, i; | 42 | int rate, mrate, erp, dur, i; |
@@ -43,7 +44,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, | |||
43 | struct ieee80211_local *local = tx->local; | 44 | struct ieee80211_local *local = tx->local; |
44 | struct ieee80211_supported_band *sband; | 45 | struct ieee80211_supported_band *sband; |
45 | struct ieee80211_hdr *hdr; | 46 | struct ieee80211_hdr *hdr; |
46 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | 47 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
47 | 48 | ||
48 | /* assume HW handles this */ | 49 | /* assume HW handles this */ |
49 | if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) | 50 | if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) |
@@ -75,7 +76,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, | |||
75 | * at the highest possible rate belonging to the PHY rates in the | 76 | * at the highest possible rate belonging to the PHY rates in the |
76 | * BSSBasicRateSet | 77 | * BSSBasicRateSet |
77 | */ | 78 | */ |
78 | hdr = (struct ieee80211_hdr *)tx->skb->data; | 79 | hdr = (struct ieee80211_hdr *)skb->data; |
79 | if (ieee80211_is_ctl(hdr->frame_control)) { | 80 | if (ieee80211_is_ctl(hdr->frame_control)) { |
80 | /* TODO: These control frames are not currently sent by | 81 | /* TODO: These control frames are not currently sent by |
81 | * mac80211, but should they be implemented, this function | 82 | * mac80211, but should they be implemented, this function |
@@ -841,11 +842,12 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) | |||
841 | return TX_CONTINUE; | 842 | return TX_CONTINUE; |
842 | } | 843 | } |
843 | 844 | ||
844 | static int ieee80211_fragment(struct ieee80211_local *local, | 845 | static int ieee80211_fragment(struct ieee80211_tx_data *tx, |
845 | struct sk_buff *skb, int hdrlen, | 846 | struct sk_buff *skb, int hdrlen, |
846 | int frag_threshold) | 847 | int frag_threshold) |
847 | { | 848 | { |
848 | struct sk_buff *tail = skb, *tmp; | 849 | struct ieee80211_local *local = tx->local; |
850 | struct sk_buff *tmp; | ||
849 | int per_fragm = frag_threshold - hdrlen - FCS_LEN; | 851 | int per_fragm = frag_threshold - hdrlen - FCS_LEN; |
850 | int pos = hdrlen + per_fragm; | 852 | int pos = hdrlen + per_fragm; |
851 | int rem = skb->len - hdrlen - per_fragm; | 853 | int rem = skb->len - hdrlen - per_fragm; |
@@ -853,6 +855,8 @@ static int ieee80211_fragment(struct ieee80211_local *local, | |||
853 | if (WARN_ON(rem < 0)) | 855 | if (WARN_ON(rem < 0)) |
854 | return -EINVAL; | 856 | return -EINVAL; |
855 | 857 | ||
858 | /* first fragment was already added to queue by caller */ | ||
859 | |||
856 | while (rem) { | 860 | while (rem) { |
857 | int fraglen = per_fragm; | 861 | int fraglen = per_fragm; |
858 | 862 | ||
@@ -865,8 +869,9 @@ static int ieee80211_fragment(struct ieee80211_local *local, | |||
865 | IEEE80211_ENCRYPT_TAILROOM); | 869 | IEEE80211_ENCRYPT_TAILROOM); |
866 | if (!tmp) | 870 | if (!tmp) |
867 | return -ENOMEM; | 871 | return -ENOMEM; |
868 | tail->next = tmp; | 872 | |
869 | tail = tmp; | 873 | __skb_queue_tail(&tx->skbs, tmp); |
874 | |||
870 | skb_reserve(tmp, local->tx_headroom + | 875 | skb_reserve(tmp, local->tx_headroom + |
871 | IEEE80211_ENCRYPT_HEADROOM); | 876 | IEEE80211_ENCRYPT_HEADROOM); |
872 | /* copy control information */ | 877 | /* copy control information */ |
@@ -882,6 +887,7 @@ static int ieee80211_fragment(struct ieee80211_local *local, | |||
882 | pos += fraglen; | 887 | pos += fraglen; |
883 | } | 888 | } |
884 | 889 | ||
890 | /* adjust first fragment's length */ | ||
885 | skb->len = hdrlen + per_fragm; | 891 | skb->len = hdrlen + per_fragm; |
886 | return 0; | 892 | return 0; |
887 | } | 893 | } |
@@ -896,6 +902,10 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
896 | int hdrlen; | 902 | int hdrlen; |
897 | int fragnum; | 903 | int fragnum; |
898 | 904 | ||
905 | /* no matter what happens, tx->skb moves to tx->skbs */ | ||
906 | __skb_queue_tail(&tx->skbs, skb); | ||
907 | tx->skb = NULL; | ||
908 | |||
899 | if (info->flags & IEEE80211_TX_CTL_DONTFRAG) | 909 | if (info->flags & IEEE80211_TX_CTL_DONTFRAG) |
900 | return TX_CONTINUE; | 910 | return TX_CONTINUE; |
901 | 911 | ||
@@ -924,21 +934,21 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
924 | * of the fragments then we will simply pretend to accept the skb | 934 | * of the fragments then we will simply pretend to accept the skb |
925 | * but store it away as pending. | 935 | * but store it away as pending. |
926 | */ | 936 | */ |
927 | if (ieee80211_fragment(tx->local, skb, hdrlen, frag_threshold)) | 937 | if (ieee80211_fragment(tx, skb, hdrlen, frag_threshold)) |
928 | return TX_DROP; | 938 | return TX_DROP; |
929 | 939 | ||
930 | /* update duration/seq/flags of fragments */ | 940 | /* update duration/seq/flags of fragments */ |
931 | fragnum = 0; | 941 | fragnum = 0; |
932 | do { | 942 | |
943 | skb_queue_walk(&tx->skbs, skb) { | ||
933 | int next_len; | 944 | int next_len; |
934 | const __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); | 945 | const __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); |
935 | 946 | ||
936 | hdr = (void *)skb->data; | 947 | hdr = (void *)skb->data; |
937 | info = IEEE80211_SKB_CB(skb); | 948 | info = IEEE80211_SKB_CB(skb); |
938 | 949 | ||
939 | if (skb->next) { | 950 | if (!skb_queue_is_last(&tx->skbs, skb)) { |
940 | hdr->frame_control |= morefrags; | 951 | hdr->frame_control |= morefrags; |
941 | next_len = skb->next->len; | ||
942 | /* | 952 | /* |
943 | * No multi-rate retries for fragmented frames, that | 953 | * No multi-rate retries for fragmented frames, that |
944 | * would completely throw off the NAV at other STAs. | 954 | * would completely throw off the NAV at other STAs. |
@@ -953,10 +963,9 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
953 | hdr->frame_control &= ~morefrags; | 963 | hdr->frame_control &= ~morefrags; |
954 | next_len = 0; | 964 | next_len = 0; |
955 | } | 965 | } |
956 | hdr->duration_id = ieee80211_duration(tx, 0, next_len); | ||
957 | hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG); | 966 | hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG); |
958 | fragnum++; | 967 | fragnum++; |
959 | } while ((skb = skb->next)); | 968 | } |
960 | 969 | ||
961 | return TX_CONTINUE; | 970 | return TX_CONTINUE; |
962 | } | 971 | } |
@@ -964,16 +973,16 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
964 | static ieee80211_tx_result debug_noinline | 973 | static ieee80211_tx_result debug_noinline |
965 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | 974 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) |
966 | { | 975 | { |
967 | struct sk_buff *skb = tx->skb; | 976 | struct sk_buff *skb; |
968 | 977 | ||
969 | if (!tx->sta) | 978 | if (!tx->sta) |
970 | return TX_CONTINUE; | 979 | return TX_CONTINUE; |
971 | 980 | ||
972 | tx->sta->tx_packets++; | 981 | tx->sta->tx_packets++; |
973 | do { | 982 | skb_queue_walk(&tx->skbs, skb) { |
974 | tx->sta->tx_fragments++; | 983 | tx->sta->tx_fragments++; |
975 | tx->sta->tx_bytes += skb->len; | 984 | tx->sta->tx_bytes += skb->len; |
976 | } while ((skb = skb->next)); | 985 | } |
977 | 986 | ||
978 | return TX_CONTINUE; | 987 | return TX_CONTINUE; |
979 | } | 988 | } |
@@ -1012,21 +1021,25 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | |||
1012 | static ieee80211_tx_result debug_noinline | 1021 | static ieee80211_tx_result debug_noinline |
1013 | ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) | 1022 | ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) |
1014 | { | 1023 | { |
1015 | struct sk_buff *skb = tx->skb; | 1024 | struct sk_buff *skb; |
1016 | struct ieee80211_hdr *hdr; | 1025 | struct ieee80211_hdr *hdr; |
1017 | int next_len; | 1026 | int next_len; |
1018 | bool group_addr; | 1027 | bool group_addr; |
1019 | 1028 | ||
1020 | do { | 1029 | skb_queue_walk(&tx->skbs, skb) { |
1021 | hdr = (void *) skb->data; | 1030 | hdr = (void *) skb->data; |
1022 | if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) | 1031 | if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) |
1023 | break; /* must not overwrite AID */ | 1032 | break; /* must not overwrite AID */ |
1024 | next_len = skb->next ? skb->next->len : 0; | 1033 | if (!skb_queue_is_last(&tx->skbs, skb)) { |
1034 | struct sk_buff *next = skb_queue_next(&tx->skbs, skb); | ||
1035 | next_len = next->len; | ||
1036 | } else | ||
1037 | next_len = 0; | ||
1025 | group_addr = is_multicast_ether_addr(hdr->addr1); | 1038 | group_addr = is_multicast_ether_addr(hdr->addr1); |
1026 | 1039 | ||
1027 | hdr->duration_id = | 1040 | hdr->duration_id = |
1028 | ieee80211_duration(tx, group_addr, next_len); | 1041 | ieee80211_duration(tx, skb, group_addr, next_len); |
1029 | } while ((skb = skb->next)); | 1042 | } |
1030 | 1043 | ||
1031 | return TX_CONTINUE; | 1044 | return TX_CONTINUE; |
1032 | } | 1045 | } |
@@ -1105,6 +1118,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1105 | tx->local = local; | 1118 | tx->local = local; |
1106 | tx->sdata = sdata; | 1119 | tx->sdata = sdata; |
1107 | tx->channel = local->hw.conf.channel; | 1120 | tx->channel = local->hw.conf.channel; |
1121 | __skb_queue_head_init(&tx->skbs); | ||
1108 | 1122 | ||
1109 | /* | 1123 | /* |
1110 | * If this flag is set to true anywhere, and we get here, | 1124 | * If this flag is set to true anywhere, and we get here, |
@@ -1180,17 +1194,18 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1180 | /* | 1194 | /* |
1181 | * Returns false if the frame couldn't be transmitted but was queued instead. | 1195 | * Returns false if the frame couldn't be transmitted but was queued instead. |
1182 | */ | 1196 | */ |
1183 | static bool __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp, | 1197 | static bool __ieee80211_tx(struct ieee80211_local *local, |
1198 | struct sk_buff_head *skbs, | ||
1184 | struct sta_info *sta, bool txpending) | 1199 | struct sta_info *sta, bool txpending) |
1185 | { | 1200 | { |
1186 | struct sk_buff *skb = *skbp, *next; | 1201 | struct sk_buff *skb, *tmp; |
1187 | struct ieee80211_tx_info *info; | 1202 | struct ieee80211_tx_info *info; |
1188 | struct ieee80211_sub_if_data *sdata; | 1203 | struct ieee80211_sub_if_data *sdata; |
1189 | unsigned long flags; | 1204 | unsigned long flags; |
1190 | int len; | 1205 | int len; |
1191 | bool fragm = false; | 1206 | bool fragm = false; |
1192 | 1207 | ||
1193 | while (skb) { | 1208 | skb_queue_walk_safe(skbs, skb, tmp) { |
1194 | int q = skb_get_queue_mapping(skb); | 1209 | int q = skb_get_queue_mapping(skb); |
1195 | __le16 fc; | 1210 | __le16 fc; |
1196 | 1211 | ||
@@ -1202,24 +1217,10 @@ static bool __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp, | |||
1202 | * transmission from the tx-pending tasklet when the | 1217 | * transmission from the tx-pending tasklet when the |
1203 | * queue is woken again. | 1218 | * queue is woken again. |
1204 | */ | 1219 | */ |
1205 | 1220 | if (txpending) | |
1206 | do { | 1221 | skb_queue_splice(skbs, &local->pending[q]); |
1207 | next = skb->next; | 1222 | else |
1208 | skb->next = NULL; | 1223 | skb_queue_splice_tail(skbs, &local->pending[q]); |
1209 | /* | ||
1210 | * NB: If txpending is true, next must already | ||
1211 | * be NULL since we must've gone through this | ||
1212 | * loop before already; therefore we can just | ||
1213 | * queue the frame to the head without worrying | ||
1214 | * about reordering of fragments. | ||
1215 | */ | ||
1216 | if (unlikely(txpending)) | ||
1217 | __skb_queue_head(&local->pending[q], | ||
1218 | skb); | ||
1219 | else | ||
1220 | __skb_queue_tail(&local->pending[q], | ||
1221 | skb); | ||
1222 | } while ((skb = next)); | ||
1223 | 1224 | ||
1224 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, | 1225 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, |
1225 | flags); | 1226 | flags); |
@@ -1233,10 +1234,9 @@ static bool __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp, | |||
1233 | info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | | 1234 | info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | |
1234 | IEEE80211_TX_CTL_FIRST_FRAGMENT); | 1235 | IEEE80211_TX_CTL_FIRST_FRAGMENT); |
1235 | 1236 | ||
1236 | next = skb->next; | ||
1237 | len = skb->len; | 1237 | len = skb->len; |
1238 | 1238 | ||
1239 | if (next) | 1239 | if (!skb_queue_is_last(skbs, skb)) |
1240 | info->flags |= IEEE80211_TX_CTL_MORE_FRAMES; | 1240 | info->flags |= IEEE80211_TX_CTL_MORE_FRAMES; |
1241 | 1241 | ||
1242 | sdata = vif_to_sdata(info->control.vif); | 1242 | sdata = vif_to_sdata(info->control.vif); |
@@ -1260,14 +1260,17 @@ static bool __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp, | |||
1260 | info->control.sta = NULL; | 1260 | info->control.sta = NULL; |
1261 | 1261 | ||
1262 | fc = ((struct ieee80211_hdr *)skb->data)->frame_control; | 1262 | fc = ((struct ieee80211_hdr *)skb->data)->frame_control; |
1263 | |||
1264 | __skb_unlink(skb, skbs); | ||
1263 | drv_tx(local, skb); | 1265 | drv_tx(local, skb); |
1264 | 1266 | ||
1265 | ieee80211_tpt_led_trig_tx(local, fc, len); | 1267 | ieee80211_tpt_led_trig_tx(local, fc, len); |
1266 | *skbp = skb = next; | ||
1267 | ieee80211_led_tx(local, 1); | 1268 | ieee80211_led_tx(local, 1); |
1268 | fragm = true; | 1269 | fragm = true; |
1269 | } | 1270 | } |
1270 | 1271 | ||
1272 | WARN_ON(!skb_queue_empty(skbs)); | ||
1273 | |||
1271 | return true; | 1274 | return true; |
1272 | } | 1275 | } |
1273 | 1276 | ||
@@ -1277,8 +1280,7 @@ static bool __ieee80211_tx(struct ieee80211_local *local, struct sk_buff **skbp, | |||
1277 | */ | 1280 | */ |
1278 | static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | 1281 | static int invoke_tx_handlers(struct ieee80211_tx_data *tx) |
1279 | { | 1282 | { |
1280 | struct sk_buff *skb = tx->skb; | 1283 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); |
1281 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
1282 | ieee80211_tx_result res = TX_DROP; | 1284 | ieee80211_tx_result res = TX_DROP; |
1283 | 1285 | ||
1284 | #define CALL_TXH(txh) \ | 1286 | #define CALL_TXH(txh) \ |
@@ -1312,13 +1314,10 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1312 | txh_done: | 1314 | txh_done: |
1313 | if (unlikely(res == TX_DROP)) { | 1315 | if (unlikely(res == TX_DROP)) { |
1314 | I802_DEBUG_INC(tx->local->tx_handlers_drop); | 1316 | I802_DEBUG_INC(tx->local->tx_handlers_drop); |
1315 | while (skb) { | 1317 | if (tx->skb) |
1316 | struct sk_buff *next; | 1318 | dev_kfree_skb(tx->skb); |
1317 | 1319 | else | |
1318 | next = skb->next; | 1320 | __skb_queue_purge(&tx->skbs); |
1319 | dev_kfree_skb(skb); | ||
1320 | skb = next; | ||
1321 | } | ||
1322 | return -1; | 1321 | return -1; |
1323 | } else if (unlikely(res == TX_QUEUED)) { | 1322 | } else if (unlikely(res == TX_QUEUED)) { |
1324 | I802_DEBUG_INC(tx->local->tx_handlers_queued); | 1323 | I802_DEBUG_INC(tx->local->tx_handlers_queued); |
@@ -1361,7 +1360,7 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
1361 | info->band = tx.channel->band; | 1360 | info->band = tx.channel->band; |
1362 | 1361 | ||
1363 | if (!invoke_tx_handlers(&tx)) | 1362 | if (!invoke_tx_handlers(&tx)) |
1364 | result = __ieee80211_tx(local, &tx.skb, tx.sta, txpending); | 1363 | result = __ieee80211_tx(local, &tx.skbs, tx.sta, txpending); |
1365 | out: | 1364 | out: |
1366 | rcu_read_unlock(); | 1365 | rcu_read_unlock(); |
1367 | return result; | 1366 | return result; |
@@ -2109,10 +2108,15 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, | |||
2109 | if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { | 2108 | if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { |
2110 | result = ieee80211_tx(sdata, skb, true); | 2109 | result = ieee80211_tx(sdata, skb, true); |
2111 | } else { | 2110 | } else { |
2111 | struct sk_buff_head skbs; | ||
2112 | |||
2113 | __skb_queue_head_init(&skbs); | ||
2114 | __skb_queue_tail(&skbs, skb); | ||
2115 | |||
2112 | hdr = (struct ieee80211_hdr *)skb->data; | 2116 | hdr = (struct ieee80211_hdr *)skb->data; |
2113 | sta = sta_info_get(sdata, hdr->addr1); | 2117 | sta = sta_info_get(sdata, hdr->addr1); |
2114 | 2118 | ||
2115 | result = __ieee80211_tx(local, &skb, sta, true); | 2119 | result = __ieee80211_tx(local, &skbs, sta, true); |
2116 | } | 2120 | } |
2117 | 2121 | ||
2118 | return result; | 2122 | return result; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 4cf25b0eea74..939bf248ec73 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -95,13 +95,13 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, | |||
95 | 95 | ||
96 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) | 96 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) |
97 | { | 97 | { |
98 | struct sk_buff *skb = tx->skb; | 98 | struct sk_buff *skb; |
99 | struct ieee80211_hdr *hdr; | 99 | struct ieee80211_hdr *hdr; |
100 | 100 | ||
101 | do { | 101 | skb_queue_walk(&tx->skbs, skb) { |
102 | hdr = (struct ieee80211_hdr *) skb->data; | 102 | hdr = (struct ieee80211_hdr *) skb->data; |
103 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | 103 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
104 | } while ((skb = skb->next)); | 104 | } |
105 | } | 105 | } |
106 | 106 | ||
107 | int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, | 107 | int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, |
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index a1c6bfd55f0f..68ad351479df 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
@@ -330,13 +330,12 @@ ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx) | |||
330 | 330 | ||
331 | ieee80211_tx_set_protected(tx); | 331 | ieee80211_tx_set_protected(tx); |
332 | 332 | ||
333 | skb = tx->skb; | 333 | skb_queue_walk(&tx->skbs, skb) { |
334 | do { | ||
335 | if (wep_encrypt_skb(tx, skb) < 0) { | 334 | if (wep_encrypt_skb(tx, skb) < 0) { |
336 | I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); | 335 | I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); |
337 | return TX_DROP; | 336 | return TX_DROP; |
338 | } | 337 | } |
339 | } while ((skb = skb->next)); | 338 | } |
340 | 339 | ||
341 | return TX_CONTINUE; | 340 | return TX_CONTINUE; |
342 | } | 341 | } |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 106e15a4649f..93aab0715e8a 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -223,14 +223,14 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
223 | ieee80211_tx_result | 223 | ieee80211_tx_result |
224 | ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) | 224 | ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) |
225 | { | 225 | { |
226 | struct sk_buff *skb = tx->skb; | 226 | struct sk_buff *skb; |
227 | 227 | ||
228 | ieee80211_tx_set_protected(tx); | 228 | ieee80211_tx_set_protected(tx); |
229 | 229 | ||
230 | do { | 230 | skb_queue_walk(&tx->skbs, skb) { |
231 | if (tkip_encrypt_skb(tx, skb) < 0) | 231 | if (tkip_encrypt_skb(tx, skb) < 0) |
232 | return TX_DROP; | 232 | return TX_DROP; |
233 | } while ((skb = skb->next)); | 233 | } |
234 | 234 | ||
235 | return TX_CONTINUE; | 235 | return TX_CONTINUE; |
236 | } | 236 | } |
@@ -449,14 +449,14 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
449 | ieee80211_tx_result | 449 | ieee80211_tx_result |
450 | ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) | 450 | ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) |
451 | { | 451 | { |
452 | struct sk_buff *skb = tx->skb; | 452 | struct sk_buff *skb; |
453 | 453 | ||
454 | ieee80211_tx_set_protected(tx); | 454 | ieee80211_tx_set_protected(tx); |
455 | 455 | ||
456 | do { | 456 | skb_queue_walk(&tx->skbs, skb) { |
457 | if (ccmp_encrypt_skb(tx, skb) < 0) | 457 | if (ccmp_encrypt_skb(tx, skb) < 0) |
458 | return TX_DROP; | 458 | return TX_DROP; |
459 | } while ((skb = skb->next)); | 459 | } |
460 | 460 | ||
461 | return TX_CONTINUE; | 461 | return TX_CONTINUE; |
462 | } | 462 | } |
@@ -554,15 +554,22 @@ static inline void bip_ipn_swap(u8 *d, const u8 *s) | |||
554 | ieee80211_tx_result | 554 | ieee80211_tx_result |
555 | ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) | 555 | ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) |
556 | { | 556 | { |
557 | struct sk_buff *skb = tx->skb; | 557 | struct sk_buff *skb; |
558 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 558 | struct ieee80211_tx_info *info; |
559 | struct ieee80211_key *key = tx->key; | 559 | struct ieee80211_key *key = tx->key; |
560 | struct ieee80211_mmie *mmie; | 560 | struct ieee80211_mmie *mmie; |
561 | u8 aad[20]; | 561 | u8 aad[20]; |
562 | u64 pn64; | 562 | u64 pn64; |
563 | 563 | ||
564 | if (WARN_ON(skb_queue_len(&tx->skbs) != 1)) | ||
565 | return TX_DROP; | ||
566 | |||
567 | skb = skb_peek(&tx->skbs); | ||
568 | |||
569 | info = IEEE80211_SKB_CB(skb); | ||
570 | |||
564 | if (info->control.hw_key) | 571 | if (info->control.hw_key) |
565 | return 0; | 572 | return TX_CONTINUE; |
566 | 573 | ||
567 | if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) | 574 | if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) |
568 | return TX_DROP; | 575 | return TX_DROP; |