diff options
author | John W. Linville <linville@tuxdriver.com> | 2014-11-20 16:09:30 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-11-20 16:09:30 -0500 |
commit | 9a638ddfb09e5aa17158842c95526e1aa79f92e6 (patch) | |
tree | 7edf2e128b23f711cf28273dca3ff69f3706925a /net/mac80211 | |
parent | b4c1b70823721e9edb19a839188e4dae50ce878d (diff) | |
parent | 75769c80e381653994293b5aa5a8cfec50088f9f (diff) |
Merge tag 'mac80211-next-for-john-2014-11-20' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg <johannes@sipsolutions.net> says:
"It has been a while since my last pull request, so we accumulated
another relatively large set of changes:
* TDLS off-channel support set from Arik/Liad, with some support
patches I did
* custom regulatory fixes from Arik
* minstrel VHT fix (and a small optimisation) from Felix
* add back radiotap vendor namespace support (myself)
* random MAC address scanning for cfg80211/mac80211/hwsim (myself)
* CSA improvements (Luca)
* WoWLAN Net Detect (wake on network found) support (Luca)
* and lots of other smaller changes from many people"
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/agg-tx.c | 7 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 27 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 11 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 83 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 42 | ||||
-rw-r--r-- | net/mac80211/iface.c | 2 | ||||
-rw-r--r-- | net/mac80211/main.c | 6 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 28 | ||||
-rw-r--r-- | net/mac80211/rate.c | 5 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel_ht.c | 6 | ||||
-rw-r--r-- | net/mac80211/rx.c | 146 | ||||
-rw-r--r-- | net/mac80211/scan.c | 129 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 15 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 11 | ||||
-rw-r--r-- | net/mac80211/status.c | 55 | ||||
-rw-r--r-- | net/mac80211/tdls.c | 792 | ||||
-rw-r--r-- | net/mac80211/trace.h | 142 | ||||
-rw-r--r-- | net/mac80211/tx.c | 303 | ||||
-rw-r--r-- | net/mac80211/util.c | 60 | ||||
-rw-r--r-- | net/mac80211/vht.c | 2 | ||||
-rw-r--r-- | net/mac80211/wme.c | 39 |
21 files changed, 1689 insertions, 222 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 9242c60048cf..a360c15cc978 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -509,6 +509,10 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, | |||
509 | struct tid_ampdu_tx *tid_tx; | 509 | struct tid_ampdu_tx *tid_tx; |
510 | int ret = 0; | 510 | int ret = 0; |
511 | 511 | ||
512 | if (WARN(sta->reserved_tid == tid, | ||
513 | "Requested to start BA session on reserved tid=%d", tid)) | ||
514 | return -EINVAL; | ||
515 | |||
512 | trace_api_start_tx_ba_session(pubsta, tid); | 516 | trace_api_start_tx_ba_session(pubsta, tid); |
513 | 517 | ||
514 | if (WARN_ON_ONCE(!local->ops->ampdu_action)) | 518 | if (WARN_ON_ONCE(!local->ops->ampdu_action)) |
@@ -765,6 +769,9 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
765 | goto unlock; | 769 | goto unlock; |
766 | } | 770 | } |
767 | 771 | ||
772 | WARN(sta->reserved_tid == tid, | ||
773 | "Requested to stop BA session on reserved tid=%d", tid); | ||
774 | |||
768 | if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | 775 | if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { |
769 | /* already in progress stopping it */ | 776 | /* already in progress stopping it */ |
770 | ret = 0; | 777 | ret = 0; |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 06185940cbb6..e75d5c53e97b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1042,6 +1042,13 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1042 | clear_sta_flag(sta, WLAN_STA_TDLS_PEER); | 1042 | clear_sta_flag(sta, WLAN_STA_TDLS_PEER); |
1043 | } | 1043 | } |
1044 | 1044 | ||
1045 | /* mark TDLS channel switch support, if the AP allows it */ | ||
1046 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && | ||
1047 | !sdata->u.mgd.tdls_chan_switch_prohibited && | ||
1048 | params->ext_capab_len >= 4 && | ||
1049 | params->ext_capab[3] & WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) | ||
1050 | set_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH); | ||
1051 | |||
1045 | if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) { | 1052 | if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) { |
1046 | sta->sta.uapsd_queues = params->uapsd_queues; | 1053 | sta->sta.uapsd_queues = params->uapsd_queues; |
1047 | sta->sta.max_sp = params->max_sp; | 1054 | sta->sta.max_sp = params->max_sp; |
@@ -3158,6 +3165,12 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3158 | goto out; | 3165 | goto out; |
3159 | } | 3166 | } |
3160 | 3167 | ||
3168 | ch_switch.timestamp = 0; | ||
3169 | ch_switch.device_timestamp = 0; | ||
3170 | ch_switch.block_tx = params->block_tx; | ||
3171 | ch_switch.chandef = params->chandef; | ||
3172 | ch_switch.count = params->count; | ||
3173 | |||
3161 | err = drv_pre_channel_switch(sdata, &ch_switch); | 3174 | err = drv_pre_channel_switch(sdata, &ch_switch); |
3162 | if (err) | 3175 | if (err) |
3163 | goto out; | 3176 | goto out; |
@@ -3175,12 +3188,6 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3175 | goto out; | 3188 | goto out; |
3176 | } | 3189 | } |
3177 | 3190 | ||
3178 | ch_switch.timestamp = 0; | ||
3179 | ch_switch.device_timestamp = 0; | ||
3180 | ch_switch.block_tx = params->block_tx; | ||
3181 | ch_switch.chandef = params->chandef; | ||
3182 | ch_switch.count = params->count; | ||
3183 | |||
3184 | err = ieee80211_set_csa_beacon(sdata, params, &changed); | 3191 | err = ieee80211_set_csa_beacon(sdata, params, &changed); |
3185 | if (err) { | 3192 | if (err) { |
3186 | ieee80211_vif_unreserve_chanctx(sdata); | 3193 | ieee80211_vif_unreserve_chanctx(sdata); |
@@ -3195,6 +3202,9 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3195 | ieee80211_stop_vif_queues(local, sdata, | 3202 | ieee80211_stop_vif_queues(local, sdata, |
3196 | IEEE80211_QUEUE_STOP_REASON_CSA); | 3203 | IEEE80211_QUEUE_STOP_REASON_CSA); |
3197 | 3204 | ||
3205 | cfg80211_ch_switch_started_notify(sdata->dev, &sdata->csa_chandef, | ||
3206 | params->count); | ||
3207 | |||
3198 | if (changed) { | 3208 | if (changed) { |
3199 | ieee80211_bss_info_change_notify(sdata, changed); | 3209 | ieee80211_bss_info_change_notify(sdata, changed); |
3200 | drv_channel_switch_beacon(sdata, ¶ms->chandef); | 3210 | drv_channel_switch_beacon(sdata, ¶ms->chandef); |
@@ -3511,6 +3521,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
3511 | 3521 | ||
3512 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS | | 3522 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS | |
3513 | IEEE80211_TX_INTFL_NL80211_FRAME_TX; | 3523 | IEEE80211_TX_INTFL_NL80211_FRAME_TX; |
3524 | info->band = band; | ||
3514 | 3525 | ||
3515 | skb_set_queue_mapping(skb, IEEE80211_AC_VO); | 3526 | skb_set_queue_mapping(skb, IEEE80211_AC_VO); |
3516 | skb->priority = 7; | 3527 | skb->priority = 7; |
@@ -3518,7 +3529,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
3518 | nullfunc->qos_ctrl = cpu_to_le16(7); | 3529 | nullfunc->qos_ctrl = cpu_to_le16(7); |
3519 | 3530 | ||
3520 | local_bh_disable(); | 3531 | local_bh_disable(); |
3521 | ieee80211_xmit(sdata, skb, band); | 3532 | ieee80211_xmit(sdata, skb); |
3522 | local_bh_enable(); | 3533 | local_bh_enable(); |
3523 | rcu_read_unlock(); | 3534 | rcu_read_unlock(); |
3524 | 3535 | ||
@@ -3741,6 +3752,8 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
3741 | .set_rekey_data = ieee80211_set_rekey_data, | 3752 | .set_rekey_data = ieee80211_set_rekey_data, |
3742 | .tdls_oper = ieee80211_tdls_oper, | 3753 | .tdls_oper = ieee80211_tdls_oper, |
3743 | .tdls_mgmt = ieee80211_tdls_mgmt, | 3754 | .tdls_mgmt = ieee80211_tdls_mgmt, |
3755 | .tdls_channel_switch = ieee80211_tdls_channel_switch, | ||
3756 | .tdls_cancel_channel_switch = ieee80211_tdls_cancel_channel_switch, | ||
3744 | .probe_client = ieee80211_probe_client, | 3757 | .probe_client = ieee80211_probe_client, |
3745 | .set_noack_map = ieee80211_set_noack_map, | 3758 | .set_noack_map = ieee80211_set_noack_map, |
3746 | #ifdef CONFIG_PM | 3759 | #ifdef CONFIG_PM |
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index bafe48916229..94c70091bbd7 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -74,7 +74,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
74 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" | 74 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" |
75 | 75 | ||
76 | int res = scnprintf(buf, sizeof(buf), | 76 | int res = scnprintf(buf, sizeof(buf), |
77 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", | 77 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", |
78 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), | 78 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), |
79 | TEST(PS_DRIVER), TEST(AUTHORIZED), | 79 | TEST(PS_DRIVER), TEST(AUTHORIZED), |
80 | TEST(SHORT_PREAMBLE), | 80 | TEST(SHORT_PREAMBLE), |
@@ -82,10 +82,11 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
82 | TEST(WDS), TEST(CLEAR_PS_FILT), | 82 | TEST(WDS), TEST(CLEAR_PS_FILT), |
83 | TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), | 83 | TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), |
84 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), | 84 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), |
85 | TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), | 85 | TEST(TDLS_PEER_AUTH), TEST(TDLS_INITIATOR), |
86 | TEST(INSERTED), TEST(RATE_CONTROL), | 86 | TEST(TDLS_CHAN_SWITCH), TEST(TDLS_OFF_CHANNEL), |
87 | TEST(TOFFSET_KNOWN), TEST(MPSP_OWNER), | 87 | TEST(4ADDR_EVENT), TEST(INSERTED), |
88 | TEST(MPSP_RECIPIENT)); | 88 | TEST(RATE_CONTROL), TEST(TOFFSET_KNOWN), |
89 | TEST(MPSP_OWNER), TEST(MPSP_RECIPIENT)); | ||
89 | #undef TEST | 90 | #undef TEST |
90 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | 91 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); |
91 | } | 92 | } |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 9759dd1f0734..2ebc9ead9695 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -380,23 +380,26 @@ static inline int drv_sched_scan_stop(struct ieee80211_local *local, | |||
380 | return ret; | 380 | return ret; |
381 | } | 381 | } |
382 | 382 | ||
383 | static inline void drv_sw_scan_start(struct ieee80211_local *local) | 383 | static inline void drv_sw_scan_start(struct ieee80211_local *local, |
384 | struct ieee80211_sub_if_data *sdata, | ||
385 | const u8 *mac_addr) | ||
384 | { | 386 | { |
385 | might_sleep(); | 387 | might_sleep(); |
386 | 388 | ||
387 | trace_drv_sw_scan_start(local); | 389 | trace_drv_sw_scan_start(local, sdata, mac_addr); |
388 | if (local->ops->sw_scan_start) | 390 | if (local->ops->sw_scan_start) |
389 | local->ops->sw_scan_start(&local->hw); | 391 | local->ops->sw_scan_start(&local->hw, &sdata->vif, mac_addr); |
390 | trace_drv_return_void(local); | 392 | trace_drv_return_void(local); |
391 | } | 393 | } |
392 | 394 | ||
393 | static inline void drv_sw_scan_complete(struct ieee80211_local *local) | 395 | static inline void drv_sw_scan_complete(struct ieee80211_local *local, |
396 | struct ieee80211_sub_if_data *sdata) | ||
394 | { | 397 | { |
395 | might_sleep(); | 398 | might_sleep(); |
396 | 399 | ||
397 | trace_drv_sw_scan_complete(local); | 400 | trace_drv_sw_scan_complete(local, sdata); |
398 | if (local->ops->sw_scan_complete) | 401 | if (local->ops->sw_scan_complete) |
399 | local->ops->sw_scan_complete(&local->hw); | 402 | local->ops->sw_scan_complete(&local->hw, &sdata->vif); |
400 | trace_drv_return_void(local); | 403 | trace_drv_return_void(local); |
401 | } | 404 | } |
402 | 405 | ||
@@ -621,6 +624,21 @@ static inline void drv_sta_rc_update(struct ieee80211_local *local, | |||
621 | trace_drv_return_void(local); | 624 | trace_drv_return_void(local); |
622 | } | 625 | } |
623 | 626 | ||
627 | static inline void drv_sta_rate_tbl_update(struct ieee80211_local *local, | ||
628 | struct ieee80211_sub_if_data *sdata, | ||
629 | struct ieee80211_sta *sta) | ||
630 | { | ||
631 | sdata = get_bss_sdata(sdata); | ||
632 | if (!check_sdata_in_driver(sdata)) | ||
633 | return; | ||
634 | |||
635 | trace_drv_sta_rate_tbl_update(local, sdata, sta); | ||
636 | if (local->ops->sta_rate_tbl_update) | ||
637 | local->ops->sta_rate_tbl_update(&local->hw, &sdata->vif, sta); | ||
638 | |||
639 | trace_drv_return_void(local); | ||
640 | } | ||
641 | |||
624 | static inline int drv_conf_tx(struct ieee80211_local *local, | 642 | static inline int drv_conf_tx(struct ieee80211_local *local, |
625 | struct ieee80211_sub_if_data *sdata, u16 ac, | 643 | struct ieee80211_sub_if_data *sdata, u16 ac, |
626 | const struct ieee80211_tx_queue_params *params) | 644 | const struct ieee80211_tx_queue_params *params) |
@@ -1296,4 +1314,57 @@ static inline int drv_get_txpower(struct ieee80211_local *local, | |||
1296 | return ret; | 1314 | return ret; |
1297 | } | 1315 | } |
1298 | 1316 | ||
1317 | static inline int | ||
1318 | drv_tdls_channel_switch(struct ieee80211_local *local, | ||
1319 | struct ieee80211_sub_if_data *sdata, | ||
1320 | struct ieee80211_sta *sta, u8 oper_class, | ||
1321 | struct cfg80211_chan_def *chandef, | ||
1322 | struct sk_buff *tmpl_skb, u32 ch_sw_tm_ie) | ||
1323 | { | ||
1324 | int ret; | ||
1325 | |||
1326 | might_sleep(); | ||
1327 | if (!check_sdata_in_driver(sdata)) | ||
1328 | return -EIO; | ||
1329 | |||
1330 | if (!local->ops->tdls_channel_switch) | ||
1331 | return -EOPNOTSUPP; | ||
1332 | |||
1333 | trace_drv_tdls_channel_switch(local, sdata, sta, oper_class, chandef); | ||
1334 | ret = local->ops->tdls_channel_switch(&local->hw, &sdata->vif, sta, | ||
1335 | oper_class, chandef, tmpl_skb, | ||
1336 | ch_sw_tm_ie); | ||
1337 | trace_drv_return_int(local, ret); | ||
1338 | return ret; | ||
1339 | } | ||
1340 | |||
1341 | static inline void | ||
1342 | drv_tdls_cancel_channel_switch(struct ieee80211_local *local, | ||
1343 | struct ieee80211_sub_if_data *sdata, | ||
1344 | struct ieee80211_sta *sta) | ||
1345 | { | ||
1346 | might_sleep(); | ||
1347 | if (!check_sdata_in_driver(sdata)) | ||
1348 | return; | ||
1349 | |||
1350 | if (!local->ops->tdls_cancel_channel_switch) | ||
1351 | return; | ||
1352 | |||
1353 | trace_drv_tdls_cancel_channel_switch(local, sdata, sta); | ||
1354 | local->ops->tdls_cancel_channel_switch(&local->hw, &sdata->vif, sta); | ||
1355 | trace_drv_return_void(local); | ||
1356 | } | ||
1357 | |||
1358 | static inline void | ||
1359 | drv_tdls_recv_channel_switch(struct ieee80211_local *local, | ||
1360 | struct ieee80211_sub_if_data *sdata, | ||
1361 | struct ieee80211_tdls_ch_sw_params *params) | ||
1362 | { | ||
1363 | trace_drv_tdls_recv_channel_switch(local, sdata, params); | ||
1364 | if (local->ops->tdls_recv_channel_switch) | ||
1365 | local->ops->tdls_recv_channel_switch(&local->hw, &sdata->vif, | ||
1366 | params); | ||
1367 | trace_drv_return_void(local); | ||
1368 | } | ||
1369 | |||
1299 | #endif /* __MAC80211_DRIVER_OPS */ | 1370 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 842e0661fb57..cc6e964d9837 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -525,8 +525,13 @@ struct ieee80211_if_managed { | |||
525 | struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ | 525 | struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ |
526 | struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ | 526 | struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ |
527 | 527 | ||
528 | /* TDLS support */ | ||
528 | u8 tdls_peer[ETH_ALEN] __aligned(2); | 529 | u8 tdls_peer[ETH_ALEN] __aligned(2); |
529 | struct delayed_work tdls_peer_del_work; | 530 | struct delayed_work tdls_peer_del_work; |
531 | struct sk_buff *orig_teardown_skb; /* The original teardown skb */ | ||
532 | struct sk_buff *teardown_skb; /* A copy to send through the AP */ | ||
533 | spinlock_t teardown_lock; /* To lock changing teardown_skb */ | ||
534 | bool tdls_chan_switch_prohibited; | ||
530 | 535 | ||
531 | /* WMM-AC TSPEC support */ | 536 | /* WMM-AC TSPEC support */ |
532 | struct ieee80211_sta_tx_tspec tx_tspec[IEEE80211_NUM_ACS]; | 537 | struct ieee80211_sta_tx_tspec tx_tspec[IEEE80211_NUM_ACS]; |
@@ -988,6 +993,7 @@ enum sdata_queue_type { | |||
988 | IEEE80211_SDATA_QUEUE_AGG_STOP = 2, | 993 | IEEE80211_SDATA_QUEUE_AGG_STOP = 2, |
989 | IEEE80211_SDATA_QUEUE_RX_AGG_START = 3, | 994 | IEEE80211_SDATA_QUEUE_RX_AGG_START = 3, |
990 | IEEE80211_SDATA_QUEUE_RX_AGG_STOP = 4, | 995 | IEEE80211_SDATA_QUEUE_RX_AGG_STOP = 4, |
996 | IEEE80211_SDATA_QUEUE_TDLS_CHSW = 5, | ||
991 | }; | 997 | }; |
992 | 998 | ||
993 | enum { | 999 | enum { |
@@ -1005,6 +1011,7 @@ enum queue_stop_reason { | |||
1005 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, | 1011 | IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, |
1006 | IEEE80211_QUEUE_STOP_REASON_FLUSH, | 1012 | IEEE80211_QUEUE_STOP_REASON_FLUSH, |
1007 | IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN, | 1013 | IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN, |
1014 | IEEE80211_QUEUE_STOP_REASON_RESERVE_TID, | ||
1008 | 1015 | ||
1009 | IEEE80211_QUEUE_STOP_REASONS, | 1016 | IEEE80211_QUEUE_STOP_REASONS, |
1010 | }; | 1017 | }; |
@@ -1231,7 +1238,7 @@ struct ieee80211_local { | |||
1231 | unsigned long scanning; | 1238 | unsigned long scanning; |
1232 | struct cfg80211_ssid scan_ssid; | 1239 | struct cfg80211_ssid scan_ssid; |
1233 | struct cfg80211_scan_request *int_scan_req; | 1240 | struct cfg80211_scan_request *int_scan_req; |
1234 | struct cfg80211_scan_request *scan_req; | 1241 | struct cfg80211_scan_request __rcu *scan_req; |
1235 | struct ieee80211_scan_request *hw_scan_req; | 1242 | struct ieee80211_scan_request *hw_scan_req; |
1236 | struct cfg80211_chan_def scan_chandef; | 1243 | struct cfg80211_chan_def scan_chandef; |
1237 | enum ieee80211_band hw_scan_band; | 1244 | enum ieee80211_band hw_scan_band; |
@@ -1241,7 +1248,8 @@ struct ieee80211_local { | |||
1241 | 1248 | ||
1242 | struct work_struct sched_scan_stopped_work; | 1249 | struct work_struct sched_scan_stopped_work; |
1243 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; | 1250 | struct ieee80211_sub_if_data __rcu *sched_scan_sdata; |
1244 | struct cfg80211_sched_scan_request *sched_scan_req; | 1251 | struct cfg80211_sched_scan_request __rcu *sched_scan_req; |
1252 | u8 scan_addr[ETH_ALEN]; | ||
1245 | 1253 | ||
1246 | unsigned long leave_oper_channel_time; | 1254 | unsigned long leave_oper_channel_time; |
1247 | enum mac80211_scan_state next_scan_state; | 1255 | enum mac80211_scan_state next_scan_state; |
@@ -1395,6 +1403,9 @@ struct ieee802_11_elems { | |||
1395 | size_t total_len; | 1403 | size_t total_len; |
1396 | 1404 | ||
1397 | /* pointers to IEs */ | 1405 | /* pointers to IEs */ |
1406 | const struct ieee80211_tdls_lnkie *lnk_id; | ||
1407 | const struct ieee80211_ch_switch_timing *ch_sw_timing; | ||
1408 | const u8 *ext_capab; | ||
1398 | const u8 *ssid; | 1409 | const u8 *ssid; |
1399 | const u8 *supp_rates; | 1410 | const u8 *supp_rates; |
1400 | const u8 *ds_params; | 1411 | const u8 *ds_params; |
@@ -1429,6 +1440,7 @@ struct ieee802_11_elems { | |||
1429 | const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie; | 1440 | const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie; |
1430 | 1441 | ||
1431 | /* length of them, respectively */ | 1442 | /* length of them, respectively */ |
1443 | u8 ext_capab_len; | ||
1432 | u8 ssid_len; | 1444 | u8 ssid_len; |
1433 | u8 supp_rates_len; | 1445 | u8 supp_rates_len; |
1434 | u8 tim_len; | 1446 | u8 tim_len; |
@@ -1625,8 +1637,14 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1625 | struct net_device *dev); | 1637 | struct net_device *dev); |
1626 | netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | 1638 | netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, |
1627 | struct net_device *dev); | 1639 | struct net_device *dev); |
1640 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, | ||
1641 | struct net_device *dev, | ||
1642 | u32 info_flags); | ||
1628 | void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, | 1643 | void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, |
1629 | struct sk_buff_head *skbs); | 1644 | struct sk_buff_head *skbs); |
1645 | struct sk_buff * | ||
1646 | ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata, | ||
1647 | struct sk_buff *skb, u32 info_flags); | ||
1630 | 1648 | ||
1631 | /* HT */ | 1649 | /* HT */ |
1632 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | 1650 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, |
@@ -1753,8 +1771,7 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke | |||
1753 | gfp_t gfp); | 1771 | gfp_t gfp); |
1754 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | 1772 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, |
1755 | bool bss_notify); | 1773 | bool bss_notify); |
1756 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 1774 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); |
1757 | enum ieee80211_band band); | ||
1758 | 1775 | ||
1759 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, | 1776 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, |
1760 | struct sk_buff *skb, int tid, | 1777 | struct sk_buff *skb, int tid, |
@@ -1865,6 +1882,9 @@ void ieee80211_add_pending_skbs(struct ieee80211_local *local, | |||
1865 | struct sk_buff_head *skbs); | 1882 | struct sk_buff_head *skbs); |
1866 | void ieee80211_flush_queues(struct ieee80211_local *local, | 1883 | void ieee80211_flush_queues(struct ieee80211_local *local, |
1867 | struct ieee80211_sub_if_data *sdata); | 1884 | struct ieee80211_sub_if_data *sdata); |
1885 | void __ieee80211_flush_queues(struct ieee80211_local *local, | ||
1886 | struct ieee80211_sub_if_data *sdata, | ||
1887 | unsigned int queues); | ||
1868 | 1888 | ||
1869 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1889 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, |
1870 | u16 transaction, u16 auth_alg, u16 status, | 1890 | u16 transaction, u16 auth_alg, u16 status, |
@@ -1881,12 +1901,14 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1881 | u8 bands_used, u32 *rate_masks, | 1901 | u8 bands_used, u32 *rate_masks, |
1882 | struct cfg80211_chan_def *chandef); | 1902 | struct cfg80211_chan_def *chandef); |
1883 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1903 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
1884 | u8 *dst, u32 ratemask, | 1904 | const u8 *src, const u8 *dst, |
1905 | u32 ratemask, | ||
1885 | struct ieee80211_channel *chan, | 1906 | struct ieee80211_channel *chan, |
1886 | const u8 *ssid, size_t ssid_len, | 1907 | const u8 *ssid, size_t ssid_len, |
1887 | const u8 *ie, size_t ie_len, | 1908 | const u8 *ie, size_t ie_len, |
1888 | bool directed); | 1909 | bool directed); |
1889 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 1910 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, |
1911 | const u8 *src, const u8 *dst, | ||
1890 | const u8 *ssid, size_t ssid_len, | 1912 | const u8 *ssid, size_t ssid_len, |
1891 | const u8 *ie, size_t ie_len, | 1913 | const u8 *ie, size_t ie_len, |
1892 | u32 ratemask, bool directed, u32 tx_flags, | 1914 | u32 ratemask, bool directed, u32 tx_flags, |
@@ -1992,6 +2014,14 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
1992 | int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | 2014 | int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, |
1993 | const u8 *peer, enum nl80211_tdls_operation oper); | 2015 | const u8 *peer, enum nl80211_tdls_operation oper); |
1994 | void ieee80211_tdls_peer_del_work(struct work_struct *wk); | 2016 | void ieee80211_tdls_peer_del_work(struct work_struct *wk); |
2017 | int ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev, | ||
2018 | const u8 *addr, u8 oper_class, | ||
2019 | struct cfg80211_chan_def *chandef); | ||
2020 | void ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy, | ||
2021 | struct net_device *dev, | ||
2022 | const u8 *addr); | ||
2023 | void ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata, | ||
2024 | struct sk_buff *skb); | ||
1995 | 2025 | ||
1996 | extern const struct ethtool_ops ieee80211_ethtool_ops; | 2026 | extern const struct ethtool_ops ieee80211_ethtool_ops; |
1997 | 2027 | ||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 9df26adb864a..538fe4ef5c85 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -1208,6 +1208,8 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
1208 | WLAN_BACK_RECIPIENT, 0, | 1208 | WLAN_BACK_RECIPIENT, 0, |
1209 | false); | 1209 | false); |
1210 | mutex_unlock(&local->sta_mtx); | 1210 | mutex_unlock(&local->sta_mtx); |
1211 | } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_TDLS_CHSW) { | ||
1212 | ieee80211_process_tdls_channel_switch(sdata, skb); | ||
1211 | } else if (ieee80211_is_action(mgmt->frame_control) && | 1213 | } else if (ieee80211_is_action(mgmt->frame_control) && |
1212 | mgmt->u.action.category == WLAN_CATEGORY_BACK) { | 1214 | mgmt->u.action.category == WLAN_CATEGORY_BACK) { |
1213 | int len = skb->len; | 1215 | int len = skb->len; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 282a4f36eb92..6ab99da38db9 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -764,6 +764,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
764 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) | 764 | local->hw.offchannel_tx_hw_queue >= local->hw.queues)) |
765 | return -EINVAL; | 765 | return -EINVAL; |
766 | 766 | ||
767 | if ((hw->wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) && | ||
768 | (!local->ops->tdls_channel_switch || | ||
769 | !local->ops->tdls_cancel_channel_switch || | ||
770 | !local->ops->tdls_recv_channel_switch)) | ||
771 | return -EOPNOTSUPP; | ||
772 | |||
767 | #ifdef CONFIG_PM | 773 | #ifdef CONFIG_PM |
768 | if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume)) | 774 | if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume)) |
769 | return -EINVAL; | 775 | return -EINVAL; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0d166e766dad..ba06cd003375 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1049,6 +1049,8 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata) | |||
1049 | sdata->csa_block_tx = false; | 1049 | sdata->csa_block_tx = false; |
1050 | } | 1050 | } |
1051 | 1051 | ||
1052 | cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef); | ||
1053 | |||
1052 | sdata->vif.csa_active = false; | 1054 | sdata->vif.csa_active = false; |
1053 | ifmgd->csa_waiting_bcn = false; | 1055 | ifmgd->csa_waiting_bcn = false; |
1054 | 1056 | ||
@@ -1205,6 +1207,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1205 | IEEE80211_QUEUE_STOP_REASON_CSA); | 1207 | IEEE80211_QUEUE_STOP_REASON_CSA); |
1206 | mutex_unlock(&local->mtx); | 1208 | mutex_unlock(&local->mtx); |
1207 | 1209 | ||
1210 | cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chandef, | ||
1211 | csa_ie.count); | ||
1212 | |||
1208 | if (local->ops->channel_switch) { | 1213 | if (local->ops->channel_switch) { |
1209 | /* use driver's channel switch callback */ | 1214 | /* use driver's channel switch callback */ |
1210 | drv_channel_switch(local, sdata, &ch_switch); | 1215 | drv_channel_switch(local, sdata, &ch_switch); |
@@ -2221,7 +2226,8 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
2221 | else | 2226 | else |
2222 | ssid_len = ssid[1]; | 2227 | ssid_len = ssid[1]; |
2223 | 2228 | ||
2224 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid_len, NULL, | 2229 | ieee80211_send_probe_req(sdata, sdata->vif.addr, NULL, |
2230 | ssid + 2, ssid_len, NULL, | ||
2225 | 0, (u32) -1, true, 0, | 2231 | 0, (u32) -1, true, 0, |
2226 | ifmgd->associated->channel, false); | 2232 | ifmgd->associated->channel, false); |
2227 | rcu_read_unlock(); | 2233 | rcu_read_unlock(); |
@@ -2324,7 +2330,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
2324 | else | 2330 | else |
2325 | ssid_len = ssid[1]; | 2331 | ssid_len = ssid[1]; |
2326 | 2332 | ||
2327 | skb = ieee80211_build_probe_req(sdata, cbss->bssid, | 2333 | skb = ieee80211_build_probe_req(sdata, sdata->vif.addr, cbss->bssid, |
2328 | (u32) -1, cbss->channel, | 2334 | (u32) -1, cbss->channel, |
2329 | ssid + 2, ssid_len, | 2335 | ssid + 2, ssid_len, |
2330 | NULL, 0, true); | 2336 | NULL, 0, true); |
@@ -2798,6 +2804,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2798 | } | 2804 | } |
2799 | 2805 | ||
2800 | ifmgd->aid = aid; | 2806 | ifmgd->aid = aid; |
2807 | ifmgd->tdls_chan_switch_prohibited = | ||
2808 | elems.ext_capab && elems.ext_capab_len >= 5 && | ||
2809 | (elems.ext_capab[4] & WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED); | ||
2801 | 2810 | ||
2802 | /* | 2811 | /* |
2803 | * Some APs are erroneously not including some information in their | 2812 | * Some APs are erroneously not including some information in their |
@@ -3642,7 +3651,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | |||
3642 | * Direct probe is sent to broadcast address as some APs | 3651 | * Direct probe is sent to broadcast address as some APs |
3643 | * will not answer to direct packet in unassociated state. | 3652 | * will not answer to direct packet in unassociated state. |
3644 | */ | 3653 | */ |
3645 | ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], | 3654 | ieee80211_send_probe_req(sdata, sdata->vif.addr, NULL, |
3655 | ssidie + 2, ssidie[1], | ||
3646 | NULL, 0, (u32) -1, true, 0, | 3656 | NULL, 0, (u32) -1, true, 0, |
3647 | auth_data->bss->channel, false); | 3657 | auth_data->bss->channel, false); |
3648 | rcu_read_unlock(); | 3658 | rcu_read_unlock(); |
@@ -3999,6 +4009,11 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
3999 | ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC; | 4009 | ifmgd->req_smps = IEEE80211_SMPS_AUTOMATIC; |
4000 | else | 4010 | else |
4001 | ifmgd->req_smps = IEEE80211_SMPS_OFF; | 4011 | ifmgd->req_smps = IEEE80211_SMPS_OFF; |
4012 | |||
4013 | /* Setup TDLS data */ | ||
4014 | spin_lock_init(&ifmgd->teardown_lock); | ||
4015 | ifmgd->teardown_skb = NULL; | ||
4016 | ifmgd->orig_teardown_skb = NULL; | ||
4002 | } | 4017 | } |
4003 | 4018 | ||
4004 | /* scan finished notification */ | 4019 | /* scan finished notification */ |
@@ -4861,6 +4876,13 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) | |||
4861 | } | 4876 | } |
4862 | if (ifmgd->auth_data) | 4877 | if (ifmgd->auth_data) |
4863 | ieee80211_destroy_auth_data(sdata, false); | 4878 | ieee80211_destroy_auth_data(sdata, false); |
4879 | spin_lock_bh(&ifmgd->teardown_lock); | ||
4880 | if (ifmgd->teardown_skb) { | ||
4881 | kfree_skb(ifmgd->teardown_skb); | ||
4882 | ifmgd->teardown_skb = NULL; | ||
4883 | ifmgd->orig_teardown_skb = NULL; | ||
4884 | } | ||
4885 | spin_unlock_bh(&ifmgd->teardown_lock); | ||
4864 | del_timer_sync(&ifmgd->timer); | 4886 | del_timer_sync(&ifmgd->timer); |
4865 | sdata_unlock(sdata); | 4887 | sdata_unlock(sdata); |
4866 | } | 4888 | } |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 6081329784dd..08ab7d6d1517 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -385,7 +385,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate, | |||
385 | *rate = alt_rate; | 385 | *rate = alt_rate; |
386 | return; | 386 | return; |
387 | } | 387 | } |
388 | } else { | 388 | } else if (!(rate->flags & IEEE80211_TX_RC_VHT_MCS)) { |
389 | /* handle legacy rates */ | 389 | /* handle legacy rates */ |
390 | if (rate_idx_match_legacy_mask(rate, sband->n_bitrates, mask)) | 390 | if (rate_idx_match_legacy_mask(rate, sband->n_bitrates, mask)) |
391 | return; | 391 | return; |
@@ -696,6 +696,7 @@ int rate_control_set_rates(struct ieee80211_hw *hw, | |||
696 | struct ieee80211_sta *pubsta, | 696 | struct ieee80211_sta *pubsta, |
697 | struct ieee80211_sta_rates *rates) | 697 | struct ieee80211_sta_rates *rates) |
698 | { | 698 | { |
699 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
699 | struct ieee80211_sta_rates *old; | 700 | struct ieee80211_sta_rates *old; |
700 | 701 | ||
701 | /* | 702 | /* |
@@ -709,6 +710,8 @@ int rate_control_set_rates(struct ieee80211_hw *hw, | |||
709 | if (old) | 710 | if (old) |
710 | kfree_rcu(old, rcu_head); | 711 | kfree_rcu(old, rcu_head); |
711 | 712 | ||
713 | drv_sta_rate_tbl_update(hw_to_local(hw), sta->sdata, pubsta); | ||
714 | |||
712 | return 0; | 715 | return 0; |
713 | } | 716 | } |
714 | EXPORT_SYMBOL(rate_control_set_rates); | 717 | EXPORT_SYMBOL(rate_control_set_rates); |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index c50fd94d2aef..62ff7cfb2723 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -690,6 +690,9 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) | |||
690 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | 690 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); |
691 | u16 tid; | 691 | u16 tid; |
692 | 692 | ||
693 | if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) | ||
694 | return; | ||
695 | |||
693 | if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) | 696 | if (unlikely(!ieee80211_is_data_qos(hdr->frame_control))) |
694 | return; | 697 | return; |
695 | 698 | ||
@@ -700,9 +703,6 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) | |||
700 | if (likely(sta->ampdu_mlme.tid_tx[tid])) | 703 | if (likely(sta->ampdu_mlme.tid_tx[tid])) |
701 | return; | 704 | return; |
702 | 705 | ||
703 | if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) | ||
704 | return; | ||
705 | |||
706 | ieee80211_start_tx_ba_session(pubsta, tid, 5000); | 706 | ieee80211_start_tx_ba_session(pubsta, tid, 5000); |
707 | } | 707 | } |
708 | 708 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a726bb169302..49c23bdf08bb 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -39,7 +39,8 @@ | |||
39 | * only useful for monitoring. | 39 | * only useful for monitoring. |
40 | */ | 40 | */ |
41 | static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | 41 | static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, |
42 | struct sk_buff *skb) | 42 | struct sk_buff *skb, |
43 | unsigned int rtap_vendor_space) | ||
43 | { | 44 | { |
44 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { | 45 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { |
45 | if (likely(skb->len > FCS_LEN)) | 46 | if (likely(skb->len > FCS_LEN)) |
@@ -52,20 +53,25 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | |||
52 | } | 53 | } |
53 | } | 54 | } |
54 | 55 | ||
56 | __pskb_pull(skb, rtap_vendor_space); | ||
57 | |||
55 | return skb; | 58 | return skb; |
56 | } | 59 | } |
57 | 60 | ||
58 | static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len) | 61 | static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len, |
62 | unsigned int rtap_vendor_space) | ||
59 | { | 63 | { |
60 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 64 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
61 | struct ieee80211_hdr *hdr = (void *)skb->data; | 65 | struct ieee80211_hdr *hdr; |
66 | |||
67 | hdr = (void *)(skb->data + rtap_vendor_space); | ||
62 | 68 | ||
63 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | | 69 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | |
64 | RX_FLAG_FAILED_PLCP_CRC | | 70 | RX_FLAG_FAILED_PLCP_CRC | |
65 | RX_FLAG_AMPDU_IS_ZEROLEN)) | 71 | RX_FLAG_AMPDU_IS_ZEROLEN)) |
66 | return true; | 72 | return true; |
67 | 73 | ||
68 | if (unlikely(skb->len < 16 + present_fcs_len)) | 74 | if (unlikely(skb->len < 16 + present_fcs_len + rtap_vendor_space)) |
69 | return true; | 75 | return true; |
70 | 76 | ||
71 | if (ieee80211_is_ctl(hdr->frame_control) && | 77 | if (ieee80211_is_ctl(hdr->frame_control) && |
@@ -77,8 +83,9 @@ static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len) | |||
77 | } | 83 | } |
78 | 84 | ||
79 | static int | 85 | static int |
80 | ieee80211_rx_radiotap_space(struct ieee80211_local *local, | 86 | ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local, |
81 | struct ieee80211_rx_status *status) | 87 | struct ieee80211_rx_status *status, |
88 | struct sk_buff *skb) | ||
82 | { | 89 | { |
83 | int len; | 90 | int len; |
84 | 91 | ||
@@ -121,6 +128,21 @@ ieee80211_rx_radiotap_space(struct ieee80211_local *local, | |||
121 | len += 2 * hweight8(status->chains); | 128 | len += 2 * hweight8(status->chains); |
122 | } | 129 | } |
123 | 130 | ||
131 | if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { | ||
132 | struct ieee80211_vendor_radiotap *rtap = (void *)skb->data; | ||
133 | |||
134 | /* vendor presence bitmap */ | ||
135 | len += 4; | ||
136 | /* alignment for fixed 6-byte vendor data header */ | ||
137 | len = ALIGN(len, 2); | ||
138 | /* vendor data header */ | ||
139 | len += 6; | ||
140 | if (WARN_ON(rtap->align == 0)) | ||
141 | rtap->align = 1; | ||
142 | len = ALIGN(len, rtap->align); | ||
143 | len += rtap->len + rtap->pad; | ||
144 | } | ||
145 | |||
124 | return len; | 146 | return len; |
125 | } | 147 | } |
126 | 148 | ||
@@ -144,13 +166,20 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
144 | u16 channel_flags = 0; | 166 | u16 channel_flags = 0; |
145 | int mpdulen, chain; | 167 | int mpdulen, chain; |
146 | unsigned long chains = status->chains; | 168 | unsigned long chains = status->chains; |
169 | struct ieee80211_vendor_radiotap rtap = {}; | ||
170 | |||
171 | if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { | ||
172 | rtap = *(struct ieee80211_vendor_radiotap *)skb->data; | ||
173 | /* rtap.len and rtap.pad are undone immediately */ | ||
174 | skb_pull(skb, sizeof(rtap) + rtap.len + rtap.pad); | ||
175 | } | ||
147 | 176 | ||
148 | mpdulen = skb->len; | 177 | mpdulen = skb->len; |
149 | if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))) | 178 | if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS))) |
150 | mpdulen += FCS_LEN; | 179 | mpdulen += FCS_LEN; |
151 | 180 | ||
152 | rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); | 181 | rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); |
153 | memset(rthdr, 0, rtap_len); | 182 | memset(rthdr, 0, rtap_len - rtap.len - rtap.pad); |
154 | it_present = &rthdr->it_present; | 183 | it_present = &rthdr->it_present; |
155 | 184 | ||
156 | /* radiotap header, set always present flags */ | 185 | /* radiotap header, set always present flags */ |
@@ -172,6 +201,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
172 | BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL); | 201 | BIT(IEEE80211_RADIOTAP_DBM_ANTSIGNAL); |
173 | } | 202 | } |
174 | 203 | ||
204 | if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { | ||
205 | it_present_val |= BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE) | | ||
206 | BIT(IEEE80211_RADIOTAP_EXT); | ||
207 | put_unaligned_le32(it_present_val, it_present); | ||
208 | it_present++; | ||
209 | it_present_val = rtap.present; | ||
210 | } | ||
211 | |||
175 | put_unaligned_le32(it_present_val, it_present); | 212 | put_unaligned_le32(it_present_val, it_present); |
176 | 213 | ||
177 | pos = (void *)(it_present + 1); | 214 | pos = (void *)(it_present + 1); |
@@ -366,6 +403,22 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
366 | *pos++ = status->chain_signal[chain]; | 403 | *pos++ = status->chain_signal[chain]; |
367 | *pos++ = chain; | 404 | *pos++ = chain; |
368 | } | 405 | } |
406 | |||
407 | if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) { | ||
408 | /* ensure 2 byte alignment for the vendor field as required */ | ||
409 | if ((pos - (u8 *)rthdr) & 1) | ||
410 | *pos++ = 0; | ||
411 | *pos++ = rtap.oui[0]; | ||
412 | *pos++ = rtap.oui[1]; | ||
413 | *pos++ = rtap.oui[2]; | ||
414 | *pos++ = rtap.subns; | ||
415 | put_unaligned_le16(rtap.len, pos); | ||
416 | pos += 2; | ||
417 | /* align the actual payload as requested */ | ||
418 | while ((pos - (u8 *)rthdr) & (rtap.align - 1)) | ||
419 | *pos++ = 0; | ||
420 | /* data (and possible padding) already follows */ | ||
421 | } | ||
369 | } | 422 | } |
370 | 423 | ||
371 | /* | 424 | /* |
@@ -379,10 +432,17 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
379 | { | 432 | { |
380 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb); | 433 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(origskb); |
381 | struct ieee80211_sub_if_data *sdata; | 434 | struct ieee80211_sub_if_data *sdata; |
382 | int needed_headroom; | 435 | int rt_hdrlen, needed_headroom; |
383 | struct sk_buff *skb, *skb2; | 436 | struct sk_buff *skb, *skb2; |
384 | struct net_device *prev_dev = NULL; | 437 | struct net_device *prev_dev = NULL; |
385 | int present_fcs_len = 0; | 438 | int present_fcs_len = 0; |
439 | unsigned int rtap_vendor_space = 0; | ||
440 | |||
441 | if (unlikely(status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)) { | ||
442 | struct ieee80211_vendor_radiotap *rtap = (void *)origskb->data; | ||
443 | |||
444 | rtap_vendor_space = sizeof(*rtap) + rtap->len + rtap->pad; | ||
445 | } | ||
386 | 446 | ||
387 | /* | 447 | /* |
388 | * First, we may need to make a copy of the skb because | 448 | * First, we may need to make a copy of the skb because |
@@ -396,25 +456,27 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
396 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | 456 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) |
397 | present_fcs_len = FCS_LEN; | 457 | present_fcs_len = FCS_LEN; |
398 | 458 | ||
399 | /* ensure hdr->frame_control is in skb head */ | 459 | /* ensure hdr->frame_control and vendor radiotap data are in skb head */ |
400 | if (!pskb_may_pull(origskb, 2)) { | 460 | if (!pskb_may_pull(origskb, 2 + rtap_vendor_space)) { |
401 | dev_kfree_skb(origskb); | 461 | dev_kfree_skb(origskb); |
402 | return NULL; | 462 | return NULL; |
403 | } | 463 | } |
404 | 464 | ||
405 | if (!local->monitors) { | 465 | if (!local->monitors) { |
406 | if (should_drop_frame(origskb, present_fcs_len)) { | 466 | if (should_drop_frame(origskb, present_fcs_len, |
467 | rtap_vendor_space)) { | ||
407 | dev_kfree_skb(origskb); | 468 | dev_kfree_skb(origskb); |
408 | return NULL; | 469 | return NULL; |
409 | } | 470 | } |
410 | 471 | ||
411 | return remove_monitor_info(local, origskb); | 472 | return remove_monitor_info(local, origskb, rtap_vendor_space); |
412 | } | 473 | } |
413 | 474 | ||
414 | /* room for the radiotap header based on driver features */ | 475 | /* room for the radiotap header based on driver features */ |
415 | needed_headroom = ieee80211_rx_radiotap_space(local, status); | 476 | rt_hdrlen = ieee80211_rx_radiotap_hdrlen(local, status, origskb); |
477 | needed_headroom = rt_hdrlen - rtap_vendor_space; | ||
416 | 478 | ||
417 | if (should_drop_frame(origskb, present_fcs_len)) { | 479 | if (should_drop_frame(origskb, present_fcs_len, rtap_vendor_space)) { |
418 | /* only need to expand headroom if necessary */ | 480 | /* only need to expand headroom if necessary */ |
419 | skb = origskb; | 481 | skb = origskb; |
420 | origskb = NULL; | 482 | origskb = NULL; |
@@ -438,15 +500,15 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
438 | */ | 500 | */ |
439 | skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC); | 501 | skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC); |
440 | 502 | ||
441 | origskb = remove_monitor_info(local, origskb); | 503 | origskb = remove_monitor_info(local, origskb, |
504 | rtap_vendor_space); | ||
442 | 505 | ||
443 | if (!skb) | 506 | if (!skb) |
444 | return origskb; | 507 | return origskb; |
445 | } | 508 | } |
446 | 509 | ||
447 | /* prepend radiotap information */ | 510 | /* prepend radiotap information */ |
448 | ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom, | 511 | ieee80211_add_rx_radiotap_header(local, skb, rate, rt_hdrlen, true); |
449 | true); | ||
450 | 512 | ||
451 | skb_reset_mac_header(skb); | 513 | skb_reset_mac_header(skb); |
452 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 514 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
@@ -985,7 +1047,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx, | |||
985 | } | 1047 | } |
986 | 1048 | ||
987 | static ieee80211_rx_result debug_noinline | 1049 | static ieee80211_rx_result debug_noinline |
988 | ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | 1050 | ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx) |
989 | { | 1051 | { |
990 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1052 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
991 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | 1053 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
@@ -994,10 +1056,16 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
994 | * Drop duplicate 802.11 retransmissions | 1056 | * Drop duplicate 802.11 retransmissions |
995 | * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") | 1057 | * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery") |
996 | */ | 1058 | */ |
997 | if (rx->skb->len >= 24 && rx->sta && | 1059 | |
998 | !ieee80211_is_ctl(hdr->frame_control) && | 1060 | if (rx->skb->len < 24) |
999 | !ieee80211_is_qos_nullfunc(hdr->frame_control) && | 1061 | return RX_CONTINUE; |
1000 | !is_multicast_ether_addr(hdr->addr1)) { | 1062 | |
1063 | if (ieee80211_is_ctl(hdr->frame_control) || | ||
1064 | ieee80211_is_qos_nullfunc(hdr->frame_control) || | ||
1065 | is_multicast_ether_addr(hdr->addr1)) | ||
1066 | return RX_CONTINUE; | ||
1067 | |||
1068 | if (rx->sta) { | ||
1001 | if (unlikely(ieee80211_has_retry(hdr->frame_control) && | 1069 | if (unlikely(ieee80211_has_retry(hdr->frame_control) && |
1002 | rx->sta->last_seq_ctrl[rx->seqno_idx] == | 1070 | rx->sta->last_seq_ctrl[rx->seqno_idx] == |
1003 | hdr->seq_ctrl)) { | 1071 | hdr->seq_ctrl)) { |
@@ -1011,6 +1079,14 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
1011 | } | 1079 | } |
1012 | } | 1080 | } |
1013 | 1081 | ||
1082 | return RX_CONTINUE; | ||
1083 | } | ||
1084 | |||
1085 | static ieee80211_rx_result debug_noinline | ||
1086 | ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | ||
1087 | { | ||
1088 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
1089 | |||
1014 | if (unlikely(rx->skb->len < 16)) { | 1090 | if (unlikely(rx->skb->len < 16)) { |
1015 | I802_DEBUG_INC(rx->local->rx_handlers_drop_short); | 1091 | I802_DEBUG_INC(rx->local->rx_handlers_drop_short); |
1016 | return RX_DROP_MONITOR; | 1092 | return RX_DROP_MONITOR; |
@@ -2257,6 +2333,27 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
2257 | if (!ieee80211_frame_allowed(rx, fc)) | 2333 | if (!ieee80211_frame_allowed(rx, fc)) |
2258 | return RX_DROP_MONITOR; | 2334 | return RX_DROP_MONITOR; |
2259 | 2335 | ||
2336 | /* directly handle TDLS channel switch requests/responses */ | ||
2337 | if (unlikely(((struct ethhdr *)rx->skb->data)->h_proto == | ||
2338 | cpu_to_be16(ETH_P_TDLS))) { | ||
2339 | struct ieee80211_tdls_data *tf = (void *)rx->skb->data; | ||
2340 | |||
2341 | if (pskb_may_pull(rx->skb, | ||
2342 | offsetof(struct ieee80211_tdls_data, u)) && | ||
2343 | tf->payload_type == WLAN_TDLS_SNAP_RFTYPE && | ||
2344 | tf->category == WLAN_CATEGORY_TDLS && | ||
2345 | (tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST || | ||
2346 | tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE)) { | ||
2347 | rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TDLS_CHSW; | ||
2348 | skb_queue_tail(&sdata->skb_queue, rx->skb); | ||
2349 | ieee80211_queue_work(&rx->local->hw, &sdata->work); | ||
2350 | if (rx->sta) | ||
2351 | rx->sta->rx_packets++; | ||
2352 | |||
2353 | return RX_QUEUED; | ||
2354 | } | ||
2355 | } | ||
2356 | |||
2260 | if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && | 2357 | if (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && |
2261 | unlikely(port_control) && sdata->bss) { | 2358 | unlikely(port_control) && sdata->bss) { |
2262 | sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, | 2359 | sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, |
@@ -2892,8 +2989,10 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, | |||
2892 | if (!local->cooked_mntrs) | 2989 | if (!local->cooked_mntrs) |
2893 | goto out_free_skb; | 2990 | goto out_free_skb; |
2894 | 2991 | ||
2992 | /* vendor data is long removed here */ | ||
2993 | status->flag &= ~RX_FLAG_RADIOTAP_VENDOR_DATA; | ||
2895 | /* room for the radiotap header based on driver features */ | 2994 | /* room for the radiotap header based on driver features */ |
2896 | needed_headroom = ieee80211_rx_radiotap_space(local, status); | 2995 | needed_headroom = ieee80211_rx_radiotap_hdrlen(local, status, skb); |
2897 | 2996 | ||
2898 | if (skb_headroom(skb) < needed_headroom && | 2997 | if (skb_headroom(skb) < needed_headroom && |
2899 | pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) | 2998 | pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) |
@@ -3046,6 +3145,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) | |||
3046 | goto rxh_next; \ | 3145 | goto rxh_next; \ |
3047 | } while (0); | 3146 | } while (0); |
3048 | 3147 | ||
3148 | CALL_RXH(ieee80211_rx_h_check_dup) | ||
3049 | CALL_RXH(ieee80211_rx_h_check) | 3149 | CALL_RXH(ieee80211_rx_h_check) |
3050 | 3150 | ||
3051 | ieee80211_rx_reorder_ampdu(rx, &reorder_release); | 3151 | ieee80211_rx_reorder_ampdu(rx, &reorder_release); |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index af0d094b2f2f..ae842678b629 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -184,9 +184,21 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) | |||
184 | return; | 184 | return; |
185 | 185 | ||
186 | if (ieee80211_is_probe_resp(mgmt->frame_control)) { | 186 | if (ieee80211_is_probe_resp(mgmt->frame_control)) { |
187 | /* ignore ProbeResp to foreign address */ | 187 | struct cfg80211_scan_request *scan_req; |
188 | if ((!sdata1 || !ether_addr_equal(mgmt->da, sdata1->vif.addr)) && | 188 | struct cfg80211_sched_scan_request *sched_scan_req; |
189 | (!sdata2 || !ether_addr_equal(mgmt->da, sdata2->vif.addr))) | 189 | |
190 | scan_req = rcu_dereference(local->scan_req); | ||
191 | sched_scan_req = rcu_dereference(local->sched_scan_req); | ||
192 | |||
193 | /* ignore ProbeResp to foreign address unless scanning | ||
194 | * with randomised address | ||
195 | */ | ||
196 | if (!(sdata1 && | ||
197 | (ether_addr_equal(mgmt->da, sdata1->vif.addr) || | ||
198 | scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) && | ||
199 | !(sdata2 && | ||
200 | (ether_addr_equal(mgmt->da, sdata2->vif.addr) || | ||
201 | sched_scan_req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR))) | ||
190 | return; | 202 | return; |
191 | 203 | ||
192 | elements = mgmt->u.probe_resp.variable; | 204 | elements = mgmt->u.probe_resp.variable; |
@@ -234,11 +246,14 @@ ieee80211_prepare_scan_chandef(struct cfg80211_chan_def *chandef, | |||
234 | /* return false if no more work */ | 246 | /* return false if no more work */ |
235 | static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | 247 | static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) |
236 | { | 248 | { |
237 | struct cfg80211_scan_request *req = local->scan_req; | 249 | struct cfg80211_scan_request *req; |
238 | struct cfg80211_chan_def chandef; | 250 | struct cfg80211_chan_def chandef; |
239 | u8 bands_used = 0; | 251 | u8 bands_used = 0; |
240 | int i, ielen, n_chans; | 252 | int i, ielen, n_chans; |
241 | 253 | ||
254 | req = rcu_dereference_protected(local->scan_req, | ||
255 | lockdep_is_held(&local->mtx)); | ||
256 | |||
242 | if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) | 257 | if (test_bit(SCAN_HW_CANCELLED, &local->scanning)) |
243 | return false; | 258 | return false; |
244 | 259 | ||
@@ -281,6 +296,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | |||
281 | bands_used, req->rates, &chandef); | 296 | bands_used, req->rates, &chandef); |
282 | local->hw_scan_req->req.ie_len = ielen; | 297 | local->hw_scan_req->req.ie_len = ielen; |
283 | local->hw_scan_req->req.no_cck = req->no_cck; | 298 | local->hw_scan_req->req.no_cck = req->no_cck; |
299 | ether_addr_copy(local->hw_scan_req->req.mac_addr, req->mac_addr); | ||
300 | ether_addr_copy(local->hw_scan_req->req.mac_addr_mask, | ||
301 | req->mac_addr_mask); | ||
284 | 302 | ||
285 | return true; | 303 | return true; |
286 | } | 304 | } |
@@ -290,6 +308,8 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
290 | struct ieee80211_local *local = hw_to_local(hw); | 308 | struct ieee80211_local *local = hw_to_local(hw); |
291 | bool hw_scan = local->ops->hw_scan; | 309 | bool hw_scan = local->ops->hw_scan; |
292 | bool was_scanning = local->scanning; | 310 | bool was_scanning = local->scanning; |
311 | struct cfg80211_scan_request *scan_req; | ||
312 | struct ieee80211_sub_if_data *scan_sdata; | ||
293 | 313 | ||
294 | lockdep_assert_held(&local->mtx); | 314 | lockdep_assert_held(&local->mtx); |
295 | 315 | ||
@@ -322,9 +342,15 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
322 | kfree(local->hw_scan_req); | 342 | kfree(local->hw_scan_req); |
323 | local->hw_scan_req = NULL; | 343 | local->hw_scan_req = NULL; |
324 | 344 | ||
325 | if (local->scan_req != local->int_scan_req) | 345 | scan_req = rcu_dereference_protected(local->scan_req, |
326 | cfg80211_scan_done(local->scan_req, aborted); | 346 | lockdep_is_held(&local->mtx)); |
327 | local->scan_req = NULL; | 347 | |
348 | if (scan_req != local->int_scan_req) | ||
349 | cfg80211_scan_done(scan_req, aborted); | ||
350 | RCU_INIT_POINTER(local->scan_req, NULL); | ||
351 | |||
352 | scan_sdata = rcu_dereference_protected(local->scan_sdata, | ||
353 | lockdep_is_held(&local->mtx)); | ||
328 | RCU_INIT_POINTER(local->scan_sdata, NULL); | 354 | RCU_INIT_POINTER(local->scan_sdata, NULL); |
329 | 355 | ||
330 | local->scanning = 0; | 356 | local->scanning = 0; |
@@ -335,7 +361,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
335 | 361 | ||
336 | if (!hw_scan) { | 362 | if (!hw_scan) { |
337 | ieee80211_configure_filter(local); | 363 | ieee80211_configure_filter(local); |
338 | drv_sw_scan_complete(local); | 364 | drv_sw_scan_complete(local, scan_sdata); |
339 | ieee80211_offchannel_return(local); | 365 | ieee80211_offchannel_return(local); |
340 | } | 366 | } |
341 | 367 | ||
@@ -361,7 +387,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
361 | } | 387 | } |
362 | EXPORT_SYMBOL(ieee80211_scan_completed); | 388 | EXPORT_SYMBOL(ieee80211_scan_completed); |
363 | 389 | ||
364 | static int ieee80211_start_sw_scan(struct ieee80211_local *local) | 390 | static int ieee80211_start_sw_scan(struct ieee80211_local *local, |
391 | struct ieee80211_sub_if_data *sdata) | ||
365 | { | 392 | { |
366 | /* Software scan is not supported in multi-channel cases */ | 393 | /* Software scan is not supported in multi-channel cases */ |
367 | if (local->use_chanctx) | 394 | if (local->use_chanctx) |
@@ -380,7 +407,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) | |||
380 | * nullfunc frames and probe requests will be dropped in | 407 | * nullfunc frames and probe requests will be dropped in |
381 | * ieee80211_tx_h_check_assoc(). | 408 | * ieee80211_tx_h_check_assoc(). |
382 | */ | 409 | */ |
383 | drv_sw_scan_start(local); | 410 | drv_sw_scan_start(local, sdata, local->scan_addr); |
384 | 411 | ||
385 | local->leave_oper_channel_time = jiffies; | 412 | local->leave_oper_channel_time = jiffies; |
386 | local->next_scan_state = SCAN_DECISION; | 413 | local->next_scan_state = SCAN_DECISION; |
@@ -440,23 +467,26 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | |||
440 | { | 467 | { |
441 | int i; | 468 | int i; |
442 | struct ieee80211_sub_if_data *sdata; | 469 | struct ieee80211_sub_if_data *sdata; |
470 | struct cfg80211_scan_request *scan_req; | ||
443 | enum ieee80211_band band = local->hw.conf.chandef.chan->band; | 471 | enum ieee80211_band band = local->hw.conf.chandef.chan->band; |
444 | u32 tx_flags; | 472 | u32 tx_flags; |
445 | 473 | ||
474 | scan_req = rcu_dereference_protected(local->scan_req, | ||
475 | lockdep_is_held(&local->mtx)); | ||
476 | |||
446 | tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK; | 477 | tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK; |
447 | if (local->scan_req->no_cck) | 478 | if (scan_req->no_cck) |
448 | tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE; | 479 | tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE; |
449 | 480 | ||
450 | sdata = rcu_dereference_protected(local->scan_sdata, | 481 | sdata = rcu_dereference_protected(local->scan_sdata, |
451 | lockdep_is_held(&local->mtx)); | 482 | lockdep_is_held(&local->mtx)); |
452 | 483 | ||
453 | for (i = 0; i < local->scan_req->n_ssids; i++) | 484 | for (i = 0; i < scan_req->n_ssids; i++) |
454 | ieee80211_send_probe_req( | 485 | ieee80211_send_probe_req( |
455 | sdata, NULL, | 486 | sdata, local->scan_addr, NULL, |
456 | local->scan_req->ssids[i].ssid, | 487 | scan_req->ssids[i].ssid, scan_req->ssids[i].ssid_len, |
457 | local->scan_req->ssids[i].ssid_len, | 488 | scan_req->ie, scan_req->ie_len, |
458 | local->scan_req->ie, local->scan_req->ie_len, | 489 | scan_req->rates[band], false, |
459 | local->scan_req->rates[band], false, | ||
460 | tx_flags, local->hw.conf.chandef.chan, true); | 490 | tx_flags, local->hw.conf.chandef.chan, true); |
461 | 491 | ||
462 | /* | 492 | /* |
@@ -480,7 +510,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
480 | 510 | ||
481 | if (!ieee80211_can_scan(local, sdata)) { | 511 | if (!ieee80211_can_scan(local, sdata)) { |
482 | /* wait for the work to finish/time out */ | 512 | /* wait for the work to finish/time out */ |
483 | local->scan_req = req; | 513 | rcu_assign_pointer(local->scan_req, req); |
484 | rcu_assign_pointer(local->scan_sdata, sdata); | 514 | rcu_assign_pointer(local->scan_sdata, sdata); |
485 | return 0; | 515 | return 0; |
486 | } | 516 | } |
@@ -530,9 +560,16 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
530 | */ | 560 | */ |
531 | } | 561 | } |
532 | 562 | ||
533 | local->scan_req = req; | 563 | rcu_assign_pointer(local->scan_req, req); |
534 | rcu_assign_pointer(local->scan_sdata, sdata); | 564 | rcu_assign_pointer(local->scan_sdata, sdata); |
535 | 565 | ||
566 | if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) | ||
567 | get_random_mask_addr(local->scan_addr, | ||
568 | req->mac_addr, | ||
569 | req->mac_addr_mask); | ||
570 | else | ||
571 | memcpy(local->scan_addr, sdata->vif.addr, ETH_ALEN); | ||
572 | |||
536 | if (local->ops->hw_scan) { | 573 | if (local->ops->hw_scan) { |
537 | __set_bit(SCAN_HW_SCANNING, &local->scanning); | 574 | __set_bit(SCAN_HW_SCANNING, &local->scanning); |
538 | } else if ((req->n_channels == 1) && | 575 | } else if ((req->n_channels == 1) && |
@@ -549,7 +586,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
549 | 586 | ||
550 | /* Notify driver scan is starting, keep order of operations | 587 | /* Notify driver scan is starting, keep order of operations |
551 | * same as normal software scan, in case that matters. */ | 588 | * same as normal software scan, in case that matters. */ |
552 | drv_sw_scan_start(local); | 589 | drv_sw_scan_start(local, sdata, local->scan_addr); |
553 | 590 | ||
554 | ieee80211_configure_filter(local); /* accept probe-responses */ | 591 | ieee80211_configure_filter(local); /* accept probe-responses */ |
555 | 592 | ||
@@ -558,7 +595,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
558 | 595 | ||
559 | if ((req->channels[0]->flags & | 596 | if ((req->channels[0]->flags & |
560 | IEEE80211_CHAN_NO_IR) || | 597 | IEEE80211_CHAN_NO_IR) || |
561 | !local->scan_req->n_ssids) { | 598 | !req->n_ssids) { |
562 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; | 599 | next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; |
563 | } else { | 600 | } else { |
564 | ieee80211_scan_state_send_probe(local, &next_delay); | 601 | ieee80211_scan_state_send_probe(local, &next_delay); |
@@ -579,8 +616,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
579 | if (local->ops->hw_scan) { | 616 | if (local->ops->hw_scan) { |
580 | WARN_ON(!ieee80211_prep_hw_scan(local)); | 617 | WARN_ON(!ieee80211_prep_hw_scan(local)); |
581 | rc = drv_hw_scan(local, sdata, local->hw_scan_req); | 618 | rc = drv_hw_scan(local, sdata, local->hw_scan_req); |
582 | } else | 619 | } else { |
583 | rc = ieee80211_start_sw_scan(local); | 620 | rc = ieee80211_start_sw_scan(local, sdata); |
621 | } | ||
584 | 622 | ||
585 | if (rc) { | 623 | if (rc) { |
586 | kfree(local->hw_scan_req); | 624 | kfree(local->hw_scan_req); |
@@ -617,6 +655,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
617 | struct ieee80211_sub_if_data *sdata; | 655 | struct ieee80211_sub_if_data *sdata; |
618 | struct ieee80211_channel *next_chan; | 656 | struct ieee80211_channel *next_chan; |
619 | enum mac80211_scan_state next_scan_state; | 657 | enum mac80211_scan_state next_scan_state; |
658 | struct cfg80211_scan_request *scan_req; | ||
620 | 659 | ||
621 | /* | 660 | /* |
622 | * check if at least one STA interface is associated, | 661 | * check if at least one STA interface is associated, |
@@ -641,7 +680,10 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
641 | } | 680 | } |
642 | mutex_unlock(&local->iflist_mtx); | 681 | mutex_unlock(&local->iflist_mtx); |
643 | 682 | ||
644 | next_chan = local->scan_req->channels[local->scan_channel_idx]; | 683 | scan_req = rcu_dereference_protected(local->scan_req, |
684 | lockdep_is_held(&local->mtx)); | ||
685 | |||
686 | next_chan = scan_req->channels[local->scan_channel_idx]; | ||
645 | 687 | ||
646 | /* | 688 | /* |
647 | * we're currently scanning a different channel, let's | 689 | * we're currently scanning a different channel, let's |
@@ -656,7 +698,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
656 | local->leave_oper_channel_time + HZ / 8); | 698 | local->leave_oper_channel_time + HZ / 8); |
657 | 699 | ||
658 | if (associated && !tx_empty) { | 700 | if (associated && !tx_empty) { |
659 | if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) | 701 | if (scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) |
660 | next_scan_state = SCAN_ABORT; | 702 | next_scan_state = SCAN_ABORT; |
661 | else | 703 | else |
662 | next_scan_state = SCAN_SUSPEND; | 704 | next_scan_state = SCAN_SUSPEND; |
@@ -677,14 +719,18 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, | |||
677 | int skip; | 719 | int skip; |
678 | struct ieee80211_channel *chan; | 720 | struct ieee80211_channel *chan; |
679 | enum nl80211_bss_scan_width oper_scan_width; | 721 | enum nl80211_bss_scan_width oper_scan_width; |
722 | struct cfg80211_scan_request *scan_req; | ||
723 | |||
724 | scan_req = rcu_dereference_protected(local->scan_req, | ||
725 | lockdep_is_held(&local->mtx)); | ||
680 | 726 | ||
681 | skip = 0; | 727 | skip = 0; |
682 | chan = local->scan_req->channels[local->scan_channel_idx]; | 728 | chan = scan_req->channels[local->scan_channel_idx]; |
683 | 729 | ||
684 | local->scan_chandef.chan = chan; | 730 | local->scan_chandef.chan = chan; |
685 | local->scan_chandef.center_freq1 = chan->center_freq; | 731 | local->scan_chandef.center_freq1 = chan->center_freq; |
686 | local->scan_chandef.center_freq2 = 0; | 732 | local->scan_chandef.center_freq2 = 0; |
687 | switch (local->scan_req->scan_width) { | 733 | switch (scan_req->scan_width) { |
688 | case NL80211_BSS_CHAN_WIDTH_5: | 734 | case NL80211_BSS_CHAN_WIDTH_5: |
689 | local->scan_chandef.width = NL80211_CHAN_WIDTH_5; | 735 | local->scan_chandef.width = NL80211_CHAN_WIDTH_5; |
690 | break; | 736 | break; |
@@ -698,7 +744,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, | |||
698 | oper_scan_width = cfg80211_chandef_to_scan_width( | 744 | oper_scan_width = cfg80211_chandef_to_scan_width( |
699 | &local->_oper_chandef); | 745 | &local->_oper_chandef); |
700 | if (chan == local->_oper_chandef.chan && | 746 | if (chan == local->_oper_chandef.chan && |
701 | oper_scan_width == local->scan_req->scan_width) | 747 | oper_scan_width == scan_req->scan_width) |
702 | local->scan_chandef = local->_oper_chandef; | 748 | local->scan_chandef = local->_oper_chandef; |
703 | else | 749 | else |
704 | local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT; | 750 | local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT; |
@@ -727,8 +773,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, | |||
727 | * | 773 | * |
728 | * In any case, it is not necessary for a passive scan. | 774 | * In any case, it is not necessary for a passive scan. |
729 | */ | 775 | */ |
730 | if (chan->flags & IEEE80211_CHAN_NO_IR || | 776 | if (chan->flags & IEEE80211_CHAN_NO_IR || !scan_req->n_ssids) { |
731 | !local->scan_req->n_ssids) { | ||
732 | *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; | 777 | *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; |
733 | local->next_scan_state = SCAN_DECISION; | 778 | local->next_scan_state = SCAN_DECISION; |
734 | return; | 779 | return; |
@@ -777,6 +822,7 @@ void ieee80211_scan_work(struct work_struct *work) | |||
777 | struct ieee80211_local *local = | 822 | struct ieee80211_local *local = |
778 | container_of(work, struct ieee80211_local, scan_work.work); | 823 | container_of(work, struct ieee80211_local, scan_work.work); |
779 | struct ieee80211_sub_if_data *sdata; | 824 | struct ieee80211_sub_if_data *sdata; |
825 | struct cfg80211_scan_request *scan_req; | ||
780 | unsigned long next_delay = 0; | 826 | unsigned long next_delay = 0; |
781 | bool aborted; | 827 | bool aborted; |
782 | 828 | ||
@@ -784,6 +830,8 @@ void ieee80211_scan_work(struct work_struct *work) | |||
784 | 830 | ||
785 | sdata = rcu_dereference_protected(local->scan_sdata, | 831 | sdata = rcu_dereference_protected(local->scan_sdata, |
786 | lockdep_is_held(&local->mtx)); | 832 | lockdep_is_held(&local->mtx)); |
833 | scan_req = rcu_dereference_protected(local->scan_req, | ||
834 | lockdep_is_held(&local->mtx)); | ||
787 | 835 | ||
788 | /* When scanning on-channel, the first-callback means completed. */ | 836 | /* When scanning on-channel, the first-callback means completed. */ |
789 | if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { | 837 | if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { |
@@ -796,20 +844,19 @@ void ieee80211_scan_work(struct work_struct *work) | |||
796 | goto out_complete; | 844 | goto out_complete; |
797 | } | 845 | } |
798 | 846 | ||
799 | if (!sdata || !local->scan_req) | 847 | if (!sdata || !scan_req) |
800 | goto out; | 848 | goto out; |
801 | 849 | ||
802 | if (local->scan_req && !local->scanning) { | 850 | if (!local->scanning) { |
803 | struct cfg80211_scan_request *req = local->scan_req; | ||
804 | int rc; | 851 | int rc; |
805 | 852 | ||
806 | local->scan_req = NULL; | 853 | RCU_INIT_POINTER(local->scan_req, NULL); |
807 | RCU_INIT_POINTER(local->scan_sdata, NULL); | 854 | RCU_INIT_POINTER(local->scan_sdata, NULL); |
808 | 855 | ||
809 | rc = __ieee80211_start_scan(sdata, req); | 856 | rc = __ieee80211_start_scan(sdata, scan_req); |
810 | if (rc) { | 857 | if (rc) { |
811 | /* need to complete scan in cfg80211 */ | 858 | /* need to complete scan in cfg80211 */ |
812 | local->scan_req = req; | 859 | rcu_assign_pointer(local->scan_req, scan_req); |
813 | aborted = true; | 860 | aborted = true; |
814 | goto out_complete; | 861 | goto out_complete; |
815 | } else | 862 | } else |
@@ -829,7 +876,7 @@ void ieee80211_scan_work(struct work_struct *work) | |||
829 | switch (local->next_scan_state) { | 876 | switch (local->next_scan_state) { |
830 | case SCAN_DECISION: | 877 | case SCAN_DECISION: |
831 | /* if no more bands/channels left, complete scan */ | 878 | /* if no more bands/channels left, complete scan */ |
832 | if (local->scan_channel_idx >= local->scan_req->n_channels) { | 879 | if (local->scan_channel_idx >= scan_req->n_channels) { |
833 | aborted = false; | 880 | aborted = false; |
834 | goto out_complete; | 881 | goto out_complete; |
835 | } | 882 | } |
@@ -1043,7 +1090,7 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, | |||
1043 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); | 1090 | ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies); |
1044 | if (ret == 0) { | 1091 | if (ret == 0) { |
1045 | rcu_assign_pointer(local->sched_scan_sdata, sdata); | 1092 | rcu_assign_pointer(local->sched_scan_sdata, sdata); |
1046 | local->sched_scan_req = req; | 1093 | rcu_assign_pointer(local->sched_scan_req, req); |
1047 | } | 1094 | } |
1048 | 1095 | ||
1049 | kfree(ie); | 1096 | kfree(ie); |
@@ -1052,7 +1099,7 @@ out: | |||
1052 | if (ret) { | 1099 | if (ret) { |
1053 | /* Clean in case of failure after HW restart or upon resume. */ | 1100 | /* Clean in case of failure after HW restart or upon resume. */ |
1054 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); | 1101 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); |
1055 | local->sched_scan_req = NULL; | 1102 | RCU_INIT_POINTER(local->sched_scan_req, NULL); |
1056 | } | 1103 | } |
1057 | 1104 | ||
1058 | return ret; | 1105 | return ret; |
@@ -1090,7 +1137,7 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) | |||
1090 | } | 1137 | } |
1091 | 1138 | ||
1092 | /* We don't want to restart sched scan anymore. */ | 1139 | /* We don't want to restart sched scan anymore. */ |
1093 | local->sched_scan_req = NULL; | 1140 | RCU_INIT_POINTER(local->sched_scan_req, NULL); |
1094 | 1141 | ||
1095 | if (rcu_access_pointer(local->sched_scan_sdata)) { | 1142 | if (rcu_access_pointer(local->sched_scan_sdata)) { |
1096 | ret = drv_sched_scan_stop(local, sdata); | 1143 | ret = drv_sched_scan_stop(local, sdata); |
@@ -1125,7 +1172,7 @@ void ieee80211_sched_scan_end(struct ieee80211_local *local) | |||
1125 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); | 1172 | RCU_INIT_POINTER(local->sched_scan_sdata, NULL); |
1126 | 1173 | ||
1127 | /* If sched scan was aborted by the driver. */ | 1174 | /* If sched scan was aborted by the driver. */ |
1128 | local->sched_scan_req = NULL; | 1175 | RCU_INIT_POINTER(local->sched_scan_req, NULL); |
1129 | 1176 | ||
1130 | mutex_unlock(&local->mtx); | 1177 | mutex_unlock(&local->mtx); |
1131 | 1178 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index adc25371b171..a42f5b2b024d 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -351,6 +351,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
351 | 351 | ||
352 | sta->sta_state = IEEE80211_STA_NONE; | 352 | sta->sta_state = IEEE80211_STA_NONE; |
353 | 353 | ||
354 | /* Mark TID as unreserved */ | ||
355 | sta->reserved_tid = IEEE80211_TID_UNRESERVED; | ||
356 | |||
354 | ktime_get_ts(&uptime); | 357 | ktime_get_ts(&uptime); |
355 | sta->last_connected = uptime.tv_sec; | 358 | sta->last_connected = uptime.tv_sec; |
356 | ewma_init(&sta->avg_signal, 1024, 8); | 359 | ewma_init(&sta->avg_signal, 1024, 8); |
@@ -847,6 +850,15 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta) | |||
847 | if (WARN_ON(ret)) | 850 | if (WARN_ON(ret)) |
848 | return ret; | 851 | return ret; |
849 | 852 | ||
853 | /* | ||
854 | * for TDLS peers, make sure to return to the base channel before | ||
855 | * removal. | ||
856 | */ | ||
857 | if (test_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL)) { | ||
858 | drv_tdls_cancel_channel_switch(local, sdata, &sta->sta); | ||
859 | clear_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL); | ||
860 | } | ||
861 | |||
850 | list_del_rcu(&sta->list); | 862 | list_del_rcu(&sta->list); |
851 | 863 | ||
852 | drv_sta_pre_rcu_remove(local, sta->sdata, sta); | 864 | drv_sta_pre_rcu_remove(local, sta->sdata, sta); |
@@ -1249,7 +1261,8 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
1249 | return; | 1261 | return; |
1250 | } | 1262 | } |
1251 | 1263 | ||
1252 | ieee80211_xmit(sdata, skb, chanctx_conf->def.chan->band); | 1264 | info->band = chanctx_conf->def.chan->band; |
1265 | ieee80211_xmit(sdata, skb); | ||
1253 | rcu_read_unlock(); | 1266 | rcu_read_unlock(); |
1254 | } | 1267 | } |
1255 | 1268 | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index bcda2ac7d844..4f052bb2a5ad 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -49,6 +49,9 @@ | |||
49 | * packets. This means the link is enabled. | 49 | * packets. This means the link is enabled. |
50 | * @WLAN_STA_TDLS_INITIATOR: We are the initiator of the TDLS link with this | 50 | * @WLAN_STA_TDLS_INITIATOR: We are the initiator of the TDLS link with this |
51 | * station. | 51 | * station. |
52 | * @WLAN_STA_TDLS_CHAN_SWITCH: This TDLS peer supports TDLS channel-switching | ||
53 | * @WLAN_STA_TDLS_OFF_CHANNEL: The local STA is currently off-channel with this | ||
54 | * TDLS peer | ||
52 | * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was | 55 | * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was |
53 | * keeping station in power-save mode, reply when the driver | 56 | * keeping station in power-save mode, reply when the driver |
54 | * unblocks the station. | 57 | * unblocks the station. |
@@ -78,6 +81,8 @@ enum ieee80211_sta_info_flags { | |||
78 | WLAN_STA_TDLS_PEER, | 81 | WLAN_STA_TDLS_PEER, |
79 | WLAN_STA_TDLS_PEER_AUTH, | 82 | WLAN_STA_TDLS_PEER_AUTH, |
80 | WLAN_STA_TDLS_INITIATOR, | 83 | WLAN_STA_TDLS_INITIATOR, |
84 | WLAN_STA_TDLS_CHAN_SWITCH, | ||
85 | WLAN_STA_TDLS_OFF_CHANNEL, | ||
81 | WLAN_STA_UAPSD, | 86 | WLAN_STA_UAPSD, |
82 | WLAN_STA_SP, | 87 | WLAN_STA_SP, |
83 | WLAN_STA_4ADDR_EVENT, | 88 | WLAN_STA_4ADDR_EVENT, |
@@ -249,6 +254,9 @@ struct ieee80211_tx_latency_stat { | |||
249 | u32 bin_count; | 254 | u32 bin_count; |
250 | }; | 255 | }; |
251 | 256 | ||
257 | /* Value to indicate no TID reservation */ | ||
258 | #define IEEE80211_TID_UNRESERVED 0xff | ||
259 | |||
252 | /** | 260 | /** |
253 | * struct sta_info - STA information | 261 | * struct sta_info - STA information |
254 | * | 262 | * |
@@ -337,6 +345,7 @@ struct ieee80211_tx_latency_stat { | |||
337 | * AP only. | 345 | * AP only. |
338 | * @cipher_scheme: optional cipher scheme for this station | 346 | * @cipher_scheme: optional cipher scheme for this station |
339 | * @last_tdls_pkt_time: holds the time in jiffies of last TDLS pkt ACKed | 347 | * @last_tdls_pkt_time: holds the time in jiffies of last TDLS pkt ACKed |
348 | * @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED) | ||
340 | */ | 349 | */ |
341 | struct sta_info { | 350 | struct sta_info { |
342 | /* General information, mostly static */ | 351 | /* General information, mostly static */ |
@@ -454,6 +463,8 @@ struct sta_info { | |||
454 | /* TDLS timeout data */ | 463 | /* TDLS timeout data */ |
455 | unsigned long last_tdls_pkt_time; | 464 | unsigned long last_tdls_pkt_time; |
456 | 465 | ||
466 | u8 reserved_tid; | ||
467 | |||
457 | /* keep last! */ | 468 | /* keep last! */ |
458 | struct ieee80211_sta sta; | 469 | struct ieee80211_sta sta; |
459 | }; | 470 | }; |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 9612d89fad56..71de2d3866cc 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -390,6 +390,46 @@ ieee80211_add_tx_radiotap_header(struct ieee80211_local *local, | |||
390 | } | 390 | } |
391 | } | 391 | } |
392 | 392 | ||
393 | /* | ||
394 | * Handles the tx for TDLS teardown frames. | ||
395 | * If the frame wasn't ACKed by the peer - it will be re-sent through the AP | ||
396 | */ | ||
397 | static void ieee80211_tdls_td_tx_handle(struct ieee80211_local *local, | ||
398 | struct ieee80211_sub_if_data *sdata, | ||
399 | struct sk_buff *skb, u32 flags) | ||
400 | { | ||
401 | struct sk_buff *teardown_skb; | ||
402 | struct sk_buff *orig_teardown_skb; | ||
403 | bool is_teardown = false; | ||
404 | |||
405 | /* Get the teardown data we need and free the lock */ | ||
406 | spin_lock(&sdata->u.mgd.teardown_lock); | ||
407 | teardown_skb = sdata->u.mgd.teardown_skb; | ||
408 | orig_teardown_skb = sdata->u.mgd.orig_teardown_skb; | ||
409 | if ((skb == orig_teardown_skb) && teardown_skb) { | ||
410 | sdata->u.mgd.teardown_skb = NULL; | ||
411 | sdata->u.mgd.orig_teardown_skb = NULL; | ||
412 | is_teardown = true; | ||
413 | } | ||
414 | spin_unlock(&sdata->u.mgd.teardown_lock); | ||
415 | |||
416 | if (is_teardown) { | ||
417 | /* This mechanism relies on being able to get ACKs */ | ||
418 | WARN_ON(!(local->hw.flags & | ||
419 | IEEE80211_HW_REPORTS_TX_ACK_STATUS)); | ||
420 | |||
421 | /* Check if peer has ACKed */ | ||
422 | if (flags & IEEE80211_TX_STAT_ACK) { | ||
423 | dev_kfree_skb_any(teardown_skb); | ||
424 | } else { | ||
425 | tdls_dbg(sdata, | ||
426 | "TDLS Resending teardown through AP\n"); | ||
427 | |||
428 | ieee80211_subif_start_xmit(teardown_skb, skb->dev); | ||
429 | } | ||
430 | } | ||
431 | } | ||
432 | |||
393 | static void ieee80211_report_used_skb(struct ieee80211_local *local, | 433 | static void ieee80211_report_used_skb(struct ieee80211_local *local, |
394 | struct sk_buff *skb, bool dropped) | 434 | struct sk_buff *skb, bool dropped) |
395 | { | 435 | { |
@@ -426,8 +466,19 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local, | |||
426 | if (!sdata) { | 466 | if (!sdata) { |
427 | skb->dev = NULL; | 467 | skb->dev = NULL; |
428 | } else if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) { | 468 | } else if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) { |
429 | ieee80211_mgd_conn_tx_status(sdata, hdr->frame_control, | 469 | unsigned int hdr_size = |
430 | acked); | 470 | ieee80211_hdrlen(hdr->frame_control); |
471 | |||
472 | /* Check to see if packet is a TDLS teardown packet */ | ||
473 | if (ieee80211_is_data(hdr->frame_control) && | ||
474 | (ieee80211_get_tdls_action(skb, hdr_size) == | ||
475 | WLAN_TDLS_TEARDOWN)) | ||
476 | ieee80211_tdls_td_tx_handle(local, sdata, skb, | ||
477 | info->flags); | ||
478 | else | ||
479 | ieee80211_mgd_conn_tx_status(sdata, | ||
480 | hdr->frame_control, | ||
481 | acked); | ||
431 | } else if (ieee80211_is_nullfunc(hdr->frame_control) || | 482 | } else if (ieee80211_is_nullfunc(hdr->frame_control) || |
432 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | 483 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { |
433 | cfg80211_probe_status(sdata->dev, hdr->addr1, | 484 | cfg80211_probe_status(sdata->dev, hdr->addr1, |
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index b4f368e2cb3b..55ddd77b865d 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c | |||
@@ -35,19 +35,101 @@ void ieee80211_tdls_peer_del_work(struct work_struct *wk) | |||
35 | mutex_unlock(&local->mtx); | 35 | mutex_unlock(&local->mtx); |
36 | } | 36 | } |
37 | 37 | ||
38 | static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb) | 38 | static void ieee80211_tdls_add_ext_capab(struct ieee80211_local *local, |
39 | struct sk_buff *skb) | ||
39 | { | 40 | { |
40 | u8 *pos = (void *)skb_put(skb, 7); | 41 | u8 *pos = (void *)skb_put(skb, 7); |
42 | bool chan_switch = local->hw.wiphy->features & | ||
43 | NL80211_FEATURE_TDLS_CHANNEL_SWITCH; | ||
41 | 44 | ||
42 | *pos++ = WLAN_EID_EXT_CAPABILITY; | 45 | *pos++ = WLAN_EID_EXT_CAPABILITY; |
43 | *pos++ = 5; /* len */ | 46 | *pos++ = 5; /* len */ |
44 | *pos++ = 0x0; | 47 | *pos++ = 0x0; |
45 | *pos++ = 0x0; | 48 | *pos++ = 0x0; |
46 | *pos++ = 0x0; | 49 | *pos++ = 0x0; |
47 | *pos++ = 0x0; | 50 | *pos++ = chan_switch ? WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH : 0; |
48 | *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; | 51 | *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; |
49 | } | 52 | } |
50 | 53 | ||
54 | static u8 | ||
55 | ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata, | ||
56 | struct sk_buff *skb, u16 start, u16 end, | ||
57 | u16 spacing) | ||
58 | { | ||
59 | u8 subband_cnt = 0, ch_cnt = 0; | ||
60 | struct ieee80211_channel *ch; | ||
61 | struct cfg80211_chan_def chandef; | ||
62 | int i, subband_start; | ||
63 | |||
64 | for (i = start; i <= end; i += spacing) { | ||
65 | if (!ch_cnt) | ||
66 | subband_start = i; | ||
67 | |||
68 | ch = ieee80211_get_channel(sdata->local->hw.wiphy, i); | ||
69 | if (ch) { | ||
70 | /* we will be active on the channel */ | ||
71 | u32 flags = IEEE80211_CHAN_DISABLED | | ||
72 | IEEE80211_CHAN_NO_IR; | ||
73 | cfg80211_chandef_create(&chandef, ch, | ||
74 | NL80211_CHAN_HT20); | ||
75 | if (cfg80211_chandef_usable(sdata->local->hw.wiphy, | ||
76 | &chandef, flags)) { | ||
77 | ch_cnt++; | ||
78 | continue; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | if (ch_cnt) { | ||
83 | u8 *pos = skb_put(skb, 2); | ||
84 | *pos++ = ieee80211_frequency_to_channel(subband_start); | ||
85 | *pos++ = ch_cnt; | ||
86 | |||
87 | subband_cnt++; | ||
88 | ch_cnt = 0; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | return subband_cnt; | ||
93 | } | ||
94 | |||
95 | static void | ||
96 | ieee80211_tdls_add_supp_channels(struct ieee80211_sub_if_data *sdata, | ||
97 | struct sk_buff *skb) | ||
98 | { | ||
99 | /* | ||
100 | * Add possible channels for TDLS. These are channels that are allowed | ||
101 | * to be active. | ||
102 | */ | ||
103 | u8 subband_cnt; | ||
104 | u8 *pos = skb_put(skb, 2); | ||
105 | |||
106 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; | ||
107 | |||
108 | /* | ||
109 | * 5GHz and 2GHz channels numbers can overlap. Ignore this for now, as | ||
110 | * this doesn't happen in real world scenarios. | ||
111 | */ | ||
112 | |||
113 | /* 2GHz, with 5MHz spacing */ | ||
114 | subband_cnt = ieee80211_tdls_add_subband(sdata, skb, 2412, 2472, 5); | ||
115 | |||
116 | /* 5GHz, with 20MHz spacing */ | ||
117 | subband_cnt += ieee80211_tdls_add_subband(sdata, skb, 5000, 5825, 20); | ||
118 | |||
119 | /* length */ | ||
120 | *pos = 2 * subband_cnt; | ||
121 | } | ||
122 | |||
123 | static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb) | ||
124 | { | ||
125 | u8 *pos = (void *)skb_put(skb, 3); | ||
126 | |||
127 | *pos++ = WLAN_EID_BSS_COEX_2040; | ||
128 | *pos++ = 1; /* len */ | ||
129 | |||
130 | *pos++ = WLAN_BSS_COEX_INFORMATION_REQUEST; | ||
131 | } | ||
132 | |||
51 | static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, | 133 | static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, |
52 | u16 status_code) | 134 | u16 status_code) |
53 | { | 135 | { |
@@ -190,6 +272,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
190 | 272 | ||
191 | ieee80211_add_srates_ie(sdata, skb, false, band); | 273 | ieee80211_add_srates_ie(sdata, skb, false, band); |
192 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); | 274 | ieee80211_add_ext_srates_ie(sdata, skb, false, band); |
275 | ieee80211_tdls_add_supp_channels(sdata, skb); | ||
193 | 276 | ||
194 | /* add any custom IEs that go before Extended Capabilities */ | 277 | /* add any custom IEs that go before Extended Capabilities */ |
195 | if (extra_ies_len) { | 278 | if (extra_ies_len) { |
@@ -209,7 +292,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
209 | offset = noffset; | 292 | offset = noffset; |
210 | } | 293 | } |
211 | 294 | ||
212 | ieee80211_tdls_add_ext_capab(skb); | 295 | ieee80211_tdls_add_ext_capab(local, skb); |
213 | 296 | ||
214 | /* add the QoS element if we support it */ | 297 | /* add the QoS element if we support it */ |
215 | if (local->hw.queues >= IEEE80211_NUM_ACS && | 298 | if (local->hw.queues >= IEEE80211_NUM_ACS && |
@@ -271,6 +354,10 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, | |||
271 | 354 | ||
272 | rcu_read_unlock(); | 355 | rcu_read_unlock(); |
273 | 356 | ||
357 | if (ht_cap.ht_supported && | ||
358 | (ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
359 | ieee80211_tdls_add_bss_coex_ie(skb); | ||
360 | |||
274 | /* add any remaining IEs */ | 361 | /* add any remaining IEs */ |
275 | if (extra_ies_len) { | 362 | if (extra_ies_len) { |
276 | noffset = extra_ies_len; | 363 | noffset = extra_ies_len; |
@@ -362,11 +449,68 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, | |||
362 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | 449 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); |
363 | } | 450 | } |
364 | 451 | ||
452 | static void | ||
453 | ieee80211_tdls_add_chan_switch_req_ies(struct ieee80211_sub_if_data *sdata, | ||
454 | struct sk_buff *skb, const u8 *peer, | ||
455 | bool initiator, const u8 *extra_ies, | ||
456 | size_t extra_ies_len, u8 oper_class, | ||
457 | struct cfg80211_chan_def *chandef) | ||
458 | { | ||
459 | struct ieee80211_tdls_data *tf; | ||
460 | size_t offset = 0, noffset; | ||
461 | u8 *pos; | ||
462 | |||
463 | if (WARN_ON_ONCE(!chandef)) | ||
464 | return; | ||
465 | |||
466 | tf = (void *)skb->data; | ||
467 | tf->u.chan_switch_req.target_channel = | ||
468 | ieee80211_frequency_to_channel(chandef->chan->center_freq); | ||
469 | tf->u.chan_switch_req.oper_class = oper_class; | ||
470 | |||
471 | if (extra_ies_len) { | ||
472 | static const u8 before_lnkie[] = { | ||
473 | WLAN_EID_SECONDARY_CHANNEL_OFFSET, | ||
474 | }; | ||
475 | noffset = ieee80211_ie_split(extra_ies, extra_ies_len, | ||
476 | before_lnkie, | ||
477 | ARRAY_SIZE(before_lnkie), | ||
478 | offset); | ||
479 | pos = skb_put(skb, noffset - offset); | ||
480 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
481 | offset = noffset; | ||
482 | } | ||
483 | |||
484 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
485 | |||
486 | /* add any remaining IEs */ | ||
487 | if (extra_ies_len) { | ||
488 | noffset = extra_ies_len; | ||
489 | pos = skb_put(skb, noffset - offset); | ||
490 | memcpy(pos, extra_ies + offset, noffset - offset); | ||
491 | } | ||
492 | } | ||
493 | |||
494 | static void | ||
495 | ieee80211_tdls_add_chan_switch_resp_ies(struct ieee80211_sub_if_data *sdata, | ||
496 | struct sk_buff *skb, const u8 *peer, | ||
497 | u16 status_code, bool initiator, | ||
498 | const u8 *extra_ies, | ||
499 | size_t extra_ies_len) | ||
500 | { | ||
501 | if (status_code == 0) | ||
502 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | ||
503 | |||
504 | if (extra_ies_len) | ||
505 | memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); | ||
506 | } | ||
507 | |||
365 | static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, | 508 | static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, |
366 | struct sk_buff *skb, const u8 *peer, | 509 | struct sk_buff *skb, const u8 *peer, |
367 | u8 action_code, u16 status_code, | 510 | u8 action_code, u16 status_code, |
368 | bool initiator, const u8 *extra_ies, | 511 | bool initiator, const u8 *extra_ies, |
369 | size_t extra_ies_len) | 512 | size_t extra_ies_len, u8 oper_class, |
513 | struct cfg80211_chan_def *chandef) | ||
370 | { | 514 | { |
371 | switch (action_code) { | 515 | switch (action_code) { |
372 | case WLAN_TDLS_SETUP_REQUEST: | 516 | case WLAN_TDLS_SETUP_REQUEST: |
@@ -393,6 +537,18 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, | |||
393 | if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN) | 537 | if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN) |
394 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); | 538 | ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); |
395 | break; | 539 | break; |
540 | case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: | ||
541 | ieee80211_tdls_add_chan_switch_req_ies(sdata, skb, peer, | ||
542 | initiator, extra_ies, | ||
543 | extra_ies_len, | ||
544 | oper_class, chandef); | ||
545 | break; | ||
546 | case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: | ||
547 | ieee80211_tdls_add_chan_switch_resp_ies(sdata, skb, peer, | ||
548 | status_code, | ||
549 | initiator, extra_ies, | ||
550 | extra_ies_len); | ||
551 | break; | ||
396 | } | 552 | } |
397 | 553 | ||
398 | } | 554 | } |
@@ -459,6 +615,19 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
459 | skb_put(skb, sizeof(tf->u.discover_req)); | 615 | skb_put(skb, sizeof(tf->u.discover_req)); |
460 | tf->u.discover_req.dialog_token = dialog_token; | 616 | tf->u.discover_req.dialog_token = dialog_token; |
461 | break; | 617 | break; |
618 | case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: | ||
619 | tf->category = WLAN_CATEGORY_TDLS; | ||
620 | tf->action_code = WLAN_TDLS_CHANNEL_SWITCH_REQUEST; | ||
621 | |||
622 | skb_put(skb, sizeof(tf->u.chan_switch_req)); | ||
623 | break; | ||
624 | case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: | ||
625 | tf->category = WLAN_CATEGORY_TDLS; | ||
626 | tf->action_code = WLAN_TDLS_CHANNEL_SWITCH_RESPONSE; | ||
627 | |||
628 | skb_put(skb, sizeof(tf->u.chan_switch_resp)); | ||
629 | tf->u.chan_switch_resp.status_code = cpu_to_le16(status_code); | ||
630 | break; | ||
462 | default: | 631 | default: |
463 | return -EINVAL; | 632 | return -EINVAL; |
464 | } | 633 | } |
@@ -502,32 +671,33 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
502 | return 0; | 671 | return 0; |
503 | } | 672 | } |
504 | 673 | ||
505 | static int | 674 | static struct sk_buff * |
506 | ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | 675 | ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, |
507 | const u8 *peer, u8 action_code, | 676 | const u8 *peer, u8 action_code, |
508 | u8 dialog_token, u16 status_code, | 677 | u8 dialog_token, u16 status_code, |
509 | u32 peer_capability, bool initiator, | 678 | bool initiator, const u8 *extra_ies, |
510 | const u8 *extra_ies, size_t extra_ies_len) | 679 | size_t extra_ies_len, u8 oper_class, |
680 | struct cfg80211_chan_def *chandef) | ||
511 | { | 681 | { |
512 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
513 | struct ieee80211_local *local = sdata->local; | 682 | struct ieee80211_local *local = sdata->local; |
514 | struct sk_buff *skb = NULL; | 683 | struct sk_buff *skb; |
515 | bool send_direct; | ||
516 | struct sta_info *sta; | ||
517 | int ret; | 684 | int ret; |
518 | 685 | ||
519 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 686 | skb = netdev_alloc_skb(sdata->dev, |
520 | max(sizeof(struct ieee80211_mgmt), | 687 | local->hw.extra_tx_headroom + |
521 | sizeof(struct ieee80211_tdls_data)) + | 688 | max(sizeof(struct ieee80211_mgmt), |
522 | 50 + /* supported rates */ | 689 | sizeof(struct ieee80211_tdls_data)) + |
523 | 7 + /* ext capab */ | 690 | 50 + /* supported rates */ |
524 | 26 + /* max(WMM-info, WMM-param) */ | 691 | 7 + /* ext capab */ |
525 | 2 + max(sizeof(struct ieee80211_ht_cap), | 692 | 26 + /* max(WMM-info, WMM-param) */ |
526 | sizeof(struct ieee80211_ht_operation)) + | 693 | 2 + max(sizeof(struct ieee80211_ht_cap), |
527 | extra_ies_len + | 694 | sizeof(struct ieee80211_ht_operation)) + |
528 | sizeof(struct ieee80211_tdls_lnkie)); | 695 | 50 + /* supported channels */ |
696 | 3 + /* 40/20 BSS coex */ | ||
697 | extra_ies_len + | ||
698 | sizeof(struct ieee80211_tdls_lnkie)); | ||
529 | if (!skb) | 699 | if (!skb) |
530 | return -ENOMEM; | 700 | return NULL; |
531 | 701 | ||
532 | skb_reserve(skb, local->hw.extra_tx_headroom); | 702 | skb_reserve(skb, local->hw.extra_tx_headroom); |
533 | 703 | ||
@@ -537,16 +707,18 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
537 | case WLAN_TDLS_SETUP_CONFIRM: | 707 | case WLAN_TDLS_SETUP_CONFIRM: |
538 | case WLAN_TDLS_TEARDOWN: | 708 | case WLAN_TDLS_TEARDOWN: |
539 | case WLAN_TDLS_DISCOVERY_REQUEST: | 709 | case WLAN_TDLS_DISCOVERY_REQUEST: |
540 | ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer, | 710 | case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: |
711 | case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: | ||
712 | ret = ieee80211_prep_tdls_encap_data(local->hw.wiphy, | ||
713 | sdata->dev, peer, | ||
541 | action_code, dialog_token, | 714 | action_code, dialog_token, |
542 | status_code, skb); | 715 | status_code, skb); |
543 | send_direct = false; | ||
544 | break; | 716 | break; |
545 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | 717 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: |
546 | ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code, | 718 | ret = ieee80211_prep_tdls_direct(local->hw.wiphy, sdata->dev, |
719 | peer, action_code, | ||
547 | dialog_token, status_code, | 720 | dialog_token, status_code, |
548 | skb); | 721 | skb); |
549 | send_direct = true; | ||
550 | break; | 722 | break; |
551 | default: | 723 | default: |
552 | ret = -ENOTSUPP; | 724 | ret = -ENOTSUPP; |
@@ -556,6 +728,30 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
556 | if (ret < 0) | 728 | if (ret < 0) |
557 | goto fail; | 729 | goto fail; |
558 | 730 | ||
731 | ieee80211_tdls_add_ies(sdata, skb, peer, action_code, status_code, | ||
732 | initiator, extra_ies, extra_ies_len, oper_class, | ||
733 | chandef); | ||
734 | return skb; | ||
735 | |||
736 | fail: | ||
737 | dev_kfree_skb(skb); | ||
738 | return NULL; | ||
739 | } | ||
740 | |||
741 | static int | ||
742 | ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | ||
743 | const u8 *peer, u8 action_code, u8 dialog_token, | ||
744 | u16 status_code, u32 peer_capability, | ||
745 | bool initiator, const u8 *extra_ies, | ||
746 | size_t extra_ies_len, u8 oper_class, | ||
747 | struct cfg80211_chan_def *chandef) | ||
748 | { | ||
749 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
750 | struct sk_buff *skb = NULL; | ||
751 | struct sta_info *sta; | ||
752 | u32 flags = 0; | ||
753 | int ret = 0; | ||
754 | |||
559 | rcu_read_lock(); | 755 | rcu_read_lock(); |
560 | sta = sta_info_get(sdata, peer); | 756 | sta = sta_info_get(sdata, peer); |
561 | 757 | ||
@@ -586,6 +782,8 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
586 | initiator = false; | 782 | initiator = false; |
587 | break; | 783 | break; |
588 | case WLAN_TDLS_TEARDOWN: | 784 | case WLAN_TDLS_TEARDOWN: |
785 | case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: | ||
786 | case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: | ||
589 | /* any value is ok */ | 787 | /* any value is ok */ |
590 | break; | 788 | break; |
591 | default: | 789 | default: |
@@ -600,9 +798,17 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
600 | if (ret < 0) | 798 | if (ret < 0) |
601 | goto fail; | 799 | goto fail; |
602 | 800 | ||
603 | ieee80211_tdls_add_ies(sdata, skb, peer, action_code, status_code, | 801 | skb = ieee80211_tdls_build_mgmt_packet_data(sdata, peer, action_code, |
604 | initiator, extra_ies, extra_ies_len); | 802 | dialog_token, status_code, |
605 | if (send_direct) { | 803 | initiator, extra_ies, |
804 | extra_ies_len, oper_class, | ||
805 | chandef); | ||
806 | if (!skb) { | ||
807 | ret = -EINVAL; | ||
808 | goto fail; | ||
809 | } | ||
810 | |||
811 | if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) { | ||
606 | ieee80211_tx_skb(sdata, skb); | 812 | ieee80211_tx_skb(sdata, skb); |
607 | return 0; | 813 | return 0; |
608 | } | 814 | } |
@@ -623,9 +829,44 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
623 | break; | 829 | break; |
624 | } | 830 | } |
625 | 831 | ||
832 | /* | ||
833 | * Set the WLAN_TDLS_TEARDOWN flag to indicate a teardown in progress. | ||
834 | * Later, if no ACK is returned from peer, we will re-send the teardown | ||
835 | * packet through the AP. | ||
836 | */ | ||
837 | if ((action_code == WLAN_TDLS_TEARDOWN) && | ||
838 | (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { | ||
839 | struct sta_info *sta = NULL; | ||
840 | bool try_resend; /* Should we keep skb for possible resend */ | ||
841 | |||
842 | /* If not sending directly to peer - no point in keeping skb */ | ||
843 | rcu_read_lock(); | ||
844 | sta = sta_info_get(sdata, peer); | ||
845 | try_resend = sta && test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); | ||
846 | rcu_read_unlock(); | ||
847 | |||
848 | spin_lock_bh(&sdata->u.mgd.teardown_lock); | ||
849 | if (try_resend && !sdata->u.mgd.teardown_skb) { | ||
850 | /* Mark it as requiring TX status callback */ | ||
851 | flags |= IEEE80211_TX_CTL_REQ_TX_STATUS | | ||
852 | IEEE80211_TX_INTFL_MLME_CONN_TX; | ||
853 | |||
854 | /* | ||
855 | * skb is copied since mac80211 will later set | ||
856 | * properties that might not be the same as the AP, | ||
857 | * such as encryption, QoS, addresses, etc. | ||
858 | * | ||
859 | * No problem if skb_copy() fails, so no need to check. | ||
860 | */ | ||
861 | sdata->u.mgd.teardown_skb = skb_copy(skb, GFP_ATOMIC); | ||
862 | sdata->u.mgd.orig_teardown_skb = skb; | ||
863 | } | ||
864 | spin_unlock_bh(&sdata->u.mgd.teardown_lock); | ||
865 | } | ||
866 | |||
626 | /* disable bottom halves when entering the Tx path */ | 867 | /* disable bottom halves when entering the Tx path */ |
627 | local_bh_disable(); | 868 | local_bh_disable(); |
628 | ret = ieee80211_subif_start_xmit(skb, dev); | 869 | __ieee80211_subif_start_xmit(skb, dev, flags); |
629 | local_bh_enable(); | 870 | local_bh_enable(); |
630 | 871 | ||
631 | return ret; | 872 | return ret; |
@@ -676,7 +917,8 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, | |||
676 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, | 917 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, |
677 | dialog_token, status_code, | 918 | dialog_token, status_code, |
678 | peer_capability, initiator, | 919 | peer_capability, initiator, |
679 | extra_ies, extra_ies_len); | 920 | extra_ies, extra_ies_len, 0, |
921 | NULL); | ||
680 | if (ret < 0) | 922 | if (ret < 0) |
681 | goto exit; | 923 | goto exit; |
682 | 924 | ||
@@ -715,7 +957,8 @@ ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev, | |||
715 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, | 957 | ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, |
716 | dialog_token, status_code, | 958 | dialog_token, status_code, |
717 | peer_capability, initiator, | 959 | peer_capability, initiator, |
718 | extra_ies, extra_ies_len); | 960 | extra_ies, extra_ies_len, 0, |
961 | NULL); | ||
719 | if (ret < 0) | 962 | if (ret < 0) |
720 | sdata_err(sdata, "Failed sending TDLS teardown packet %d\n", | 963 | sdata_err(sdata, "Failed sending TDLS teardown packet %d\n", |
721 | ret); | 964 | ret); |
@@ -785,7 +1028,7 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
785 | status_code, | 1028 | status_code, |
786 | peer_capability, | 1029 | peer_capability, |
787 | initiator, extra_ies, | 1030 | initiator, extra_ies, |
788 | extra_ies_len); | 1031 | extra_ies_len, 0, NULL); |
789 | break; | 1032 | break; |
790 | default: | 1033 | default: |
791 | ret = -EOPNOTSUPP; | 1034 | ret = -EOPNOTSUPP; |
@@ -888,3 +1131,480 @@ void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer, | |||
888 | cfg80211_tdls_oper_request(sdata->dev, peer, oper, reason_code, gfp); | 1131 | cfg80211_tdls_oper_request(sdata->dev, peer, oper, reason_code, gfp); |
889 | } | 1132 | } |
890 | EXPORT_SYMBOL(ieee80211_tdls_oper_request); | 1133 | EXPORT_SYMBOL(ieee80211_tdls_oper_request); |
1134 | |||
1135 | static void | ||
1136 | iee80211_tdls_add_ch_switch_timing(u8 *buf, u16 switch_time, u16 switch_timeout) | ||
1137 | { | ||
1138 | struct ieee80211_ch_switch_timing *ch_sw; | ||
1139 | |||
1140 | *buf++ = WLAN_EID_CHAN_SWITCH_TIMING; | ||
1141 | *buf++ = sizeof(struct ieee80211_ch_switch_timing); | ||
1142 | |||
1143 | ch_sw = (void *)buf; | ||
1144 | ch_sw->switch_time = cpu_to_le16(switch_time); | ||
1145 | ch_sw->switch_timeout = cpu_to_le16(switch_timeout); | ||
1146 | } | ||
1147 | |||
1148 | /* find switch timing IE in SKB ready for Tx */ | ||
1149 | static const u8 *ieee80211_tdls_find_sw_timing_ie(struct sk_buff *skb) | ||
1150 | { | ||
1151 | struct ieee80211_tdls_data *tf; | ||
1152 | const u8 *ie_start; | ||
1153 | |||
1154 | /* | ||
1155 | * Get the offset for the new location of the switch timing IE. | ||
1156 | * The SKB network header will now point to the "payload_type" | ||
1157 | * element of the TDLS data frame struct. | ||
1158 | */ | ||
1159 | tf = container_of(skb->data + skb_network_offset(skb), | ||
1160 | struct ieee80211_tdls_data, payload_type); | ||
1161 | ie_start = tf->u.chan_switch_req.variable; | ||
1162 | return cfg80211_find_ie(WLAN_EID_CHAN_SWITCH_TIMING, ie_start, | ||
1163 | skb->len - (ie_start - skb->data)); | ||
1164 | } | ||
1165 | |||
1166 | static struct sk_buff * | ||
1167 | ieee80211_tdls_ch_sw_tmpl_get(struct sta_info *sta, u8 oper_class, | ||
1168 | struct cfg80211_chan_def *chandef, | ||
1169 | u32 *ch_sw_tm_ie_offset) | ||
1170 | { | ||
1171 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
1172 | u8 extra_ies[2 + sizeof(struct ieee80211_sec_chan_offs_ie) + | ||
1173 | 2 + sizeof(struct ieee80211_ch_switch_timing)]; | ||
1174 | int extra_ies_len = 2 + sizeof(struct ieee80211_ch_switch_timing); | ||
1175 | u8 *pos = extra_ies; | ||
1176 | struct sk_buff *skb; | ||
1177 | |||
1178 | /* | ||
1179 | * if chandef points to a wide channel add a Secondary-Channel | ||
1180 | * Offset information element | ||
1181 | */ | ||
1182 | if (chandef->width == NL80211_CHAN_WIDTH_40) { | ||
1183 | struct ieee80211_sec_chan_offs_ie *sec_chan_ie; | ||
1184 | bool ht40plus; | ||
1185 | |||
1186 | *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; | ||
1187 | *pos++ = sizeof(*sec_chan_ie); | ||
1188 | sec_chan_ie = (void *)pos; | ||
1189 | |||
1190 | ht40plus = cfg80211_get_chandef_type(chandef) == | ||
1191 | NL80211_CHAN_HT40PLUS; | ||
1192 | sec_chan_ie->sec_chan_offs = ht40plus ? | ||
1193 | IEEE80211_HT_PARAM_CHA_SEC_ABOVE : | ||
1194 | IEEE80211_HT_PARAM_CHA_SEC_BELOW; | ||
1195 | pos += sizeof(*sec_chan_ie); | ||
1196 | |||
1197 | extra_ies_len += 2 + sizeof(struct ieee80211_sec_chan_offs_ie); | ||
1198 | } | ||
1199 | |||
1200 | /* just set the values to 0, this is a template */ | ||
1201 | iee80211_tdls_add_ch_switch_timing(pos, 0, 0); | ||
1202 | |||
1203 | skb = ieee80211_tdls_build_mgmt_packet_data(sdata, sta->sta.addr, | ||
1204 | WLAN_TDLS_CHANNEL_SWITCH_REQUEST, | ||
1205 | 0, 0, !sta->sta.tdls_initiator, | ||
1206 | extra_ies, extra_ies_len, | ||
1207 | oper_class, chandef); | ||
1208 | if (!skb) | ||
1209 | return NULL; | ||
1210 | |||
1211 | skb = ieee80211_build_data_template(sdata, skb, 0); | ||
1212 | if (IS_ERR(skb)) { | ||
1213 | tdls_dbg(sdata, "Failed building TDLS channel switch frame\n"); | ||
1214 | return NULL; | ||
1215 | } | ||
1216 | |||
1217 | if (ch_sw_tm_ie_offset) { | ||
1218 | const u8 *tm_ie = ieee80211_tdls_find_sw_timing_ie(skb); | ||
1219 | |||
1220 | if (!tm_ie) { | ||
1221 | tdls_dbg(sdata, "No switch timing IE in TDLS switch\n"); | ||
1222 | dev_kfree_skb_any(skb); | ||
1223 | return NULL; | ||
1224 | } | ||
1225 | |||
1226 | *ch_sw_tm_ie_offset = tm_ie - skb->data; | ||
1227 | } | ||
1228 | |||
1229 | tdls_dbg(sdata, | ||
1230 | "TDLS channel switch request template for %pM ch %d width %d\n", | ||
1231 | sta->sta.addr, chandef->chan->center_freq, chandef->width); | ||
1232 | return skb; | ||
1233 | } | ||
1234 | |||
1235 | int | ||
1236 | ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev, | ||
1237 | const u8 *addr, u8 oper_class, | ||
1238 | struct cfg80211_chan_def *chandef) | ||
1239 | { | ||
1240 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1241 | struct ieee80211_local *local = sdata->local; | ||
1242 | struct sta_info *sta; | ||
1243 | struct sk_buff *skb = NULL; | ||
1244 | u32 ch_sw_tm_ie; | ||
1245 | int ret; | ||
1246 | |||
1247 | mutex_lock(&local->sta_mtx); | ||
1248 | sta = sta_info_get(sdata, addr); | ||
1249 | if (!sta) { | ||
1250 | tdls_dbg(sdata, | ||
1251 | "Invalid TDLS peer %pM for channel switch request\n", | ||
1252 | addr); | ||
1253 | ret = -ENOENT; | ||
1254 | goto out; | ||
1255 | } | ||
1256 | |||
1257 | if (!test_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH)) { | ||
1258 | tdls_dbg(sdata, "TDLS channel switch unsupported by %pM\n", | ||
1259 | addr); | ||
1260 | ret = -ENOTSUPP; | ||
1261 | goto out; | ||
1262 | } | ||
1263 | |||
1264 | skb = ieee80211_tdls_ch_sw_tmpl_get(sta, oper_class, chandef, | ||
1265 | &ch_sw_tm_ie); | ||
1266 | if (!skb) { | ||
1267 | ret = -ENOENT; | ||
1268 | goto out; | ||
1269 | } | ||
1270 | |||
1271 | ret = drv_tdls_channel_switch(local, sdata, &sta->sta, oper_class, | ||
1272 | chandef, skb, ch_sw_tm_ie); | ||
1273 | if (!ret) | ||
1274 | set_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL); | ||
1275 | |||
1276 | out: | ||
1277 | mutex_unlock(&local->sta_mtx); | ||
1278 | dev_kfree_skb_any(skb); | ||
1279 | return ret; | ||
1280 | } | ||
1281 | |||
1282 | void | ||
1283 | ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy, | ||
1284 | struct net_device *dev, | ||
1285 | const u8 *addr) | ||
1286 | { | ||
1287 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1288 | struct ieee80211_local *local = sdata->local; | ||
1289 | struct sta_info *sta; | ||
1290 | |||
1291 | mutex_lock(&local->sta_mtx); | ||
1292 | sta = sta_info_get(sdata, addr); | ||
1293 | if (!sta) { | ||
1294 | tdls_dbg(sdata, | ||
1295 | "Invalid TDLS peer %pM for channel switch cancel\n", | ||
1296 | addr); | ||
1297 | goto out; | ||
1298 | } | ||
1299 | |||
1300 | if (!test_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL)) { | ||
1301 | tdls_dbg(sdata, "TDLS channel switch not initiated by %pM\n", | ||
1302 | addr); | ||
1303 | goto out; | ||
1304 | } | ||
1305 | |||
1306 | drv_tdls_cancel_channel_switch(local, sdata, &sta->sta); | ||
1307 | clear_sta_flag(sta, WLAN_STA_TDLS_OFF_CHANNEL); | ||
1308 | |||
1309 | out: | ||
1310 | mutex_unlock(&local->sta_mtx); | ||
1311 | } | ||
1312 | |||
1313 | static struct sk_buff * | ||
1314 | ieee80211_tdls_ch_sw_resp_tmpl_get(struct sta_info *sta, | ||
1315 | u32 *ch_sw_tm_ie_offset) | ||
1316 | { | ||
1317 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
1318 | struct sk_buff *skb; | ||
1319 | u8 extra_ies[2 + sizeof(struct ieee80211_ch_switch_timing)]; | ||
1320 | |||
1321 | /* initial timing are always zero in the template */ | ||
1322 | iee80211_tdls_add_ch_switch_timing(extra_ies, 0, 0); | ||
1323 | |||
1324 | skb = ieee80211_tdls_build_mgmt_packet_data(sdata, sta->sta.addr, | ||
1325 | WLAN_TDLS_CHANNEL_SWITCH_RESPONSE, | ||
1326 | 0, 0, !sta->sta.tdls_initiator, | ||
1327 | extra_ies, sizeof(extra_ies), 0, NULL); | ||
1328 | if (!skb) | ||
1329 | return NULL; | ||
1330 | |||
1331 | skb = ieee80211_build_data_template(sdata, skb, 0); | ||
1332 | if (IS_ERR(skb)) { | ||
1333 | tdls_dbg(sdata, | ||
1334 | "Failed building TDLS channel switch resp frame\n"); | ||
1335 | return NULL; | ||
1336 | } | ||
1337 | |||
1338 | if (ch_sw_tm_ie_offset) { | ||
1339 | const u8 *tm_ie = ieee80211_tdls_find_sw_timing_ie(skb); | ||
1340 | |||
1341 | if (!tm_ie) { | ||
1342 | tdls_dbg(sdata, | ||
1343 | "No switch timing IE in TDLS switch resp\n"); | ||
1344 | dev_kfree_skb_any(skb); | ||
1345 | return NULL; | ||
1346 | } | ||
1347 | |||
1348 | *ch_sw_tm_ie_offset = tm_ie - skb->data; | ||
1349 | } | ||
1350 | |||
1351 | tdls_dbg(sdata, "TDLS get channel switch response template for %pM\n", | ||
1352 | sta->sta.addr); | ||
1353 | return skb; | ||
1354 | } | ||
1355 | |||
1356 | static int | ||
1357 | ieee80211_process_tdls_channel_switch_resp(struct ieee80211_sub_if_data *sdata, | ||
1358 | struct sk_buff *skb) | ||
1359 | { | ||
1360 | struct ieee80211_local *local = sdata->local; | ||
1361 | struct ieee802_11_elems elems; | ||
1362 | struct sta_info *sta; | ||
1363 | struct ieee80211_tdls_data *tf = (void *)skb->data; | ||
1364 | bool local_initiator; | ||
1365 | struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); | ||
1366 | int baselen = offsetof(typeof(*tf), u.chan_switch_resp.variable); | ||
1367 | struct ieee80211_tdls_ch_sw_params params = {}; | ||
1368 | int ret; | ||
1369 | |||
1370 | params.action_code = WLAN_TDLS_CHANNEL_SWITCH_RESPONSE; | ||
1371 | params.timestamp = rx_status->device_timestamp; | ||
1372 | |||
1373 | if (skb->len < baselen) { | ||
1374 | tdls_dbg(sdata, "TDLS channel switch resp too short: %d\n", | ||
1375 | skb->len); | ||
1376 | return -EINVAL; | ||
1377 | } | ||
1378 | |||
1379 | mutex_lock(&local->sta_mtx); | ||
1380 | sta = sta_info_get(sdata, tf->sa); | ||
1381 | if (!sta || !test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) { | ||
1382 | tdls_dbg(sdata, "TDLS chan switch from non-peer sta %pM\n", | ||
1383 | tf->sa); | ||
1384 | ret = -EINVAL; | ||
1385 | goto out; | ||
1386 | } | ||
1387 | |||
1388 | params.sta = &sta->sta; | ||
1389 | params.status = le16_to_cpu(tf->u.chan_switch_resp.status_code); | ||
1390 | if (params.status != 0) { | ||
1391 | ret = 0; | ||
1392 | goto call_drv; | ||
1393 | } | ||
1394 | |||
1395 | ieee802_11_parse_elems(tf->u.chan_switch_resp.variable, | ||
1396 | skb->len - baselen, false, &elems); | ||
1397 | if (elems.parse_error) { | ||
1398 | tdls_dbg(sdata, "Invalid IEs in TDLS channel switch resp\n"); | ||
1399 | ret = -EINVAL; | ||
1400 | goto out; | ||
1401 | } | ||
1402 | |||
1403 | if (!elems.ch_sw_timing || !elems.lnk_id) { | ||
1404 | tdls_dbg(sdata, "TDLS channel switch resp - missing IEs\n"); | ||
1405 | ret = -EINVAL; | ||
1406 | goto out; | ||
1407 | } | ||
1408 | |||
1409 | /* validate the initiator is set correctly */ | ||
1410 | local_initiator = | ||
1411 | !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); | ||
1412 | if (local_initiator == sta->sta.tdls_initiator) { | ||
1413 | tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); | ||
1414 | ret = -EINVAL; | ||
1415 | goto out; | ||
1416 | } | ||
1417 | |||
1418 | params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); | ||
1419 | params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); | ||
1420 | |||
1421 | params.tmpl_skb = | ||
1422 | ieee80211_tdls_ch_sw_resp_tmpl_get(sta, ¶ms.ch_sw_tm_ie); | ||
1423 | if (!params.tmpl_skb) { | ||
1424 | ret = -ENOENT; | ||
1425 | goto out; | ||
1426 | } | ||
1427 | |||
1428 | call_drv: | ||
1429 | drv_tdls_recv_channel_switch(sdata->local, sdata, ¶ms); | ||
1430 | |||
1431 | tdls_dbg(sdata, | ||
1432 | "TDLS channel switch response received from %pM status %d\n", | ||
1433 | tf->sa, params.status); | ||
1434 | |||
1435 | out: | ||
1436 | mutex_unlock(&local->sta_mtx); | ||
1437 | dev_kfree_skb_any(params.tmpl_skb); | ||
1438 | return ret; | ||
1439 | } | ||
1440 | |||
1441 | static int | ||
1442 | ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata, | ||
1443 | struct sk_buff *skb) | ||
1444 | { | ||
1445 | struct ieee80211_local *local = sdata->local; | ||
1446 | struct ieee802_11_elems elems; | ||
1447 | struct cfg80211_chan_def chandef; | ||
1448 | struct ieee80211_channel *chan; | ||
1449 | enum nl80211_channel_type chan_type; | ||
1450 | int freq; | ||
1451 | u8 target_channel, oper_class; | ||
1452 | bool local_initiator; | ||
1453 | struct sta_info *sta; | ||
1454 | enum ieee80211_band band; | ||
1455 | struct ieee80211_tdls_data *tf = (void *)skb->data; | ||
1456 | struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); | ||
1457 | int baselen = offsetof(typeof(*tf), u.chan_switch_req.variable); | ||
1458 | struct ieee80211_tdls_ch_sw_params params = {}; | ||
1459 | int ret = 0; | ||
1460 | |||
1461 | params.action_code = WLAN_TDLS_CHANNEL_SWITCH_REQUEST; | ||
1462 | params.timestamp = rx_status->device_timestamp; | ||
1463 | |||
1464 | if (skb->len < baselen) { | ||
1465 | tdls_dbg(sdata, "TDLS channel switch req too short: %d\n", | ||
1466 | skb->len); | ||
1467 | return -EINVAL; | ||
1468 | } | ||
1469 | |||
1470 | target_channel = tf->u.chan_switch_req.target_channel; | ||
1471 | oper_class = tf->u.chan_switch_req.oper_class; | ||
1472 | |||
1473 | /* | ||
1474 | * We can't easily infer the channel band. The operating class is | ||
1475 | * ambiguous - there are multiple tables (US/Europe/JP/Global). The | ||
1476 | * solution here is to treat channels with number >14 as 5GHz ones, | ||
1477 | * and specifically check for the (oper_class, channel) combinations | ||
1478 | * where this doesn't hold. These are thankfully unique according to | ||
1479 | * IEEE802.11-2012. | ||
1480 | * We consider only the 2GHz and 5GHz bands and 20MHz+ channels as | ||
1481 | * valid here. | ||
1482 | */ | ||
1483 | if ((oper_class == 112 || oper_class == 2 || oper_class == 3 || | ||
1484 | oper_class == 4 || oper_class == 5 || oper_class == 6) && | ||
1485 | target_channel < 14) | ||
1486 | band = IEEE80211_BAND_5GHZ; | ||
1487 | else | ||
1488 | band = target_channel < 14 ? IEEE80211_BAND_2GHZ : | ||
1489 | IEEE80211_BAND_5GHZ; | ||
1490 | |||
1491 | freq = ieee80211_channel_to_frequency(target_channel, band); | ||
1492 | if (freq == 0) { | ||
1493 | tdls_dbg(sdata, "Invalid channel in TDLS chan switch: %d\n", | ||
1494 | target_channel); | ||
1495 | return -EINVAL; | ||
1496 | } | ||
1497 | |||
1498 | chan = ieee80211_get_channel(sdata->local->hw.wiphy, freq); | ||
1499 | if (!chan) { | ||
1500 | tdls_dbg(sdata, | ||
1501 | "Unsupported channel for TDLS chan switch: %d\n", | ||
1502 | target_channel); | ||
1503 | return -EINVAL; | ||
1504 | } | ||
1505 | |||
1506 | ieee802_11_parse_elems(tf->u.chan_switch_req.variable, | ||
1507 | skb->len - baselen, false, &elems); | ||
1508 | if (elems.parse_error) { | ||
1509 | tdls_dbg(sdata, "Invalid IEs in TDLS channel switch req\n"); | ||
1510 | return -EINVAL; | ||
1511 | } | ||
1512 | |||
1513 | if (!elems.ch_sw_timing || !elems.lnk_id) { | ||
1514 | tdls_dbg(sdata, "TDLS channel switch req - missing IEs\n"); | ||
1515 | return -EINVAL; | ||
1516 | } | ||
1517 | |||
1518 | mutex_lock(&local->sta_mtx); | ||
1519 | sta = sta_info_get(sdata, tf->sa); | ||
1520 | if (!sta || !test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) { | ||
1521 | tdls_dbg(sdata, "TDLS chan switch from non-peer sta %pM\n", | ||
1522 | tf->sa); | ||
1523 | ret = -EINVAL; | ||
1524 | goto out; | ||
1525 | } | ||
1526 | |||
1527 | params.sta = &sta->sta; | ||
1528 | |||
1529 | /* validate the initiator is set correctly */ | ||
1530 | local_initiator = | ||
1531 | !memcmp(elems.lnk_id->init_sta, sdata->vif.addr, ETH_ALEN); | ||
1532 | if (local_initiator == sta->sta.tdls_initiator) { | ||
1533 | tdls_dbg(sdata, "TDLS chan switch invalid lnk-id initiator\n"); | ||
1534 | ret = -EINVAL; | ||
1535 | goto out; | ||
1536 | } | ||
1537 | |||
1538 | if (!sta->sta.ht_cap.ht_supported) { | ||
1539 | chan_type = NL80211_CHAN_NO_HT; | ||
1540 | } else if (!elems.sec_chan_offs) { | ||
1541 | chan_type = NL80211_CHAN_HT20; | ||
1542 | } else { | ||
1543 | switch (elems.sec_chan_offs->sec_chan_offs) { | ||
1544 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
1545 | chan_type = NL80211_CHAN_HT40PLUS; | ||
1546 | break; | ||
1547 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
1548 | chan_type = NL80211_CHAN_HT40MINUS; | ||
1549 | break; | ||
1550 | default: | ||
1551 | chan_type = NL80211_CHAN_HT20; | ||
1552 | break; | ||
1553 | } | ||
1554 | } | ||
1555 | |||
1556 | cfg80211_chandef_create(&chandef, chan, chan_type); | ||
1557 | params.chandef = &chandef; | ||
1558 | |||
1559 | params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); | ||
1560 | params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); | ||
1561 | |||
1562 | params.tmpl_skb = | ||
1563 | ieee80211_tdls_ch_sw_resp_tmpl_get(sta, | ||
1564 | ¶ms.ch_sw_tm_ie); | ||
1565 | if (!params.tmpl_skb) { | ||
1566 | ret = -ENOENT; | ||
1567 | goto out; | ||
1568 | } | ||
1569 | |||
1570 | drv_tdls_recv_channel_switch(sdata->local, sdata, ¶ms); | ||
1571 | |||
1572 | tdls_dbg(sdata, | ||
1573 | "TDLS ch switch request received from %pM ch %d width %d\n", | ||
1574 | tf->sa, params.chandef->chan->center_freq, | ||
1575 | params.chandef->width); | ||
1576 | out: | ||
1577 | mutex_unlock(&local->sta_mtx); | ||
1578 | dev_kfree_skb_any(params.tmpl_skb); | ||
1579 | return ret; | ||
1580 | } | ||
1581 | |||
1582 | void ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata, | ||
1583 | struct sk_buff *skb) | ||
1584 | { | ||
1585 | struct ieee80211_tdls_data *tf = (void *)skb->data; | ||
1586 | struct wiphy *wiphy = sdata->local->hw.wiphy; | ||
1587 | |||
1588 | /* make sure the driver supports it */ | ||
1589 | if (!(wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH)) | ||
1590 | return; | ||
1591 | |||
1592 | /* we want to access the entire packet */ | ||
1593 | if (skb_linearize(skb)) | ||
1594 | return; | ||
1595 | /* | ||
1596 | * The packet/size was already validated by mac80211 Rx path, only look | ||
1597 | * at the action type. | ||
1598 | */ | ||
1599 | switch (tf->action_code) { | ||
1600 | case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: | ||
1601 | ieee80211_process_tdls_channel_switch_req(sdata, skb); | ||
1602 | break; | ||
1603 | case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: | ||
1604 | ieee80211_process_tdls_channel_switch_resp(sdata, skb); | ||
1605 | break; | ||
1606 | default: | ||
1607 | WARN_ON_ONCE(1); | ||
1608 | return; | ||
1609 | } | ||
1610 | } | ||
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 809a4983eb4a..85ccfbe863db 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #define STA_ENTRY __array(char, sta_addr, ETH_ALEN) | 17 | #define STA_ENTRY __array(char, sta_addr, ETH_ALEN) |
18 | #define STA_ASSIGN (sta ? memcpy(__entry->sta_addr, sta->addr, ETH_ALEN) : memset(__entry->sta_addr, 0, ETH_ALEN)) | 18 | #define STA_ASSIGN (sta ? memcpy(__entry->sta_addr, sta->addr, ETH_ALEN) : memset(__entry->sta_addr, 0, ETH_ALEN)) |
19 | #define STA_NAMED_ASSIGN(s) memcpy(__entry->sta_addr, (s)->addr, ETH_ALEN) | ||
19 | #define STA_PR_FMT " sta:%pM" | 20 | #define STA_PR_FMT " sta:%pM" |
20 | #define STA_PR_ARG __entry->sta_addr | 21 | #define STA_PR_ARG __entry->sta_addr |
21 | 22 | ||
@@ -595,14 +596,33 @@ DEFINE_EVENT(local_sdata_evt, drv_sched_scan_stop, | |||
595 | TP_ARGS(local, sdata) | 596 | TP_ARGS(local, sdata) |
596 | ); | 597 | ); |
597 | 598 | ||
598 | DEFINE_EVENT(local_only_evt, drv_sw_scan_start, | 599 | TRACE_EVENT(drv_sw_scan_start, |
599 | TP_PROTO(struct ieee80211_local *local), | 600 | TP_PROTO(struct ieee80211_local *local, |
600 | TP_ARGS(local) | 601 | struct ieee80211_sub_if_data *sdata, |
602 | const u8 *mac_addr), | ||
603 | |||
604 | TP_ARGS(local, sdata, mac_addr), | ||
605 | |||
606 | TP_STRUCT__entry( | ||
607 | LOCAL_ENTRY | ||
608 | VIF_ENTRY | ||
609 | __array(char, mac_addr, ETH_ALEN) | ||
610 | ), | ||
611 | |||
612 | TP_fast_assign( | ||
613 | LOCAL_ASSIGN; | ||
614 | VIF_ASSIGN; | ||
615 | memcpy(__entry->mac_addr, mac_addr, ETH_ALEN); | ||
616 | ), | ||
617 | |||
618 | TP_printk(LOCAL_PR_FMT ", " VIF_PR_FMT ", addr:%pM", | ||
619 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->mac_addr) | ||
601 | ); | 620 | ); |
602 | 621 | ||
603 | DEFINE_EVENT(local_only_evt, drv_sw_scan_complete, | 622 | DEFINE_EVENT(local_sdata_evt, drv_sw_scan_complete, |
604 | TP_PROTO(struct ieee80211_local *local), | 623 | TP_PROTO(struct ieee80211_local *local, |
605 | TP_ARGS(local) | 624 | struct ieee80211_sub_if_data *sdata), |
625 | TP_ARGS(local, sdata) | ||
606 | ); | 626 | ); |
607 | 627 | ||
608 | TRACE_EVENT(drv_get_stats, | 628 | TRACE_EVENT(drv_get_stats, |
@@ -826,6 +846,13 @@ DEFINE_EVENT(sta_event, drv_sta_pre_rcu_remove, | |||
826 | TP_ARGS(local, sdata, sta) | 846 | TP_ARGS(local, sdata, sta) |
827 | ); | 847 | ); |
828 | 848 | ||
849 | DEFINE_EVENT(sta_event, drv_sta_rate_tbl_update, | ||
850 | TP_PROTO(struct ieee80211_local *local, | ||
851 | struct ieee80211_sub_if_data *sdata, | ||
852 | struct ieee80211_sta *sta), | ||
853 | TP_ARGS(local, sdata, sta) | ||
854 | ); | ||
855 | |||
829 | TRACE_EVENT(drv_conf_tx, | 856 | TRACE_EVENT(drv_conf_tx, |
830 | TP_PROTO(struct ieee80211_local *local, | 857 | TP_PROTO(struct ieee80211_local *local, |
831 | struct ieee80211_sub_if_data *sdata, | 858 | struct ieee80211_sub_if_data *sdata, |
@@ -2140,6 +2167,7 @@ TRACE_EVENT(drv_pre_channel_switch, | |||
2140 | VIF_ENTRY | 2167 | VIF_ENTRY |
2141 | CHANDEF_ENTRY | 2168 | CHANDEF_ENTRY |
2142 | __field(u64, timestamp) | 2169 | __field(u64, timestamp) |
2170 | __field(u32, device_timestamp) | ||
2143 | __field(bool, block_tx) | 2171 | __field(bool, block_tx) |
2144 | __field(u8, count) | 2172 | __field(u8, count) |
2145 | ), | 2173 | ), |
@@ -2149,6 +2177,7 @@ TRACE_EVENT(drv_pre_channel_switch, | |||
2149 | VIF_ASSIGN; | 2177 | VIF_ASSIGN; |
2150 | CHANDEF_ASSIGN(&ch_switch->chandef) | 2178 | CHANDEF_ASSIGN(&ch_switch->chandef) |
2151 | __entry->timestamp = ch_switch->timestamp; | 2179 | __entry->timestamp = ch_switch->timestamp; |
2180 | __entry->device_timestamp = ch_switch->device_timestamp; | ||
2152 | __entry->block_tx = ch_switch->block_tx; | 2181 | __entry->block_tx = ch_switch->block_tx; |
2153 | __entry->count = ch_switch->count; | 2182 | __entry->count = ch_switch->count; |
2154 | ), | 2183 | ), |
@@ -2194,6 +2223,107 @@ TRACE_EVENT(drv_get_txpower, | |||
2194 | ) | 2223 | ) |
2195 | ); | 2224 | ); |
2196 | 2225 | ||
2226 | TRACE_EVENT(drv_tdls_channel_switch, | ||
2227 | TP_PROTO(struct ieee80211_local *local, | ||
2228 | struct ieee80211_sub_if_data *sdata, | ||
2229 | struct ieee80211_sta *sta, u8 oper_class, | ||
2230 | struct cfg80211_chan_def *chandef), | ||
2231 | |||
2232 | TP_ARGS(local, sdata, sta, oper_class, chandef), | ||
2233 | |||
2234 | TP_STRUCT__entry( | ||
2235 | LOCAL_ENTRY | ||
2236 | VIF_ENTRY | ||
2237 | STA_ENTRY | ||
2238 | __field(u8, oper_class) | ||
2239 | CHANDEF_ENTRY | ||
2240 | ), | ||
2241 | |||
2242 | TP_fast_assign( | ||
2243 | LOCAL_ASSIGN; | ||
2244 | VIF_ASSIGN; | ||
2245 | STA_ASSIGN; | ||
2246 | __entry->oper_class = oper_class; | ||
2247 | CHANDEF_ASSIGN(chandef) | ||
2248 | ), | ||
2249 | |||
2250 | TP_printk( | ||
2251 | LOCAL_PR_FMT VIF_PR_FMT " tdls channel switch to" | ||
2252 | CHANDEF_PR_FMT " oper_class:%d " STA_PR_FMT, | ||
2253 | LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->oper_class, | ||
2254 | STA_PR_ARG | ||
2255 | ) | ||
2256 | ); | ||
2257 | |||
2258 | TRACE_EVENT(drv_tdls_cancel_channel_switch, | ||
2259 | TP_PROTO(struct ieee80211_local *local, | ||
2260 | struct ieee80211_sub_if_data *sdata, | ||
2261 | struct ieee80211_sta *sta), | ||
2262 | |||
2263 | TP_ARGS(local, sdata, sta), | ||
2264 | |||
2265 | TP_STRUCT__entry( | ||
2266 | LOCAL_ENTRY | ||
2267 | VIF_ENTRY | ||
2268 | STA_ENTRY | ||
2269 | ), | ||
2270 | |||
2271 | TP_fast_assign( | ||
2272 | LOCAL_ASSIGN; | ||
2273 | VIF_ASSIGN; | ||
2274 | STA_ASSIGN; | ||
2275 | ), | ||
2276 | |||
2277 | TP_printk( | ||
2278 | LOCAL_PR_FMT VIF_PR_FMT | ||
2279 | " tdls cancel channel switch with " STA_PR_FMT, | ||
2280 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG | ||
2281 | ) | ||
2282 | ); | ||
2283 | |||
2284 | TRACE_EVENT(drv_tdls_recv_channel_switch, | ||
2285 | TP_PROTO(struct ieee80211_local *local, | ||
2286 | struct ieee80211_sub_if_data *sdata, | ||
2287 | struct ieee80211_tdls_ch_sw_params *params), | ||
2288 | |||
2289 | TP_ARGS(local, sdata, params), | ||
2290 | |||
2291 | TP_STRUCT__entry( | ||
2292 | LOCAL_ENTRY | ||
2293 | VIF_ENTRY | ||
2294 | __field(u8, action_code) | ||
2295 | STA_ENTRY | ||
2296 | CHANDEF_ENTRY | ||
2297 | __field(u32, status) | ||
2298 | __field(bool, peer_initiator) | ||
2299 | __field(u32, timestamp) | ||
2300 | __field(u16, switch_time) | ||
2301 | __field(u16, switch_timeout) | ||
2302 | ), | ||
2303 | |||
2304 | TP_fast_assign( | ||
2305 | LOCAL_ASSIGN; | ||
2306 | VIF_ASSIGN; | ||
2307 | STA_NAMED_ASSIGN(params->sta); | ||
2308 | CHANDEF_ASSIGN(params->chandef) | ||
2309 | __entry->peer_initiator = params->sta->tdls_initiator; | ||
2310 | __entry->action_code = params->action_code; | ||
2311 | __entry->status = params->status; | ||
2312 | __entry->timestamp = params->timestamp; | ||
2313 | __entry->switch_time = params->switch_time; | ||
2314 | __entry->switch_timeout = params->switch_timeout; | ||
2315 | ), | ||
2316 | |||
2317 | TP_printk( | ||
2318 | LOCAL_PR_FMT VIF_PR_FMT " received tdls channel switch packet" | ||
2319 | " action:%d status:%d time:%d switch time:%d switch" | ||
2320 | " timeout:%d initiator: %d chan:" CHANDEF_PR_FMT STA_PR_FMT, | ||
2321 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->action_code, __entry->status, | ||
2322 | __entry->timestamp, __entry->switch_time, | ||
2323 | __entry->switch_timeout, __entry->peer_initiator, | ||
2324 | CHANDEF_PR_ARG, STA_PR_ARG | ||
2325 | ) | ||
2326 | ); | ||
2197 | 2327 | ||
2198 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING | 2328 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING |
2199 | #undef TRACE_SYSTEM | 2329 | #undef TRACE_SYSTEM |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3ffd91f295a6..66ddbbeccd20 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1426,8 +1426,7 @@ EXPORT_SYMBOL(ieee80211_tx_prepare_skb); | |||
1426 | * Returns false if the frame couldn't be transmitted but was queued instead. | 1426 | * Returns false if the frame couldn't be transmitted but was queued instead. |
1427 | */ | 1427 | */ |
1428 | static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | 1428 | static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, |
1429 | struct sk_buff *skb, bool txpending, | 1429 | struct sk_buff *skb, bool txpending) |
1430 | enum ieee80211_band band) | ||
1431 | { | 1430 | { |
1432 | struct ieee80211_local *local = sdata->local; | 1431 | struct ieee80211_local *local = sdata->local; |
1433 | struct ieee80211_tx_data tx; | 1432 | struct ieee80211_tx_data tx; |
@@ -1452,8 +1451,6 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, | |||
1452 | return true; | 1451 | return true; |
1453 | } | 1452 | } |
1454 | 1453 | ||
1455 | info->band = band; | ||
1456 | |||
1457 | /* set up hw_queue value early */ | 1454 | /* set up hw_queue value early */ |
1458 | if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || | 1455 | if (!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || |
1459 | !(local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) | 1456 | !(local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) |
@@ -1501,8 +1498,7 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, | |||
1501 | return 0; | 1498 | return 0; |
1502 | } | 1499 | } |
1503 | 1500 | ||
1504 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 1501 | void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) |
1505 | enum ieee80211_band band) | ||
1506 | { | 1502 | { |
1507 | struct ieee80211_local *local = sdata->local; | 1503 | struct ieee80211_local *local = sdata->local; |
1508 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1504 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
@@ -1537,7 +1533,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
1537 | } | 1533 | } |
1538 | 1534 | ||
1539 | ieee80211_set_qos_hdr(sdata, skb); | 1535 | ieee80211_set_qos_hdr(sdata, skb); |
1540 | ieee80211_tx(sdata, skb, false, band); | 1536 | ieee80211_tx(sdata, skb, false); |
1541 | } | 1537 | } |
1542 | 1538 | ||
1543 | static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) | 1539 | static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) |
@@ -1757,7 +1753,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, | |||
1757 | sdata->vif.type)) | 1753 | sdata->vif.type)) |
1758 | goto fail_rcu; | 1754 | goto fail_rcu; |
1759 | 1755 | ||
1760 | ieee80211_xmit(sdata, skb, chandef->chan->band); | 1756 | info->band = chandef->chan->band; |
1757 | ieee80211_xmit(sdata, skb); | ||
1761 | rcu_read_unlock(); | 1758 | rcu_read_unlock(); |
1762 | 1759 | ||
1763 | return NETDEV_TX_OK; | 1760 | return NETDEV_TX_OK; |
@@ -1787,23 +1784,26 @@ static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local, | |||
1787 | } | 1784 | } |
1788 | 1785 | ||
1789 | /** | 1786 | /** |
1790 | * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type | 1787 | * ieee80211_build_hdr - build 802.11 header in the given frame |
1791 | * subinterfaces (wlan#, WDS, and VLAN interfaces) | 1788 | * @sdata: virtual interface to build the header for |
1792 | * @skb: packet to be sent | 1789 | * @skb: the skb to build the header in |
1793 | * @dev: incoming interface | 1790 | * @info_flags: skb flags to set |
1791 | * | ||
1792 | * This function takes the skb with 802.3 header and reformats the header to | ||
1793 | * the appropriate IEEE 802.11 header based on which interface the packet is | ||
1794 | * being transmitted on. | ||
1794 | * | 1795 | * |
1795 | * Returns: NETDEV_TX_OK both on success and on failure. On failure skb will | 1796 | * Note that this function also takes care of the TX status request and |
1796 | * be freed. | 1797 | * potential unsharing of the SKB - this needs to be interleaved with the |
1798 | * header building. | ||
1797 | * | 1799 | * |
1798 | * This function takes in an Ethernet header and encapsulates it with suitable | 1800 | * The function requires the read-side RCU lock held |
1799 | * IEEE 802.11 header based on which interface the packet is coming in. The | 1801 | * |
1800 | * encapsulated packet will then be passed to master interface, wlan#.11, for | 1802 | * Returns: the (possibly reallocated) skb or an ERR_PTR() code |
1801 | * transmission (through low-level driver). | ||
1802 | */ | 1803 | */ |
1803 | netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | 1804 | static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, |
1804 | struct net_device *dev) | 1805 | struct sk_buff *skb, u32 info_flags) |
1805 | { | 1806 | { |
1806 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1807 | struct ieee80211_local *local = sdata->local; | 1807 | struct ieee80211_local *local = sdata->local; |
1808 | struct ieee80211_tx_info *info; | 1808 | struct ieee80211_tx_info *info; |
1809 | int head_need; | 1809 | int head_need; |
@@ -1819,25 +1819,17 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1819 | bool wme_sta = false, authorized = false, tdls_auth = false; | 1819 | bool wme_sta = false, authorized = false, tdls_auth = false; |
1820 | bool tdls_peer = false, tdls_setup_frame = false; | 1820 | bool tdls_peer = false, tdls_setup_frame = false; |
1821 | bool multicast; | 1821 | bool multicast; |
1822 | u32 info_flags = 0; | ||
1823 | u16 info_id = 0; | 1822 | u16 info_id = 0; |
1824 | struct ieee80211_chanctx_conf *chanctx_conf; | 1823 | struct ieee80211_chanctx_conf *chanctx_conf; |
1825 | struct ieee80211_sub_if_data *ap_sdata; | 1824 | struct ieee80211_sub_if_data *ap_sdata; |
1826 | enum ieee80211_band band; | 1825 | enum ieee80211_band band; |
1827 | 1826 | int ret; | |
1828 | if (unlikely(skb->len < ETH_HLEN)) | ||
1829 | goto fail; | ||
1830 | 1827 | ||
1831 | /* convert Ethernet header to proper 802.11 header (based on | 1828 | /* convert Ethernet header to proper 802.11 header (based on |
1832 | * operation mode) */ | 1829 | * operation mode) */ |
1833 | ethertype = (skb->data[12] << 8) | skb->data[13]; | 1830 | ethertype = (skb->data[12] << 8) | skb->data[13]; |
1834 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); | 1831 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); |
1835 | 1832 | ||
1836 | rcu_read_lock(); | ||
1837 | |||
1838 | /* Measure frame arrival for Tx latency statistics calculation */ | ||
1839 | ieee80211_tx_latency_start_msrmnt(local, skb); | ||
1840 | |||
1841 | switch (sdata->vif.type) { | 1833 | switch (sdata->vif.type) { |
1842 | case NL80211_IFTYPE_AP_VLAN: | 1834 | case NL80211_IFTYPE_AP_VLAN: |
1843 | sta = rcu_dereference(sdata->u.vlan.sta); | 1835 | sta = rcu_dereference(sdata->u.vlan.sta); |
@@ -1855,8 +1847,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1855 | ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, | 1847 | ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, |
1856 | u.ap); | 1848 | u.ap); |
1857 | chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf); | 1849 | chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf); |
1858 | if (!chanctx_conf) | 1850 | if (!chanctx_conf) { |
1859 | goto fail_rcu; | 1851 | ret = -ENOTCONN; |
1852 | goto free; | ||
1853 | } | ||
1860 | band = chanctx_conf->def.chan->band; | 1854 | band = chanctx_conf->def.chan->band; |
1861 | if (sta) | 1855 | if (sta) |
1862 | break; | 1856 | break; |
@@ -1864,8 +1858,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1864 | case NL80211_IFTYPE_AP: | 1858 | case NL80211_IFTYPE_AP: |
1865 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 1859 | if (sdata->vif.type == NL80211_IFTYPE_AP) |
1866 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 1860 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
1867 | if (!chanctx_conf) | 1861 | if (!chanctx_conf) { |
1868 | goto fail_rcu; | 1862 | ret = -ENOTCONN; |
1863 | goto free; | ||
1864 | } | ||
1869 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); | 1865 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
1870 | /* DA BSSID SA */ | 1866 | /* DA BSSID SA */ |
1871 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 1867 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
@@ -1952,8 +1948,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1952 | 1948 | ||
1953 | } | 1949 | } |
1954 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 1950 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
1955 | if (!chanctx_conf) | 1951 | if (!chanctx_conf) { |
1956 | goto fail_rcu; | 1952 | ret = -ENOTCONN; |
1953 | goto free; | ||
1954 | } | ||
1957 | band = chanctx_conf->def.chan->band; | 1955 | band = chanctx_conf->def.chan->band; |
1958 | break; | 1956 | break; |
1959 | #endif | 1957 | #endif |
@@ -1983,8 +1981,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1983 | * of a link teardown after a TDLS sta is removed due to being | 1981 | * of a link teardown after a TDLS sta is removed due to being |
1984 | * unreachable. | 1982 | * unreachable. |
1985 | */ | 1983 | */ |
1986 | if (tdls_peer && !tdls_auth && !tdls_setup_frame) | 1984 | if (tdls_peer && !tdls_auth && !tdls_setup_frame) { |
1987 | goto fail_rcu; | 1985 | ret = -EINVAL; |
1986 | goto free; | ||
1987 | } | ||
1988 | 1988 | ||
1989 | /* send direct packets to authorized TDLS peers */ | 1989 | /* send direct packets to authorized TDLS peers */ |
1990 | if (tdls_peer && tdls_auth) { | 1990 | if (tdls_peer && tdls_auth) { |
@@ -2012,8 +2012,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2012 | hdrlen = 24; | 2012 | hdrlen = 24; |
2013 | } | 2013 | } |
2014 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 2014 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
2015 | if (!chanctx_conf) | 2015 | if (!chanctx_conf) { |
2016 | goto fail_rcu; | 2016 | ret = -ENOTCONN; |
2017 | goto free; | ||
2018 | } | ||
2017 | band = chanctx_conf->def.chan->band; | 2019 | band = chanctx_conf->def.chan->band; |
2018 | break; | 2020 | break; |
2019 | case NL80211_IFTYPE_OCB: | 2021 | case NL80211_IFTYPE_OCB: |
@@ -2023,8 +2025,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2023 | eth_broadcast_addr(hdr.addr3); | 2025 | eth_broadcast_addr(hdr.addr3); |
2024 | hdrlen = 24; | 2026 | hdrlen = 24; |
2025 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 2027 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
2026 | if (!chanctx_conf) | 2028 | if (!chanctx_conf) { |
2027 | goto fail_rcu; | 2029 | ret = -ENOTCONN; |
2030 | goto free; | ||
2031 | } | ||
2028 | band = chanctx_conf->def.chan->band; | 2032 | band = chanctx_conf->def.chan->band; |
2029 | break; | 2033 | break; |
2030 | case NL80211_IFTYPE_ADHOC: | 2034 | case NL80211_IFTYPE_ADHOC: |
@@ -2034,12 +2038,15 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2034 | memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN); | 2038 | memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN); |
2035 | hdrlen = 24; | 2039 | hdrlen = 24; |
2036 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 2040 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
2037 | if (!chanctx_conf) | 2041 | if (!chanctx_conf) { |
2038 | goto fail_rcu; | 2042 | ret = -ENOTCONN; |
2043 | goto free; | ||
2044 | } | ||
2039 | band = chanctx_conf->def.chan->band; | 2045 | band = chanctx_conf->def.chan->band; |
2040 | break; | 2046 | break; |
2041 | default: | 2047 | default: |
2042 | goto fail_rcu; | 2048 | ret = -EINVAL; |
2049 | goto free; | ||
2043 | } | 2050 | } |
2044 | 2051 | ||
2045 | /* | 2052 | /* |
@@ -2077,12 +2084,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2077 | !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { | 2084 | !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { |
2078 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 2085 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
2079 | net_info_ratelimited("%s: dropped frame to %pM (unauthorized port)\n", | 2086 | net_info_ratelimited("%s: dropped frame to %pM (unauthorized port)\n", |
2080 | dev->name, hdr.addr1); | 2087 | sdata->name, hdr.addr1); |
2081 | #endif | 2088 | #endif |
2082 | 2089 | ||
2083 | I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); | 2090 | I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); |
2084 | 2091 | ||
2085 | goto fail_rcu; | 2092 | ret = -EPERM; |
2093 | goto free; | ||
2086 | } | 2094 | } |
2087 | 2095 | ||
2088 | if (unlikely(!multicast && skb->sk && | 2096 | if (unlikely(!multicast && skb->sk && |
@@ -2119,8 +2127,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2119 | skb = skb_clone(skb, GFP_ATOMIC); | 2127 | skb = skb_clone(skb, GFP_ATOMIC); |
2120 | kfree_skb(tmp_skb); | 2128 | kfree_skb(tmp_skb); |
2121 | 2129 | ||
2122 | if (!skb) | 2130 | if (!skb) { |
2123 | goto fail_rcu; | 2131 | ret = -ENOMEM; |
2132 | goto free; | ||
2133 | } | ||
2124 | } | 2134 | } |
2125 | 2135 | ||
2126 | hdr.frame_control = fc; | 2136 | hdr.frame_control = fc; |
@@ -2169,7 +2179,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2169 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { | 2179 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { |
2170 | ieee80211_free_txskb(&local->hw, skb); | 2180 | ieee80211_free_txskb(&local->hw, skb); |
2171 | skb = NULL; | 2181 | skb = NULL; |
2172 | goto fail_rcu; | 2182 | return ERR_PTR(-ENOMEM); |
2173 | } | 2183 | } |
2174 | } | 2184 | } |
2175 | 2185 | ||
@@ -2203,9 +2213,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2203 | nh_pos += hdrlen; | 2213 | nh_pos += hdrlen; |
2204 | h_pos += hdrlen; | 2214 | h_pos += hdrlen; |
2205 | 2215 | ||
2206 | dev->stats.tx_packets++; | ||
2207 | dev->stats.tx_bytes += skb->len; | ||
2208 | |||
2209 | /* Update skb pointers to various headers since this modified frame | 2216 | /* Update skb pointers to various headers since this modified frame |
2210 | * is going to go through Linux networking code that may potentially | 2217 | * is going to go through Linux networking code that may potentially |
2211 | * need things like pointer to IP header. */ | 2218 | * need things like pointer to IP header. */ |
@@ -2216,23 +2223,90 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2216 | info = IEEE80211_SKB_CB(skb); | 2223 | info = IEEE80211_SKB_CB(skb); |
2217 | memset(info, 0, sizeof(*info)); | 2224 | memset(info, 0, sizeof(*info)); |
2218 | 2225 | ||
2219 | dev->trans_start = jiffies; | ||
2220 | |||
2221 | info->flags = info_flags; | 2226 | info->flags = info_flags; |
2222 | info->ack_frame_id = info_id; | 2227 | info->ack_frame_id = info_id; |
2228 | info->band = band; | ||
2223 | 2229 | ||
2224 | ieee80211_xmit(sdata, skb, band); | 2230 | return skb; |
2225 | rcu_read_unlock(); | 2231 | free: |
2232 | kfree_skb(skb); | ||
2233 | return ERR_PTR(ret); | ||
2234 | } | ||
2226 | 2235 | ||
2227 | return NETDEV_TX_OK; | 2236 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, |
2237 | struct net_device *dev, | ||
2238 | u32 info_flags) | ||
2239 | { | ||
2240 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2241 | struct ieee80211_local *local = sdata->local; | ||
2242 | |||
2243 | if (unlikely(skb->len < ETH_HLEN)) { | ||
2244 | kfree_skb(skb); | ||
2245 | return; | ||
2246 | } | ||
2247 | |||
2248 | rcu_read_lock(); | ||
2249 | |||
2250 | /* Measure frame arrival for Tx latency statistics calculation */ | ||
2251 | ieee80211_tx_latency_start_msrmnt(local, skb); | ||
2252 | |||
2253 | skb = ieee80211_build_hdr(sdata, skb, info_flags); | ||
2254 | if (IS_ERR(skb)) | ||
2255 | goto out; | ||
2256 | |||
2257 | dev->stats.tx_packets++; | ||
2258 | dev->stats.tx_bytes += skb->len; | ||
2259 | dev->trans_start = jiffies; | ||
2228 | 2260 | ||
2229 | fail_rcu: | 2261 | ieee80211_xmit(sdata, skb); |
2262 | out: | ||
2230 | rcu_read_unlock(); | 2263 | rcu_read_unlock(); |
2231 | fail: | 2264 | } |
2232 | dev_kfree_skb(skb); | 2265 | |
2266 | /** | ||
2267 | * ieee80211_subif_start_xmit - netif start_xmit function for 802.3 vifs | ||
2268 | * @skb: packet to be sent | ||
2269 | * @dev: incoming interface | ||
2270 | * | ||
2271 | * On failure skb will be freed. | ||
2272 | */ | ||
2273 | netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | ||
2274 | struct net_device *dev) | ||
2275 | { | ||
2276 | __ieee80211_subif_start_xmit(skb, dev, 0); | ||
2233 | return NETDEV_TX_OK; | 2277 | return NETDEV_TX_OK; |
2234 | } | 2278 | } |
2235 | 2279 | ||
2280 | struct sk_buff * | ||
2281 | ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata, | ||
2282 | struct sk_buff *skb, u32 info_flags) | ||
2283 | { | ||
2284 | struct ieee80211_hdr *hdr; | ||
2285 | struct ieee80211_tx_data tx = { | ||
2286 | .local = sdata->local, | ||
2287 | .sdata = sdata, | ||
2288 | }; | ||
2289 | |||
2290 | rcu_read_lock(); | ||
2291 | |||
2292 | skb = ieee80211_build_hdr(sdata, skb, info_flags); | ||
2293 | if (IS_ERR(skb)) | ||
2294 | goto out; | ||
2295 | |||
2296 | hdr = (void *)skb->data; | ||
2297 | tx.sta = sta_info_get(sdata, hdr->addr1); | ||
2298 | tx.skb = skb; | ||
2299 | |||
2300 | if (ieee80211_tx_h_select_key(&tx) != TX_CONTINUE) { | ||
2301 | rcu_read_unlock(); | ||
2302 | kfree_skb(skb); | ||
2303 | return ERR_PTR(-EINVAL); | ||
2304 | } | ||
2305 | |||
2306 | out: | ||
2307 | rcu_read_unlock(); | ||
2308 | return skb; | ||
2309 | } | ||
2236 | 2310 | ||
2237 | /* | 2311 | /* |
2238 | * ieee80211_clear_tx_pending may not be called in a context where | 2312 | * ieee80211_clear_tx_pending may not be called in a context where |
@@ -2272,8 +2346,8 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, | |||
2272 | dev_kfree_skb(skb); | 2346 | dev_kfree_skb(skb); |
2273 | return true; | 2347 | return true; |
2274 | } | 2348 | } |
2275 | result = ieee80211_tx(sdata, skb, true, | 2349 | info->band = chanctx_conf->def.chan->band; |
2276 | chanctx_conf->def.chan->band); | 2350 | result = ieee80211_tx(sdata, skb, true); |
2277 | } else { | 2351 | } else { |
2278 | struct sk_buff_head skbs; | 2352 | struct sk_buff_head skbs; |
2279 | 2353 | ||
@@ -2887,19 +2961,16 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, | |||
2887 | EXPORT_SYMBOL(ieee80211_nullfunc_get); | 2961 | EXPORT_SYMBOL(ieee80211_nullfunc_get); |
2888 | 2962 | ||
2889 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | 2963 | struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, |
2890 | struct ieee80211_vif *vif, | 2964 | const u8 *src_addr, |
2891 | const u8 *ssid, size_t ssid_len, | 2965 | const u8 *ssid, size_t ssid_len, |
2892 | size_t tailroom) | 2966 | size_t tailroom) |
2893 | { | 2967 | { |
2894 | struct ieee80211_sub_if_data *sdata; | 2968 | struct ieee80211_local *local = hw_to_local(hw); |
2895 | struct ieee80211_local *local; | ||
2896 | struct ieee80211_hdr_3addr *hdr; | 2969 | struct ieee80211_hdr_3addr *hdr; |
2897 | struct sk_buff *skb; | 2970 | struct sk_buff *skb; |
2898 | size_t ie_ssid_len; | 2971 | size_t ie_ssid_len; |
2899 | u8 *pos; | 2972 | u8 *pos; |
2900 | 2973 | ||
2901 | sdata = vif_to_sdata(vif); | ||
2902 | local = sdata->local; | ||
2903 | ie_ssid_len = 2 + ssid_len; | 2974 | ie_ssid_len = 2 + ssid_len; |
2904 | 2975 | ||
2905 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + | 2976 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + |
@@ -2914,7 +2985,7 @@ struct sk_buff *ieee80211_probereq_get(struct ieee80211_hw *hw, | |||
2914 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 2985 | hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
2915 | IEEE80211_STYPE_PROBE_REQ); | 2986 | IEEE80211_STYPE_PROBE_REQ); |
2916 | eth_broadcast_addr(hdr->addr1); | 2987 | eth_broadcast_addr(hdr->addr1); |
2917 | memcpy(hdr->addr2, vif->addr, ETH_ALEN); | 2988 | memcpy(hdr->addr2, src_addr, ETH_ALEN); |
2918 | eth_broadcast_addr(hdr->addr3); | 2989 | eth_broadcast_addr(hdr->addr3); |
2919 | 2990 | ||
2920 | pos = skb_put(skb, ie_ssid_len); | 2991 | pos = skb_put(skb, ie_ssid_len); |
@@ -3033,6 +3104,97 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
3033 | } | 3104 | } |
3034 | EXPORT_SYMBOL(ieee80211_get_buffered_bc); | 3105 | EXPORT_SYMBOL(ieee80211_get_buffered_bc); |
3035 | 3106 | ||
3107 | int ieee80211_reserve_tid(struct ieee80211_sta *pubsta, u8 tid) | ||
3108 | { | ||
3109 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
3110 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
3111 | struct ieee80211_local *local = sdata->local; | ||
3112 | int ret; | ||
3113 | u32 queues; | ||
3114 | |||
3115 | lockdep_assert_held(&local->sta_mtx); | ||
3116 | |||
3117 | /* only some cases are supported right now */ | ||
3118 | switch (sdata->vif.type) { | ||
3119 | case NL80211_IFTYPE_STATION: | ||
3120 | case NL80211_IFTYPE_AP: | ||
3121 | case NL80211_IFTYPE_AP_VLAN: | ||
3122 | break; | ||
3123 | default: | ||
3124 | WARN_ON(1); | ||
3125 | return -EINVAL; | ||
3126 | } | ||
3127 | |||
3128 | if (WARN_ON(tid >= IEEE80211_NUM_UPS)) | ||
3129 | return -EINVAL; | ||
3130 | |||
3131 | if (sta->reserved_tid == tid) { | ||
3132 | ret = 0; | ||
3133 | goto out; | ||
3134 | } | ||
3135 | |||
3136 | if (sta->reserved_tid != IEEE80211_TID_UNRESERVED) { | ||
3137 | sdata_err(sdata, "TID reservation already active\n"); | ||
3138 | ret = -EALREADY; | ||
3139 | goto out; | ||
3140 | } | ||
3141 | |||
3142 | ieee80211_stop_vif_queues(sdata->local, sdata, | ||
3143 | IEEE80211_QUEUE_STOP_REASON_RESERVE_TID); | ||
3144 | |||
3145 | synchronize_net(); | ||
3146 | |||
3147 | /* Tear down BA sessions so we stop aggregating on this TID */ | ||
3148 | if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
3149 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); | ||
3150 | __ieee80211_stop_tx_ba_session(sta, tid, | ||
3151 | AGG_STOP_LOCAL_REQUEST); | ||
3152 | } | ||
3153 | |||
3154 | queues = BIT(sdata->vif.hw_queue[ieee802_1d_to_ac[tid]]); | ||
3155 | __ieee80211_flush_queues(local, sdata, queues); | ||
3156 | |||
3157 | sta->reserved_tid = tid; | ||
3158 | |||
3159 | ieee80211_wake_vif_queues(local, sdata, | ||
3160 | IEEE80211_QUEUE_STOP_REASON_RESERVE_TID); | ||
3161 | |||
3162 | if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) | ||
3163 | clear_sta_flag(sta, WLAN_STA_BLOCK_BA); | ||
3164 | |||
3165 | ret = 0; | ||
3166 | out: | ||
3167 | return ret; | ||
3168 | } | ||
3169 | EXPORT_SYMBOL(ieee80211_reserve_tid); | ||
3170 | |||
3171 | void ieee80211_unreserve_tid(struct ieee80211_sta *pubsta, u8 tid) | ||
3172 | { | ||
3173 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
3174 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
3175 | |||
3176 | lockdep_assert_held(&sdata->local->sta_mtx); | ||
3177 | |||
3178 | /* only some cases are supported right now */ | ||
3179 | switch (sdata->vif.type) { | ||
3180 | case NL80211_IFTYPE_STATION: | ||
3181 | case NL80211_IFTYPE_AP: | ||
3182 | case NL80211_IFTYPE_AP_VLAN: | ||
3183 | break; | ||
3184 | default: | ||
3185 | WARN_ON(1); | ||
3186 | return; | ||
3187 | } | ||
3188 | |||
3189 | if (tid != sta->reserved_tid) { | ||
3190 | sdata_err(sdata, "TID to unreserve (%d) isn't reserved\n", tid); | ||
3191 | return; | ||
3192 | } | ||
3193 | |||
3194 | sta->reserved_tid = IEEE80211_TID_UNRESERVED; | ||
3195 | } | ||
3196 | EXPORT_SYMBOL(ieee80211_unreserve_tid); | ||
3197 | |||
3036 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, | 3198 | void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, |
3037 | struct sk_buff *skb, int tid, | 3199 | struct sk_buff *skb, int tid, |
3038 | enum ieee80211_band band) | 3200 | enum ieee80211_band band) |
@@ -3054,6 +3216,7 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, | |||
3054 | * requirements are that we do not come into tx with bhs on. | 3216 | * requirements are that we do not come into tx with bhs on. |
3055 | */ | 3217 | */ |
3056 | local_bh_disable(); | 3218 | local_bh_disable(); |
3057 | ieee80211_xmit(sdata, skb, band); | 3219 | IEEE80211_SKB_CB(skb)->band = band; |
3220 | ieee80211_xmit(sdata, skb); | ||
3058 | local_bh_enable(); | 3221 | local_bh_enable(); |
3059 | } | 3222 | } |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index f9319a5dca64..bb9664cb8831 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -576,15 +576,19 @@ ieee80211_get_vif_queues(struct ieee80211_local *local, | |||
576 | return queues; | 576 | return queues; |
577 | } | 577 | } |
578 | 578 | ||
579 | void ieee80211_flush_queues(struct ieee80211_local *local, | 579 | void __ieee80211_flush_queues(struct ieee80211_local *local, |
580 | struct ieee80211_sub_if_data *sdata) | 580 | struct ieee80211_sub_if_data *sdata, |
581 | unsigned int queues) | ||
581 | { | 582 | { |
582 | unsigned int queues; | ||
583 | |||
584 | if (!local->ops->flush) | 583 | if (!local->ops->flush) |
585 | return; | 584 | return; |
586 | 585 | ||
587 | queues = ieee80211_get_vif_queues(local, sdata); | 586 | /* |
587 | * If no queue was set, or if the HW doesn't support | ||
588 | * IEEE80211_HW_QUEUE_CONTROL - flush all queues | ||
589 | */ | ||
590 | if (!queues || !(local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)) | ||
591 | queues = ieee80211_get_vif_queues(local, sdata); | ||
588 | 592 | ||
589 | ieee80211_stop_queues_by_reason(&local->hw, queues, | 593 | ieee80211_stop_queues_by_reason(&local->hw, queues, |
590 | IEEE80211_QUEUE_STOP_REASON_FLUSH, | 594 | IEEE80211_QUEUE_STOP_REASON_FLUSH, |
@@ -597,6 +601,12 @@ void ieee80211_flush_queues(struct ieee80211_local *local, | |||
597 | false); | 601 | false); |
598 | } | 602 | } |
599 | 603 | ||
604 | void ieee80211_flush_queues(struct ieee80211_local *local, | ||
605 | struct ieee80211_sub_if_data *sdata) | ||
606 | { | ||
607 | __ieee80211_flush_queues(local, sdata, 0); | ||
608 | } | ||
609 | |||
600 | void ieee80211_stop_vif_queues(struct ieee80211_local *local, | 610 | void ieee80211_stop_vif_queues(struct ieee80211_local *local, |
601 | struct ieee80211_sub_if_data *sdata, | 611 | struct ieee80211_sub_if_data *sdata, |
602 | enum queue_stop_reason reason) | 612 | enum queue_stop_reason reason) |
@@ -831,6 +841,9 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |||
831 | case WLAN_EID_SECONDARY_CHANNEL_OFFSET: | 841 | case WLAN_EID_SECONDARY_CHANNEL_OFFSET: |
832 | case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: | 842 | case WLAN_EID_WIDE_BW_CHANNEL_SWITCH: |
833 | case WLAN_EID_CHAN_SWITCH_PARAM: | 843 | case WLAN_EID_CHAN_SWITCH_PARAM: |
844 | case WLAN_EID_EXT_CAPABILITY: | ||
845 | case WLAN_EID_CHAN_SWITCH_TIMING: | ||
846 | case WLAN_EID_LINK_ID: | ||
834 | /* | 847 | /* |
835 | * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible | 848 | * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible |
836 | * that if the content gets bigger it might be needed more than once | 849 | * that if the content gets bigger it might be needed more than once |
@@ -850,6 +863,24 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |||
850 | elem_parse_failed = false; | 863 | elem_parse_failed = false; |
851 | 864 | ||
852 | switch (id) { | 865 | switch (id) { |
866 | case WLAN_EID_LINK_ID: | ||
867 | if (elen + 2 != sizeof(struct ieee80211_tdls_lnkie)) { | ||
868 | elem_parse_failed = true; | ||
869 | break; | ||
870 | } | ||
871 | elems->lnk_id = (void *)(pos - 2); | ||
872 | break; | ||
873 | case WLAN_EID_CHAN_SWITCH_TIMING: | ||
874 | if (elen != sizeof(struct ieee80211_ch_switch_timing)) { | ||
875 | elem_parse_failed = true; | ||
876 | break; | ||
877 | } | ||
878 | elems->ch_sw_timing = (void *)pos; | ||
879 | break; | ||
880 | case WLAN_EID_EXT_CAPABILITY: | ||
881 | elems->ext_capab = pos; | ||
882 | elems->ext_capab_len = elen; | ||
883 | break; | ||
853 | case WLAN_EID_SSID: | 884 | case WLAN_EID_SSID: |
854 | elems->ssid = pos; | 885 | elems->ssid = pos; |
855 | elems->ssid_len = elen; | 886 | elems->ssid_len = elen; |
@@ -1492,7 +1523,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1492 | }; | 1523 | }; |
1493 | 1524 | ||
1494 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1525 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
1495 | u8 *dst, u32 ratemask, | 1526 | const u8 *src, const u8 *dst, |
1527 | u32 ratemask, | ||
1496 | struct ieee80211_channel *chan, | 1528 | struct ieee80211_channel *chan, |
1497 | const u8 *ssid, size_t ssid_len, | 1529 | const u8 *ssid, size_t ssid_len, |
1498 | const u8 *ie, size_t ie_len, | 1530 | const u8 *ie, size_t ie_len, |
@@ -1517,8 +1549,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1517 | else | 1549 | else |
1518 | chandef.chan = chan; | 1550 | chandef.chan = chan; |
1519 | 1551 | ||
1520 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, | 1552 | skb = ieee80211_probereq_get(&local->hw, src, ssid, ssid_len, |
1521 | ssid, ssid_len, 100 + ie_len); | 1553 | 100 + ie_len); |
1522 | if (!skb) | 1554 | if (!skb) |
1523 | return NULL; | 1555 | return NULL; |
1524 | 1556 | ||
@@ -1540,7 +1572,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1540 | return skb; | 1572 | return skb; |
1541 | } | 1573 | } |
1542 | 1574 | ||
1543 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 1575 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, |
1576 | const u8 *src, const u8 *dst, | ||
1544 | const u8 *ssid, size_t ssid_len, | 1577 | const u8 *ssid, size_t ssid_len, |
1545 | const u8 *ie, size_t ie_len, | 1578 | const u8 *ie, size_t ie_len, |
1546 | u32 ratemask, bool directed, u32 tx_flags, | 1579 | u32 ratemask, bool directed, u32 tx_flags, |
@@ -1548,7 +1581,7 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
1548 | { | 1581 | { |
1549 | struct sk_buff *skb; | 1582 | struct sk_buff *skb; |
1550 | 1583 | ||
1551 | skb = ieee80211_build_probe_req(sdata, dst, ratemask, channel, | 1584 | skb = ieee80211_build_probe_req(sdata, src, dst, ratemask, channel, |
1552 | ssid, ssid_len, | 1585 | ssid, ssid_len, |
1553 | ie, ie_len, directed); | 1586 | ie, ie_len, directed); |
1554 | if (skb) { | 1587 | if (skb) { |
@@ -1690,6 +1723,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1690 | int res, i; | 1723 | int res, i; |
1691 | bool reconfig_due_to_wowlan = false; | 1724 | bool reconfig_due_to_wowlan = false; |
1692 | struct ieee80211_sub_if_data *sched_scan_sdata; | 1725 | struct ieee80211_sub_if_data *sched_scan_sdata; |
1726 | struct cfg80211_sched_scan_request *sched_scan_req; | ||
1693 | bool sched_scan_stopped = false; | 1727 | bool sched_scan_stopped = false; |
1694 | 1728 | ||
1695 | #ifdef CONFIG_PM | 1729 | #ifdef CONFIG_PM |
@@ -1980,13 +2014,15 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1980 | mutex_lock(&local->mtx); | 2014 | mutex_lock(&local->mtx); |
1981 | sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, | 2015 | sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, |
1982 | lockdep_is_held(&local->mtx)); | 2016 | lockdep_is_held(&local->mtx)); |
1983 | if (sched_scan_sdata && local->sched_scan_req) | 2017 | sched_scan_req = rcu_dereference_protected(local->sched_scan_req, |
2018 | lockdep_is_held(&local->mtx)); | ||
2019 | if (sched_scan_sdata && sched_scan_req) | ||
1984 | /* | 2020 | /* |
1985 | * Sched scan stopped, but we don't want to report it. Instead, | 2021 | * Sched scan stopped, but we don't want to report it. Instead, |
1986 | * we're trying to reschedule. | 2022 | * we're trying to reschedule. |
1987 | */ | 2023 | */ |
1988 | if (__ieee80211_request_sched_scan_start(sched_scan_sdata, | 2024 | if (__ieee80211_request_sched_scan_start(sched_scan_sdata, |
1989 | local->sched_scan_req)) | 2025 | sched_scan_req)) |
1990 | sched_scan_stopped = true; | 2026 | sched_scan_stopped = true; |
1991 | mutex_unlock(&local->mtx); | 2027 | mutex_unlock(&local->mtx); |
1992 | 2028 | ||
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 671ce0d27a80..bc9e8fc48785 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -287,6 +287,8 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta) | |||
287 | /* fall through */ | 287 | /* fall through */ |
288 | case NL80211_CHAN_WIDTH_20_NOHT: | 288 | case NL80211_CHAN_WIDTH_20_NOHT: |
289 | case NL80211_CHAN_WIDTH_20: | 289 | case NL80211_CHAN_WIDTH_20: |
290 | bw = IEEE80211_STA_RX_BW_20; | ||
291 | break; | ||
290 | case NL80211_CHAN_WIDTH_40: | 292 | case NL80211_CHAN_WIDTH_40: |
291 | bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | 293 | bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? |
292 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | 294 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; |
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index fdf52db95b33..9eb0aee9105b 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -53,6 +53,36 @@ static int wme_downgrade_ac(struct sk_buff *skb) | |||
53 | } | 53 | } |
54 | } | 54 | } |
55 | 55 | ||
56 | /** | ||
57 | * ieee80211_fix_reserved_tid - return the TID to use if this one is reserved | ||
58 | * @tid: the assumed-reserved TID | ||
59 | * | ||
60 | * Returns: the alternative TID to use, or 0 on error | ||
61 | */ | ||
62 | static inline u8 ieee80211_fix_reserved_tid(u8 tid) | ||
63 | { | ||
64 | switch (tid) { | ||
65 | case 0: | ||
66 | return 3; | ||
67 | case 1: | ||
68 | return 2; | ||
69 | case 2: | ||
70 | return 1; | ||
71 | case 3: | ||
72 | return 0; | ||
73 | case 4: | ||
74 | return 5; | ||
75 | case 5: | ||
76 | return 4; | ||
77 | case 6: | ||
78 | return 7; | ||
79 | case 7: | ||
80 | return 6; | ||
81 | } | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
56 | static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, | 86 | static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, |
57 | struct sta_info *sta, struct sk_buff *skb) | 87 | struct sta_info *sta, struct sk_buff *skb) |
58 | { | 88 | { |
@@ -77,6 +107,10 @@ static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, | |||
77 | } | 107 | } |
78 | } | 108 | } |
79 | 109 | ||
110 | /* Check to see if this is a reserved TID */ | ||
111 | if (sta && sta->reserved_tid == skb->priority) | ||
112 | skb->priority = ieee80211_fix_reserved_tid(skb->priority); | ||
113 | |||
80 | /* look up which queue to use for frames with this 1d tag */ | 114 | /* look up which queue to use for frames with this 1d tag */ |
81 | return ieee802_1d_to_ac[skb->priority]; | 115 | return ieee802_1d_to_ac[skb->priority]; |
82 | } | 116 | } |
@@ -143,6 +177,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
143 | break; | 177 | break; |
144 | #endif | 178 | #endif |
145 | case NL80211_IFTYPE_STATION: | 179 | case NL80211_IFTYPE_STATION: |
180 | /* might be a TDLS station */ | ||
181 | sta = sta_info_get(sdata, skb->data); | ||
182 | if (sta) | ||
183 | qos = sta->sta.wme; | ||
184 | |||
146 | ra = sdata->u.mgd.bssid; | 185 | ra = sdata->u.mgd.bssid; |
147 | break; | 186 | break; |
148 | case NL80211_IFTYPE_ADHOC: | 187 | case NL80211_IFTYPE_ADHOC: |