summaryrefslogtreecommitdiffstats
path: root/net/mac80211/tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r--net/mac80211/tx.c79
1 files changed, 53 insertions, 26 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 782a60198df4..4f6aac16ac3a 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -230,9 +230,9 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
* changed via debugfs, user needs to reassociate manually to have
* everything in sync.
*/
- if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
- && (ifmgd->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
- && skb_get_queue_mapping(tx->skb) == 0)
+ if ((ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) &&
+ (ifmgd->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) &&
+ skb_get_queue_mapping(tx->skb) == IEEE80211_AC_VO)
return TX_CONTINUE;
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
@@ -400,6 +400,8 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
return TX_CONTINUE;
info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
+ if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
+ info->hw_queue = tx->sdata->vif.cab_queue;
/* device releases frame after DTIM beacon */
if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING))
@@ -1118,8 +1120,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
/* reset session timer */
if (reset_agg_timer && tid_tx->timeout)
- mod_timer(&tid_tx->session_timer,
- TU_TO_EXP_TIME(tid_tx->timeout));
+ tid_tx->last_tx = jiffies;
return queued;
}
@@ -1215,11 +1216,19 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
bool txpending)
{
struct sk_buff *skb, *tmp;
- struct ieee80211_tx_info *info;
unsigned long flags;
skb_queue_walk_safe(skbs, skb, tmp) {
- int q = skb_get_queue_mapping(skb);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ int q = info->hw_queue;
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ if (WARN_ON_ONCE(q >= local->hw.queues)) {
+ __skb_unlink(skb, skbs);
+ dev_kfree_skb(skb);
+ continue;
+ }
+#endif
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
if (local->queue_stop_reasons[q] ||
@@ -1241,7 +1250,6 @@ static bool ieee80211_tx_frags(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;
@@ -1284,8 +1292,16 @@ static bool __ieee80211_tx(struct ieee80211_local *local,
switch (sdata->vif.type) {
case NL80211_IFTYPE_MONITOR:
- sdata = NULL;
- vif = NULL;
+ sdata = rcu_dereference(local->monitor_sdata);
+ if (sdata) {
+ vif = &sdata->vif;
+ info->hw_queue =
+ vif->hw_queue[skb_get_queue_mapping(skb)];
+ } else if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) {
+ dev_kfree_skb(skb);
+ return true;
+ } else
+ vif = NULL;
break;
case NL80211_IFTYPE_AP_VLAN:
sdata = container_of(sdata->bss,
@@ -1400,6 +1416,12 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
tx.channel = local->hw.conf.channel;
info->band = tx.channel->band;
+ /* set up hw_queue value early */
+ if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) ||
+ !(local->hw.flags & IEEE80211_HW_QUEUE_CONTROL))
+ info->hw_queue =
+ sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
+
if (!invoke_tx_handlers(&tx))
result = __ieee80211_tx(local, &tx.skbs, led_len,
tx.sta, txpending);
@@ -1468,12 +1490,12 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
if (ieee80211_vif_is_mesh(&sdata->vif) &&
ieee80211_is_data(hdr->frame_control) &&
- !is_multicast_ether_addr(hdr->addr1))
- if (mesh_nexthop_resolve(skb, sdata)) {
- /* skb queued: don't free */
- rcu_read_unlock();
- return;
- }
+ !is_multicast_ether_addr(hdr->addr1) &&
+ mesh_nexthop_resolve(skb, sdata)) {
+ /* skb queued: don't free */
+ rcu_read_unlock();
+ return;
+ }
ieee80211_set_qos_hdr(sdata, skb);
ieee80211_tx(sdata, skb, false);
@@ -1929,7 +1951,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
wme_sta = true;
/* receiver and we are QoS enabled, use a QoS type frame */
- if (wme_sta && local->hw.queues >= 4) {
+ if (wme_sta && local->hw.queues >= IEEE80211_NUM_ACS) {
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
hdrlen += 2;
}
@@ -2170,7 +2192,6 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
void ieee80211_tx_pending(unsigned long data)
{
struct ieee80211_local *local = (struct ieee80211_local *)data;
- struct ieee80211_sub_if_data *sdata;
unsigned long flags;
int i;
bool txok;
@@ -2207,8 +2228,7 @@ void ieee80211_tx_pending(unsigned long data)
}
if (skb_queue_empty(&local->pending[i]))
- list_for_each_entry_rcu(sdata, &local->interfaces, list)
- netif_wake_subqueue(sdata->dev, i);
+ ieee80211_propagate_queue_wake(local, i);
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
@@ -2374,6 +2394,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
IEEE80211_STYPE_BEACON);
} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
struct ieee80211_mgmt *mgmt;
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
u8 *pos;
int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) +
sizeof(mgmt->u.beacon);
@@ -2383,6 +2404,10 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
goto out;
#endif
+ if (ifmsh->sync_ops)
+ ifmsh->sync_ops->adjust_tbtt(
+ sdata);
+
skb = dev_alloc_skb(local->tx_headroom +
hdr_len +
2 + /* NULL SSID */
@@ -2390,7 +2415,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2 + 3 + /* DS params */
2 + (IEEE80211_MAX_SUPP_RATES - 8) +
2 + sizeof(struct ieee80211_ht_cap) +
- 2 + sizeof(struct ieee80211_ht_info) +
+ 2 + sizeof(struct ieee80211_ht_operation) +
2 + sdata->u.mesh.mesh_id_len +
2 + sizeof(struct ieee80211_meshconf_ie) +
sdata->u.mesh.ie_len);
@@ -2414,12 +2439,12 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
*pos++ = WLAN_EID_SSID;
*pos++ = 0x0;
- if (ieee80211_add_srates_ie(&sdata->vif, skb) ||
+ if (ieee80211_add_srates_ie(&sdata->vif, skb, true) ||
mesh_add_ds_params_ie(skb, sdata) ||
- ieee80211_add_ext_srates_ie(&sdata->vif, skb) ||
+ ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) ||
mesh_add_rsn_ie(skb, sdata) ||
mesh_add_ht_cap_ie(skb, sdata) ||
- mesh_add_ht_info_ie(skb, sdata) ||
+ mesh_add_ht_oper_ie(skb, sdata) ||
mesh_add_meshid_ie(skb, sdata) ||
mesh_add_meshconf_ie(skb, sdata) ||
mesh_add_vendor_ies(skb, sdata)) {
@@ -2603,7 +2628,7 @@ struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw,
pos = skb_put(skb, ie_ssid_len);
*pos++ = WLAN_EID_SSID;
*pos++ = ssid_len;
- if (ssid)
+ if (ssid_len)
memcpy(pos, ssid, ssid_len);
pos += ssid_len;
@@ -2710,11 +2735,13 @@ EXPORT_SYMBOL(ieee80211_get_buffered_bc);
void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, int tid)
{
+ int ac = ieee802_1d_to_ac[tid];
+
skb_set_mac_header(skb, 0);
skb_set_network_header(skb, 0);
skb_set_transport_header(skb, 0);
- skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]);
+ skb_set_queue_mapping(skb, ac);
skb->priority = tid;
/*