diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-11-16 10:02:47 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-21 16:20:43 -0500 |
commit | 11127e9121d4dd9da868cf0fd89dcac35f7f0fa3 (patch) | |
tree | 8cb16ecbd5942679c18934064b935a7e256a77da /net/mac80211/tx.c | |
parent | 74e4dbfd57a38c4ec4131cebdbfa3d621d38dd6a (diff) |
mac80211: transmit fragment list to drivers
Drivers can usually handle fragmented packets
much easier when they get the entire list of
fragments at once. The only thing they need to
do is keep enough space on the queues for up
to ten fragments of a single MSDU.
This allows them to implement this with a new
operation tx_frags.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r-- | net/mac80211/tx.c | 94 |
1 files changed, 60 insertions, 34 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0cc68d0796a2..facc80d23b0c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1200,24 +1200,15 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1200 | return TX_CONTINUE; | 1200 | return TX_CONTINUE; |
1201 | } | 1201 | } |
1202 | 1202 | ||
1203 | /* | 1203 | static bool ieee80211_tx_frags(struct ieee80211_local *local, |
1204 | * Returns false if the frame couldn't be transmitted but was queued instead. | 1204 | struct ieee80211_vif *vif, |
1205 | */ | 1205 | struct ieee80211_sta *sta, |
1206 | static bool __ieee80211_tx(struct ieee80211_local *local, | 1206 | struct sk_buff_head *skbs, |
1207 | struct sk_buff_head *skbs, int led_len, | 1207 | bool txpending) |
1208 | struct sta_info *sta, bool txpending) | ||
1209 | { | 1208 | { |
1210 | struct sk_buff *skb, *tmp; | 1209 | struct sk_buff *skb, *tmp; |
1211 | struct ieee80211_tx_info *info; | 1210 | struct ieee80211_tx_info *info; |
1212 | struct ieee80211_sub_if_data *sdata; | ||
1213 | unsigned long flags; | 1211 | unsigned long flags; |
1214 | __le16 fc; | ||
1215 | |||
1216 | if (WARN_ON(skb_queue_empty(skbs))) | ||
1217 | return true; | ||
1218 | |||
1219 | skb = skb_peek(skbs); | ||
1220 | fc = ((struct ieee80211_hdr *)skb->data)->frame_control; | ||
1221 | 1212 | ||
1222 | skb_queue_walk_safe(skbs, skb, tmp) { | 1213 | skb_queue_walk_safe(skbs, skb, tmp) { |
1223 | int q = skb_get_queue_mapping(skb); | 1214 | int q = skb_get_queue_mapping(skb); |
@@ -1242,37 +1233,72 @@ static bool __ieee80211_tx(struct ieee80211_local *local, | |||
1242 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 1233 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
1243 | 1234 | ||
1244 | info = IEEE80211_SKB_CB(skb); | 1235 | info = IEEE80211_SKB_CB(skb); |
1236 | info->control.vif = vif; | ||
1237 | info->control.sta = sta; | ||
1245 | 1238 | ||
1246 | sdata = vif_to_sdata(info->control.vif); | 1239 | __skb_unlink(skb, skbs); |
1240 | drv_tx(local, skb); | ||
1241 | } | ||
1247 | 1242 | ||
1248 | switch (sdata->vif.type) { | 1243 | return true; |
1249 | case NL80211_IFTYPE_MONITOR: | 1244 | } |
1250 | info->control.vif = NULL; | ||
1251 | break; | ||
1252 | case NL80211_IFTYPE_AP_VLAN: | ||
1253 | info->control.vif = &container_of(sdata->bss, | ||
1254 | struct ieee80211_sub_if_data, u.ap)->vif; | ||
1255 | break; | ||
1256 | default: | ||
1257 | /* keep */ | ||
1258 | break; | ||
1259 | } | ||
1260 | 1245 | ||
1261 | if (sta && sta->uploaded) | 1246 | /* |
1262 | info->control.sta = &sta->sta; | 1247 | * Returns false if the frame couldn't be transmitted but was queued instead. |
1263 | else | 1248 | */ |
1264 | info->control.sta = NULL; | 1249 | static bool __ieee80211_tx(struct ieee80211_local *local, |
1250 | struct sk_buff_head *skbs, int led_len, | ||
1251 | struct sta_info *sta, bool txpending) | ||
1252 | { | ||
1253 | struct ieee80211_tx_info *info; | ||
1254 | struct ieee80211_sub_if_data *sdata; | ||
1255 | struct ieee80211_vif *vif; | ||
1256 | struct ieee80211_sta *pubsta; | ||
1257 | struct sk_buff *skb; | ||
1258 | bool result = true; | ||
1259 | __le16 fc; | ||
1265 | 1260 | ||
1266 | __skb_unlink(skb, skbs); | 1261 | if (WARN_ON(skb_queue_empty(skbs))) |
1267 | drv_tx(local, skb); | 1262 | return true; |
1263 | |||
1264 | skb = skb_peek(skbs); | ||
1265 | fc = ((struct ieee80211_hdr *)skb->data)->frame_control; | ||
1266 | info = IEEE80211_SKB_CB(skb); | ||
1267 | sdata = vif_to_sdata(info->control.vif); | ||
1268 | if (sta && !sta->uploaded) | ||
1269 | sta = NULL; | ||
1270 | |||
1271 | if (sta) | ||
1272 | pubsta = &sta->sta; | ||
1273 | else | ||
1274 | pubsta = NULL; | ||
1275 | |||
1276 | switch (sdata->vif.type) { | ||
1277 | case NL80211_IFTYPE_MONITOR: | ||
1278 | sdata = NULL; | ||
1279 | vif = NULL; | ||
1280 | break; | ||
1281 | case NL80211_IFTYPE_AP_VLAN: | ||
1282 | sdata = container_of(sdata->bss, | ||
1283 | struct ieee80211_sub_if_data, u.ap); | ||
1284 | /* fall through */ | ||
1285 | default: | ||
1286 | vif = &sdata->vif; | ||
1287 | break; | ||
1268 | } | 1288 | } |
1269 | 1289 | ||
1290 | if (local->ops->tx_frags) | ||
1291 | drv_tx_frags(local, vif, pubsta, skbs); | ||
1292 | else | ||
1293 | result = ieee80211_tx_frags(local, vif, pubsta, skbs, | ||
1294 | txpending); | ||
1295 | |||
1270 | ieee80211_tpt_led_trig_tx(local, fc, led_len); | 1296 | ieee80211_tpt_led_trig_tx(local, fc, led_len); |
1271 | ieee80211_led_tx(local, 1); | 1297 | ieee80211_led_tx(local, 1); |
1272 | 1298 | ||
1273 | WARN_ON(!skb_queue_empty(skbs)); | 1299 | WARN_ON(!skb_queue_empty(skbs)); |
1274 | 1300 | ||
1275 | return true; | 1301 | return result; |
1276 | } | 1302 | } |
1277 | 1303 | ||
1278 | /* | 1304 | /* |