aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/chan.c11
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/main.c4
-rw-r--r--net/mac80211/mlme.c20
-rw-r--r--net/mac80211/offchannel.c26
-rw-r--r--net/mac80211/rx.c3
-rw-r--r--net/mac80211/sta_info.c3
-rw-r--r--net/mac80211/status.c6
-rw-r--r--net/mac80211/trace.h4
-rw-r--r--net/mac80211/util.c2
-rw-r--r--net/mac80211/vht.c9
11 files changed, 62 insertions, 27 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index bd1fd8ea5105..75b5dd2c9267 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -249,7 +249,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
249 249
250 if (!local->use_chanctx) { 250 if (!local->use_chanctx) {
251 local->_oper_chandef = *chandef; 251 local->_oper_chandef = *chandef;
252 ieee80211_hw_config(local, 0); 252 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
253 } else { 253 } else {
254 err = drv_add_chanctx(local, ctx); 254 err = drv_add_chanctx(local, ctx);
255 if (err) { 255 if (err) {
@@ -286,7 +286,7 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
286 check_single_channel = true; 286 check_single_channel = true;
287 local->hw.conf.radar_enabled = false; 287 local->hw.conf.radar_enabled = false;
288 288
289 ieee80211_hw_config(local, 0); 289 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
290 } else { 290 } else {
291 drv_remove_chanctx(local, ctx); 291 drv_remove_chanctx(local, ctx);
292 } 292 }
@@ -492,6 +492,13 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
492 rx_chains_static = max(rx_chains_static, needed_static); 492 rx_chains_static = max(rx_chains_static, needed_static);
493 rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic); 493 rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic);
494 } 494 }
495
496 /* Disable SMPS for the monitor interface */
497 sdata = rcu_dereference(local->monitor_sdata);
498 if (sdata &&
499 rcu_access_pointer(sdata->vif.chanctx_conf) == &chanctx->conf)
500 rx_chains_dynamic = rx_chains_static = local->rx_chains;
501
495 rcu_read_unlock(); 502 rcu_read_unlock();
496 503
497 if (!local->use_chanctx) { 504 if (!local->use_chanctx) {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 222c28b75315..f169b6ee94ee 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -317,6 +317,7 @@ struct ieee80211_roc_work {
317 317
318 bool started, abort, hw_begun, notified; 318 bool started, abort, hw_begun, notified;
319 bool to_be_freed; 319 bool to_be_freed;
320 bool on_channel;
320 321
321 unsigned long hw_start_time; 322 unsigned long hw_start_time;
322 323
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index b055f6a55c68..4c1bf61bc778 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -148,6 +148,8 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
148 list_for_each_entry_rcu(sdata, &local->interfaces, list) { 148 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
149 if (!rcu_access_pointer(sdata->vif.chanctx_conf)) 149 if (!rcu_access_pointer(sdata->vif.chanctx_conf))
150 continue; 150 continue;
151 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
152 continue;
151 power = min(power, sdata->vif.bss_conf.txpower); 153 power = min(power, sdata->vif.bss_conf.txpower);
152 } 154 }
153 rcu_read_unlock(); 155 rcu_read_unlock();
@@ -199,7 +201,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
199{ 201{
200 struct ieee80211_local *local = sdata->local; 202 struct ieee80211_local *local = sdata->local;
201 203
202 if (!changed) 204 if (!changed || sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
203 return; 205 return;
204 206
205 drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed); 207 drv_bss_info_changed(local, sdata, &sdata->vif.bss_conf, changed);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index dee50aefd6e8..27600a9808ba 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3598,18 +3598,24 @@ void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata)
3598 3598
3599 sdata_lock(sdata); 3599 sdata_lock(sdata);
3600 3600
3601 if (ifmgd->auth_data) { 3601 if (ifmgd->auth_data || ifmgd->assoc_data) {
3602 const u8 *bssid = ifmgd->auth_data ?
3603 ifmgd->auth_data->bss->bssid :
3604 ifmgd->assoc_data->bss->bssid;
3605
3602 /* 3606 /*
3603 * If we are trying to authenticate while suspending, cfg80211 3607 * If we are trying to authenticate / associate while suspending,
3604 * won't know and won't actually abort those attempts, thus we 3608 * cfg80211 won't know and won't actually abort those attempts,
3605 * need to do that ourselves. 3609 * thus we need to do that ourselves.
3606 */ 3610 */
3607 ieee80211_send_deauth_disassoc(sdata, 3611 ieee80211_send_deauth_disassoc(sdata, bssid,
3608 ifmgd->auth_data->bss->bssid,
3609 IEEE80211_STYPE_DEAUTH, 3612 IEEE80211_STYPE_DEAUTH,
3610 WLAN_REASON_DEAUTH_LEAVING, 3613 WLAN_REASON_DEAUTH_LEAVING,
3611 false, frame_buf); 3614 false, frame_buf);
3612 ieee80211_destroy_auth_data(sdata, false); 3615 if (ifmgd->assoc_data)
3616 ieee80211_destroy_assoc_data(sdata, false);
3617 if (ifmgd->auth_data)
3618 ieee80211_destroy_auth_data(sdata, false);
3613 cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, 3619 cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
3614 IEEE80211_DEAUTH_FRAME_LEN); 3620 IEEE80211_DEAUTH_FRAME_LEN);
3615 } 3621 }
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 0c2a29484c07..7a17decd27f9 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -333,7 +333,7 @@ void ieee80211_sw_roc_work(struct work_struct *work)
333 container_of(work, struct ieee80211_roc_work, work.work); 333 container_of(work, struct ieee80211_roc_work, work.work);
334 struct ieee80211_sub_if_data *sdata = roc->sdata; 334 struct ieee80211_sub_if_data *sdata = roc->sdata;
335 struct ieee80211_local *local = sdata->local; 335 struct ieee80211_local *local = sdata->local;
336 bool started; 336 bool started, on_channel;
337 337
338 mutex_lock(&local->mtx); 338 mutex_lock(&local->mtx);
339 339
@@ -354,13 +354,26 @@ void ieee80211_sw_roc_work(struct work_struct *work)
354 if (!roc->started) { 354 if (!roc->started) {
355 struct ieee80211_roc_work *dep; 355 struct ieee80211_roc_work *dep;
356 356
357 /* start this ROC */ 357 WARN_ON(local->use_chanctx);
358
359 /* If actually operating on the desired channel (with at least
360 * 20 MHz channel width) don't stop all the operations but still
361 * treat it as though the ROC operation started properly, so
362 * other ROC operations won't interfere with this one.
363 */
364 roc->on_channel = roc->chan == local->_oper_chandef.chan &&
365 local->_oper_chandef.width != NL80211_CHAN_WIDTH_5 &&
366 local->_oper_chandef.width != NL80211_CHAN_WIDTH_10;
358 367
359 /* switch channel etc */ 368 /* start this ROC */
360 ieee80211_recalc_idle(local); 369 ieee80211_recalc_idle(local);
361 370
362 local->tmp_channel = roc->chan; 371 if (!roc->on_channel) {
363 ieee80211_hw_config(local, 0); 372 ieee80211_offchannel_stop_vifs(local);
373
374 local->tmp_channel = roc->chan;
375 ieee80211_hw_config(local, 0);
376 }
364 377
365 /* tell userspace or send frame */ 378 /* tell userspace or send frame */
366 ieee80211_handle_roc_started(roc); 379 ieee80211_handle_roc_started(roc);
@@ -379,9 +392,10 @@ void ieee80211_sw_roc_work(struct work_struct *work)
379 finish: 392 finish:
380 list_del(&roc->list); 393 list_del(&roc->list);
381 started = roc->started; 394 started = roc->started;
395 on_channel = roc->on_channel;
382 ieee80211_roc_notify_destroy(roc, !roc->abort); 396 ieee80211_roc_notify_destroy(roc, !roc->abort);
383 397
384 if (started) { 398 if (started && !on_channel) {
385 ieee80211_flush_queues(local, NULL); 399 ieee80211_flush_queues(local, NULL);
386 400
387 local->tmp_channel = NULL; 401 local->tmp_channel = NULL;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 216c45b949e5..2b608b2b70ec 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1231,7 +1231,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
1231 if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) && 1231 if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) &&
1232 test_sta_flag(sta, WLAN_STA_AUTHORIZED)) { 1232 test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
1233 sta->last_rx = jiffies; 1233 sta->last_rx = jiffies;
1234 if (ieee80211_is_data(hdr->frame_control)) { 1234 if (ieee80211_is_data(hdr->frame_control) &&
1235 !is_multicast_ether_addr(hdr->addr1)) {
1235 sta->last_rx_rate_idx = status->rate_idx; 1236 sta->last_rx_rate_idx = status->rate_idx;
1236 sta->last_rx_rate_flag = status->flag; 1237 sta->last_rx_rate_flag = status->flag;
1237 sta->last_rx_rate_vht_flag = status->vht_flag; 1238 sta->last_rx_rate_vht_flag = status->vht_flag;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 137a192e64bc..847d92f6bef6 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1148,7 +1148,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
1148 atomic_dec(&ps->num_sta_ps); 1148 atomic_dec(&ps->num_sta_ps);
1149 1149
1150 /* This station just woke up and isn't aware of our SMPS state */ 1150 /* This station just woke up and isn't aware of our SMPS state */
1151 if (!ieee80211_smps_is_restrictive(sta->known_smps_mode, 1151 if (!ieee80211_vif_is_mesh(&sdata->vif) &&
1152 !ieee80211_smps_is_restrictive(sta->known_smps_mode,
1152 sdata->smps_mode) && 1153 sdata->smps_mode) &&
1153 sta->known_smps_mode != sdata->bss->req_smps && 1154 sta->known_smps_mode != sdata->bss->req_smps &&
1154 sta_info_tx_streams(sta) != 1) { 1155 sta_info_tx_streams(sta) != 1) {
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index e6e574a307c8..60cb7a665976 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -314,10 +314,9 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_local *local,
314 !is_multicast_ether_addr(hdr->addr1)) 314 !is_multicast_ether_addr(hdr->addr1))
315 txflags |= IEEE80211_RADIOTAP_F_TX_FAIL; 315 txflags |= IEEE80211_RADIOTAP_F_TX_FAIL;
316 316
317 if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || 317 if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
318 (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
319 txflags |= IEEE80211_RADIOTAP_F_TX_CTS; 318 txflags |= IEEE80211_RADIOTAP_F_TX_CTS;
320 else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) 319 if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
321 txflags |= IEEE80211_RADIOTAP_F_TX_RTS; 320 txflags |= IEEE80211_RADIOTAP_F_TX_RTS;
322 321
323 put_unaligned_le16(txflags, pos); 322 put_unaligned_le16(txflags, pos);
@@ -618,6 +617,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
618 sta, true, acked); 617 sta, true, acked);
619 618
620 if ((local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) && 619 if ((local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) &&
620 (ieee80211_is_data(hdr->frame_control)) &&
621 (rates_idx != -1)) 621 (rates_idx != -1))
622 sta->last_tx_rate = info->status.rates[rates_idx]; 622 sta->last_tx_rate = info->status.rates[rates_idx];
623 623
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index a0b0aea76525..cec5b60487a4 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -21,10 +21,10 @@
21 21
22#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \ 22#define VIF_ENTRY __field(enum nl80211_iftype, vif_type) __field(void *, sdata) \
23 __field(bool, p2p) \ 23 __field(bool, p2p) \
24 __string(vif_name, sdata->dev ? sdata->dev->name : "<nodev>") 24 __string(vif_name, sdata->name)
25#define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \ 25#define VIF_ASSIGN __entry->vif_type = sdata->vif.type; __entry->sdata = sdata; \
26 __entry->p2p = sdata->vif.p2p; \ 26 __entry->p2p = sdata->vif.p2p; \
27 __assign_str(vif_name, sdata->dev ? sdata->dev->name : sdata->name) 27 __assign_str(vif_name, sdata->name)
28#define VIF_PR_FMT " vif:%s(%d%s)" 28#define VIF_PR_FMT " vif:%s(%d%s)"
29#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : "" 29#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
30 30
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 275c94f995f7..3c365837e910 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1780,7 +1780,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1780 mutex_unlock(&local->mtx); 1780 mutex_unlock(&local->mtx);
1781 1781
1782 if (sched_scan_stopped) 1782 if (sched_scan_stopped)
1783 cfg80211_sched_scan_stopped(local->hw.wiphy); 1783 cfg80211_sched_scan_stopped_rtnl(local->hw.wiphy);
1784 1784
1785 /* 1785 /*
1786 * If this is for hw restart things are still running. 1786 * If this is for hw restart things are still running.
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index e9e36a256165..9265adfdabfc 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -129,9 +129,12 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
129 if (!vht_cap_ie || !sband->vht_cap.vht_supported) 129 if (!vht_cap_ie || !sband->vht_cap.vht_supported)
130 return; 130 return;
131 131
132 /* A VHT STA must support 40 MHz */ 132 /*
133 if (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) 133 * A VHT STA must support 40 MHz, but if we verify that here
134 return; 134 * then we break a few things - some APs (e.g. Netgear R6300v2
135 * and others based on the BCM4360 chipset) will unset this
136 * capability bit when operating in 20 MHz.
137 */
135 138
136 vht_cap->vht_supported = true; 139 vht_cap->vht_supported = true;
137 140