diff options
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, return TX_CONTINUE; } -/* - * Returns false if the frame couldn't be transmitted but was queued instead. - */ -static bool __ieee80211_tx(struct ieee80211_local *local, - struct sk_buff_head *skbs, int led_len, - struct sta_info *sta, bool txpending) +static bool ieee80211_tx_frags(struct ieee80211_local *local, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct sk_buff_head *skbs, + bool txpending) { struct sk_buff *skb, *tmp; struct ieee80211_tx_info *info; - struct ieee80211_sub_if_data *sdata; unsigned long flags; - __le16 fc; - - if (WARN_ON(skb_queue_empty(skbs))) - return true; - - skb = skb_peek(skbs); - fc = ((struct ieee80211_hdr *)skb->data)->frame_control; skb_queue_walk_safe(skbs, skb, tmp) { int q = skb_get_queue_mapping(skb); @@ -1242,37 +1233,72 @@ static bool __ieee80211_tx(struct ieee80211_local *local, spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); info = IEEE80211_SKB_CB(skb); + info->control.vif = vif; + info->control.sta = sta; - sdata = vif_to_sdata(info->control.vif); + __skb_unlink(skb, skbs); + drv_tx(local, skb); + } - switch (sdata->vif.type) { - case NL80211_IFTYPE_MONITOR: - info->control.vif = NULL; - break; - case NL80211_IFTYPE_AP_VLAN: - info->control.vif = &container_of(sdata->bss, - struct ieee80211_sub_if_data, u.ap)->vif; - break; - default: - /* keep */ - break; - } + return true; +} - if (sta && sta->uploaded) - info->control.sta = &sta->sta; - else - info->control.sta = NULL; +/* + * Returns false if the frame couldn't be transmitted but was queued instead. + */ +static bool __ieee80211_tx(struct ieee80211_local *local, + struct sk_buff_head *skbs, int led_len, + struct sta_info *sta, bool txpending) +{ + struct ieee80211_tx_info *info; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_vif *vif; + struct ieee80211_sta *pubsta; + struct sk_buff *skb; + bool result = true; + __le16 fc; - __skb_unlink(skb, skbs); - drv_tx(local, skb); + if (WARN_ON(skb_queue_empty(skbs))) + return true; + + skb = skb_peek(skbs); + fc = ((struct ieee80211_hdr *)skb->data)->frame_control; + info = IEEE80211_SKB_CB(skb); + sdata = vif_to_sdata(info->control.vif); + if (sta && !sta->uploaded) + sta = NULL; + + if (sta) + pubsta = &sta->sta; + else + pubsta = NULL; + + switch (sdata->vif.type) { + case NL80211_IFTYPE_MONITOR: + sdata = NULL; + vif = NULL; + break; + case NL80211_IFTYPE_AP_VLAN: + sdata = container_of(sdata->bss, + struct ieee80211_sub_if_data, u.ap); + /* fall through */ + default: + vif = &sdata->vif; + break; } + if (local->ops->tx_frags) + drv_tx_frags(local, vif, pubsta, skbs); + else + result = ieee80211_tx_frags(local, vif, pubsta, skbs, + txpending); + ieee80211_tpt_led_trig_tx(local, fc, led_len); ieee80211_led_tx(local, 1); WARN_ON(!skb_queue_empty(skbs)); - return true; + return result; } /* |