diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-11-16 13:59:51 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-11-16 13:59:51 -0500 |
commit | 0f62248501cbf5047486601d7e39d5ee36d478c2 (patch) | |
tree | 66119712683a8e1d4d4339d72864ceeb7e1806f0 | |
parent | b8d9e572cb8794335fb4ba63ff962acaa3c4473b (diff) | |
parent | 6352c87ff69daa2211419ec2c34ddb8bc116c505 (diff) |
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
41 files changed, 1324 insertions, 481 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 9f31cfa56cc..cdd19232960 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c | |||
@@ -511,8 +511,9 @@ ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah, | |||
511 | ath5k_vif_iter(&iter_data, vif->addr, vif); | 511 | ath5k_vif_iter(&iter_data, vif->addr, vif); |
512 | 512 | ||
513 | /* Get list of all active MAC addresses */ | 513 | /* Get list of all active MAC addresses */ |
514 | ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter, | 514 | ieee80211_iterate_active_interfaces_atomic( |
515 | &iter_data); | 515 | ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
516 | ath5k_vif_iter, &iter_data); | ||
516 | memcpy(ah->bssidmask, iter_data.mask, ETH_ALEN); | 517 | memcpy(ah->bssidmask, iter_data.mask, ETH_ALEN); |
517 | 518 | ||
518 | ah->opmode = iter_data.opmode; | 519 | ah->opmode = iter_data.opmode; |
@@ -3045,8 +3046,9 @@ ath5k_any_vif_assoc(struct ath5k_hw *ah) | |||
3045 | iter_data.need_set_hw_addr = false; | 3046 | iter_data.need_set_hw_addr = false; |
3046 | iter_data.found_active = true; | 3047 | iter_data.found_active = true; |
3047 | 3048 | ||
3048 | ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter, | 3049 | ieee80211_iterate_active_interfaces_atomic( |
3049 | &iter_data); | 3050 | ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
3051 | ath5k_vif_iter, &iter_data); | ||
3050 | return iter_data.any_assoc; | 3052 | return iter_data.any_assoc; |
3051 | } | 3053 | } |
3052 | 3054 | ||
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 7a28538e6e0..1ea8c8795c8 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c | |||
@@ -452,8 +452,9 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, | |||
452 | iter_data.hw_macaddr = NULL; | 452 | iter_data.hw_macaddr = NULL; |
453 | iter_data.n_stas = 0; | 453 | iter_data.n_stas = 0; |
454 | iter_data.need_set_hw_addr = false; | 454 | iter_data.need_set_hw_addr = false; |
455 | ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter, | 455 | ieee80211_iterate_active_interfaces_atomic( |
456 | &iter_data); | 456 | ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
457 | ath5k_vif_iter, &iter_data); | ||
457 | 458 | ||
458 | /* Set up RX Filter */ | 459 | /* Set up RX Filter */ |
459 | if (iter_data.n_stas > 1) { | 460 | if (iter_data.n_stas > 1) { |
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 277089963eb..d615f9f7506 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -1384,11 +1384,8 @@ static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
1384 | return 0; | 1384 | return 0; |
1385 | } | 1385 | } |
1386 | 1386 | ||
1387 | /* | ||
1388 | * The type nl80211_tx_power_setting replaces the following | ||
1389 | * data type from 2.6.36 onwards | ||
1390 | */ | ||
1391 | static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, | 1387 | static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, |
1388 | struct wireless_dev *wdev, | ||
1392 | enum nl80211_tx_power_setting type, | 1389 | enum nl80211_tx_power_setting type, |
1393 | int mbm) | 1390 | int mbm) |
1394 | { | 1391 | { |
@@ -1423,7 +1420,9 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, | |||
1423 | return 0; | 1420 | return 0; |
1424 | } | 1421 | } |
1425 | 1422 | ||
1426 | static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) | 1423 | static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, |
1424 | struct wireless_dev *wdev, | ||
1425 | int *dbm) | ||
1427 | { | 1426 | { |
1428 | struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); | 1427 | struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); |
1429 | struct ath6kl_vif *vif; | 1428 | struct ath6kl_vif *vif; |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index f42d2eb6af9..1318d79f5c4 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c | |||
@@ -587,9 +587,9 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv, | |||
587 | (priv->num_sta_vif > 1) && | 587 | (priv->num_sta_vif > 1) && |
588 | (vif->type == NL80211_IFTYPE_STATION)) { | 588 | (vif->type == NL80211_IFTYPE_STATION)) { |
589 | beacon_configured = false; | 589 | beacon_configured = false; |
590 | ieee80211_iterate_active_interfaces_atomic(priv->hw, | 590 | ieee80211_iterate_active_interfaces_atomic( |
591 | ath9k_htc_beacon_iter, | 591 | priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
592 | &beacon_configured); | 592 | ath9k_htc_beacon_iter, &beacon_configured); |
593 | 593 | ||
594 | if (beacon_configured) { | 594 | if (beacon_configured) { |
595 | ath_dbg(common, CONFIG, | 595 | ath_dbg(common, CONFIG, |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 66f6a74c508..02cce95331d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -127,8 +127,9 @@ static void ath9k_htc_vif_reconfig(struct ath9k_htc_priv *priv) | |||
127 | priv->rearm_ani = false; | 127 | priv->rearm_ani = false; |
128 | priv->reconfig_beacon = false; | 128 | priv->reconfig_beacon = false; |
129 | 129 | ||
130 | ieee80211_iterate_active_interfaces_atomic(priv->hw, | 130 | ieee80211_iterate_active_interfaces_atomic( |
131 | ath9k_htc_vif_iter, priv); | 131 | priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
132 | ath9k_htc_vif_iter, priv); | ||
132 | if (priv->rearm_ani) | 133 | if (priv->rearm_ani) |
133 | ath9k_htc_start_ani(priv); | 134 | ath9k_htc_start_ani(priv); |
134 | 135 | ||
@@ -165,8 +166,9 @@ static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv, | |||
165 | ath9k_htc_bssid_iter(&iter_data, vif->addr, vif); | 166 | ath9k_htc_bssid_iter(&iter_data, vif->addr, vif); |
166 | 167 | ||
167 | /* Get list of all active MAC addresses */ | 168 | /* Get list of all active MAC addresses */ |
168 | ieee80211_iterate_active_interfaces_atomic(priv->hw, ath9k_htc_bssid_iter, | 169 | ieee80211_iterate_active_interfaces_atomic( |
169 | &iter_data); | 170 | priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
171 | ath9k_htc_bssid_iter, &iter_data); | ||
170 | 172 | ||
171 | memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); | 173 | memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); |
172 | ath_hw_setbssidmask(common); | 174 | ath_hw_setbssidmask(common); |
@@ -1144,8 +1146,9 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, | |||
1144 | */ | 1146 | */ |
1145 | if ((vif->type == NL80211_IFTYPE_AP) && (priv->num_ap_vif == 0)) { | 1147 | if ((vif->type == NL80211_IFTYPE_AP) && (priv->num_ap_vif == 0)) { |
1146 | priv->rearm_ani = false; | 1148 | priv->rearm_ani = false; |
1147 | ieee80211_iterate_active_interfaces_atomic(priv->hw, | 1149 | ieee80211_iterate_active_interfaces_atomic( |
1148 | ath9k_htc_vif_iter, priv); | 1150 | priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
1151 | ath9k_htc_vif_iter, priv); | ||
1149 | if (!priv->rearm_ani) | 1152 | if (!priv->rearm_ani) |
1150 | ath9k_htc_stop_ani(priv); | 1153 | ath9k_htc_stop_ani(priv); |
1151 | } | 1154 | } |
@@ -1466,8 +1469,9 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | |||
1466 | static void ath9k_htc_choose_set_bssid(struct ath9k_htc_priv *priv) | 1469 | static void ath9k_htc_choose_set_bssid(struct ath9k_htc_priv *priv) |
1467 | { | 1470 | { |
1468 | if (priv->num_sta_assoc_vif == 1) { | 1471 | if (priv->num_sta_assoc_vif == 1) { |
1469 | ieee80211_iterate_active_interfaces_atomic(priv->hw, | 1472 | ieee80211_iterate_active_interfaces_atomic( |
1470 | ath9k_htc_bss_iter, priv); | 1473 | priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
1474 | ath9k_htc_bss_iter, priv); | ||
1471 | ath9k_htc_set_bssid(priv); | 1475 | ath9k_htc_set_bssid(priv); |
1472 | } | 1476 | } |
1473 | } | 1477 | } |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 578a7234aa5..c084532291a 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -924,8 +924,9 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw, | |||
924 | ath9k_vif_iter(iter_data, vif->addr, vif); | 924 | ath9k_vif_iter(iter_data, vif->addr, vif); |
925 | 925 | ||
926 | /* Get list of all active MAC addresses */ | 926 | /* Get list of all active MAC addresses */ |
927 | ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, | 927 | ieee80211_iterate_active_interfaces_atomic( |
928 | iter_data); | 928 | sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
929 | ath9k_vif_iter, iter_data); | ||
929 | } | 930 | } |
930 | 931 | ||
931 | /* Called with sc->mutex held. */ | 932 | /* Called with sc->mutex held. */ |
@@ -975,8 +976,9 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, | |||
975 | if (ah->opmode == NL80211_IFTYPE_STATION && | 976 | if (ah->opmode == NL80211_IFTYPE_STATION && |
976 | old_opmode == NL80211_IFTYPE_AP && | 977 | old_opmode == NL80211_IFTYPE_AP && |
977 | test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { | 978 | test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { |
978 | ieee80211_iterate_active_interfaces_atomic(sc->hw, | 979 | ieee80211_iterate_active_interfaces_atomic( |
979 | ath9k_sta_vif_iter, sc); | 980 | sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
981 | ath9k_sta_vif_iter, sc); | ||
980 | } | 982 | } |
981 | } | 983 | } |
982 | 984 | ||
@@ -1505,8 +1507,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | |||
1505 | clear_bit(SC_OP_BEACONS, &sc->sc_flags); | 1507 | clear_bit(SC_OP_BEACONS, &sc->sc_flags); |
1506 | } | 1508 | } |
1507 | 1509 | ||
1508 | ieee80211_iterate_active_interfaces_atomic(sc->hw, | 1510 | ieee80211_iterate_active_interfaces_atomic( |
1509 | ath9k_bss_assoc_iter, sc); | 1511 | sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
1512 | ath9k_bss_assoc_iter, sc); | ||
1510 | 1513 | ||
1511 | if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) && | 1514 | if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) && |
1512 | ah->opmode == NL80211_IFTYPE_STATION) { | 1515 | ah->opmode == NL80211_IFTYPE_STATION) { |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 4387ca506b3..dab6e405a2e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | |||
@@ -1529,7 +1529,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, | |||
1529 | } | 1529 | } |
1530 | 1530 | ||
1531 | static s32 | 1531 | static s32 |
1532 | brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, | 1532 | brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, |
1533 | enum nl80211_tx_power_setting type, s32 mbm) | 1533 | enum nl80211_tx_power_setting type, s32 mbm) |
1534 | { | 1534 | { |
1535 | 1535 | ||
@@ -1578,7 +1578,9 @@ done: | |||
1578 | return err; | 1578 | return err; |
1579 | } | 1579 | } |
1580 | 1580 | ||
1581 | static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) | 1581 | static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, |
1582 | struct wireless_dev *wdev, | ||
1583 | s32 *dbm) | ||
1582 | { | 1584 | { |
1583 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | 1585 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); |
1584 | struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); | 1586 | struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); |
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 429ca3215fd..a8ec7086ad0 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -44,9 +44,9 @@ static int radios = 2; | |||
44 | module_param(radios, int, 0444); | 44 | module_param(radios, int, 0444); |
45 | MODULE_PARM_DESC(radios, "Number of simulated radios"); | 45 | MODULE_PARM_DESC(radios, "Number of simulated radios"); |
46 | 46 | ||
47 | static bool fake_hw_scan; | 47 | static int channels = 1; |
48 | module_param(fake_hw_scan, bool, 0444); | 48 | module_param(channels, int, 0444); |
49 | MODULE_PARM_DESC(fake_hw_scan, "Install fake (no-op) hw-scan handler"); | 49 | MODULE_PARM_DESC(channels, "Number of concurrent channels"); |
50 | 50 | ||
51 | /** | 51 | /** |
52 | * enum hwsim_regtest - the type of regulatory tests we offer | 52 | * enum hwsim_regtest - the type of regulatory tests we offer |
@@ -166,7 +166,9 @@ struct hwsim_vif_priv { | |||
166 | static inline void hwsim_check_magic(struct ieee80211_vif *vif) | 166 | static inline void hwsim_check_magic(struct ieee80211_vif *vif) |
167 | { | 167 | { |
168 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | 168 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; |
169 | WARN_ON(vp->magic != HWSIM_VIF_MAGIC); | 169 | WARN(vp->magic != HWSIM_VIF_MAGIC, |
170 | "Invalid VIF (%p) magic %#x, %pM, %d/%d\n", | ||
171 | vif, vp->magic, vif->addr, vif->type, vif->p2p); | ||
170 | } | 172 | } |
171 | 173 | ||
172 | static inline void hwsim_set_magic(struct ieee80211_vif *vif) | 174 | static inline void hwsim_set_magic(struct ieee80211_vif *vif) |
@@ -185,7 +187,7 @@ struct hwsim_sta_priv { | |||
185 | u32 magic; | 187 | u32 magic; |
186 | }; | 188 | }; |
187 | 189 | ||
188 | #define HWSIM_STA_MAGIC 0x6d537748 | 190 | #define HWSIM_STA_MAGIC 0x6d537749 |
189 | 191 | ||
190 | static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) | 192 | static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) |
191 | { | 193 | { |
@@ -205,6 +207,30 @@ static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) | |||
205 | sp->magic = 0; | 207 | sp->magic = 0; |
206 | } | 208 | } |
207 | 209 | ||
210 | struct hwsim_chanctx_priv { | ||
211 | u32 magic; | ||
212 | }; | ||
213 | |||
214 | #define HWSIM_CHANCTX_MAGIC 0x6d53774a | ||
215 | |||
216 | static inline void hwsim_check_chanctx_magic(struct ieee80211_chanctx_conf *c) | ||
217 | { | ||
218 | struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; | ||
219 | WARN_ON(cp->magic != HWSIM_CHANCTX_MAGIC); | ||
220 | } | ||
221 | |||
222 | static inline void hwsim_set_chanctx_magic(struct ieee80211_chanctx_conf *c) | ||
223 | { | ||
224 | struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; | ||
225 | cp->magic = HWSIM_CHANCTX_MAGIC; | ||
226 | } | ||
227 | |||
228 | static inline void hwsim_clear_chanctx_magic(struct ieee80211_chanctx_conf *c) | ||
229 | { | ||
230 | struct hwsim_chanctx_priv *cp = (void *)c->drv_priv; | ||
231 | cp->magic = 0; | ||
232 | } | ||
233 | |||
208 | static struct class *hwsim_class; | 234 | static struct class *hwsim_class; |
209 | 235 | ||
210 | static struct net_device *hwsim_mon; /* global monitor netdev */ | 236 | static struct net_device *hwsim_mon; /* global monitor netdev */ |
@@ -299,6 +325,13 @@ struct mac80211_hwsim_data { | |||
299 | 325 | ||
300 | struct mac_address addresses[2]; | 326 | struct mac_address addresses[2]; |
301 | 327 | ||
328 | struct ieee80211_channel *tmp_chan; | ||
329 | struct delayed_work roc_done; | ||
330 | struct delayed_work hw_scan; | ||
331 | struct cfg80211_scan_request *hw_scan_request; | ||
332 | struct ieee80211_vif *hw_scan_vif; | ||
333 | int scan_chan_idx; | ||
334 | |||
302 | struct ieee80211_channel *channel; | 335 | struct ieee80211_channel *channel; |
303 | unsigned long beacon_int; /* in jiffies unit */ | 336 | unsigned long beacon_int; /* in jiffies unit */ |
304 | unsigned int rx_filter; | 337 | unsigned int rx_filter; |
@@ -396,7 +429,8 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw, | |||
396 | } | 429 | } |
397 | 430 | ||
398 | static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, | 431 | static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, |
399 | struct sk_buff *tx_skb) | 432 | struct sk_buff *tx_skb, |
433 | struct ieee80211_channel *chan) | ||
400 | { | 434 | { |
401 | struct mac80211_hwsim_data *data = hw->priv; | 435 | struct mac80211_hwsim_data *data = hw->priv; |
402 | struct sk_buff *skb; | 436 | struct sk_buff *skb; |
@@ -423,7 +457,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, | |||
423 | hdr->rt_tsft = __mac80211_hwsim_get_tsf(data); | 457 | hdr->rt_tsft = __mac80211_hwsim_get_tsf(data); |
424 | hdr->rt_flags = 0; | 458 | hdr->rt_flags = 0; |
425 | hdr->rt_rate = txrate->bitrate / 5; | 459 | hdr->rt_rate = txrate->bitrate / 5; |
426 | hdr->rt_channel = cpu_to_le16(data->channel->center_freq); | 460 | hdr->rt_channel = cpu_to_le16(chan->center_freq); |
427 | flags = IEEE80211_CHAN_2GHZ; | 461 | flags = IEEE80211_CHAN_2GHZ; |
428 | if (txrate->flags & IEEE80211_RATE_ERP_G) | 462 | if (txrate->flags & IEEE80211_RATE_ERP_G) |
429 | flags |= IEEE80211_CHAN_OFDM; | 463 | flags |= IEEE80211_CHAN_OFDM; |
@@ -441,9 +475,9 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, | |||
441 | } | 475 | } |
442 | 476 | ||
443 | 477 | ||
444 | static void mac80211_hwsim_monitor_ack(struct ieee80211_hw *hw, const u8 *addr) | 478 | static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan, |
479 | const u8 *addr) | ||
445 | { | 480 | { |
446 | struct mac80211_hwsim_data *data = hw->priv; | ||
447 | struct sk_buff *skb; | 481 | struct sk_buff *skb; |
448 | struct hwsim_radiotap_hdr *hdr; | 482 | struct hwsim_radiotap_hdr *hdr; |
449 | u16 flags; | 483 | u16 flags; |
@@ -464,7 +498,7 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_hw *hw, const u8 *addr) | |||
464 | (1 << IEEE80211_RADIOTAP_CHANNEL)); | 498 | (1 << IEEE80211_RADIOTAP_CHANNEL)); |
465 | hdr->rt_flags = 0; | 499 | hdr->rt_flags = 0; |
466 | hdr->rt_rate = 0; | 500 | hdr->rt_rate = 0; |
467 | hdr->rt_channel = cpu_to_le16(data->channel->center_freq); | 501 | hdr->rt_channel = cpu_to_le16(chan->center_freq); |
468 | flags = IEEE80211_CHAN_2GHZ; | 502 | flags = IEEE80211_CHAN_2GHZ; |
469 | hdr->rt_chbitmask = cpu_to_le16(flags); | 503 | hdr->rt_chbitmask = cpu_to_le16(flags); |
470 | 504 | ||
@@ -537,6 +571,7 @@ static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, | |||
537 | md.ret = false; | 571 | md.ret = false; |
538 | md.addr = addr; | 572 | md.addr = addr; |
539 | ieee80211_iterate_active_interfaces_atomic(data->hw, | 573 | ieee80211_iterate_active_interfaces_atomic(data->hw, |
574 | IEEE80211_IFACE_ITER_NORMAL, | ||
540 | mac80211_hwsim_addr_iter, | 575 | mac80211_hwsim_addr_iter, |
541 | &md); | 576 | &md); |
542 | 577 | ||
@@ -556,12 +591,6 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, | |||
556 | int i; | 591 | int i; |
557 | struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES]; | 592 | struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES]; |
558 | 593 | ||
559 | if (data->idle) { | ||
560 | wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); | ||
561 | dev_kfree_skb(my_skb); | ||
562 | return; | ||
563 | } | ||
564 | |||
565 | if (data->ps != PS_DISABLED) | 594 | if (data->ps != PS_DISABLED) |
566 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); | 595 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); |
567 | /* If the queue contains MAX_QUEUE skb's drop some */ | 596 | /* If the queue contains MAX_QUEUE skb's drop some */ |
@@ -629,8 +658,38 @@ nla_put_failure: | |||
629 | printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__); | 658 | printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__); |
630 | } | 659 | } |
631 | 660 | ||
661 | static bool hwsim_chans_compat(struct ieee80211_channel *c1, | ||
662 | struct ieee80211_channel *c2) | ||
663 | { | ||
664 | if (!c1 || !c2) | ||
665 | return false; | ||
666 | |||
667 | return c1->center_freq == c2->center_freq; | ||
668 | } | ||
669 | |||
670 | struct tx_iter_data { | ||
671 | struct ieee80211_channel *channel; | ||
672 | bool receive; | ||
673 | }; | ||
674 | |||
675 | static void mac80211_hwsim_tx_iter(void *_data, u8 *addr, | ||
676 | struct ieee80211_vif *vif) | ||
677 | { | ||
678 | struct tx_iter_data *data = _data; | ||
679 | |||
680 | if (!vif->chanctx_conf) | ||
681 | return; | ||
682 | |||
683 | if (!hwsim_chans_compat(data->channel, | ||
684 | rcu_dereference(vif->chanctx_conf)->channel)) | ||
685 | return; | ||
686 | |||
687 | data->receive = true; | ||
688 | } | ||
689 | |||
632 | static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | 690 | static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, |
633 | struct sk_buff *skb) | 691 | struct sk_buff *skb, |
692 | struct ieee80211_channel *chan) | ||
634 | { | 693 | { |
635 | struct mac80211_hwsim_data *data = hw->priv, *data2; | 694 | struct mac80211_hwsim_data *data = hw->priv, *data2; |
636 | bool ack = false; | 695 | bool ack = false; |
@@ -639,15 +698,10 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | |||
639 | struct ieee80211_rx_status rx_status; | 698 | struct ieee80211_rx_status rx_status; |
640 | struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); | 699 | struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info); |
641 | 700 | ||
642 | if (data->idle) { | ||
643 | wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); | ||
644 | return false; | ||
645 | } | ||
646 | |||
647 | memset(&rx_status, 0, sizeof(rx_status)); | 701 | memset(&rx_status, 0, sizeof(rx_status)); |
648 | rx_status.flag |= RX_FLAG_MACTIME_MPDU; | 702 | rx_status.flag |= RX_FLAG_MACTIME_MPDU; |
649 | rx_status.freq = data->channel->center_freq; | 703 | rx_status.freq = chan->center_freq; |
650 | rx_status.band = data->channel->band; | 704 | rx_status.band = chan->band; |
651 | rx_status.rate_idx = info->control.rates[0].idx; | 705 | rx_status.rate_idx = info->control.rates[0].idx; |
652 | if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) | 706 | if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) |
653 | rx_status.flag |= RX_FLAG_HT; | 707 | rx_status.flag |= RX_FLAG_HT; |
@@ -673,16 +727,30 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | |||
673 | list_for_each_entry(data2, &hwsim_radios, list) { | 727 | list_for_each_entry(data2, &hwsim_radios, list) { |
674 | struct sk_buff *nskb; | 728 | struct sk_buff *nskb; |
675 | struct ieee80211_mgmt *mgmt; | 729 | struct ieee80211_mgmt *mgmt; |
730 | struct tx_iter_data tx_iter_data = { | ||
731 | .receive = false, | ||
732 | .channel = chan, | ||
733 | }; | ||
676 | 734 | ||
677 | if (data == data2) | 735 | if (data == data2) |
678 | continue; | 736 | continue; |
679 | 737 | ||
680 | if (data2->idle || !data2->started || | 738 | if (!data2->started || (data2->idle && !data2->tmp_chan) || |
681 | !hwsim_ps_rx_ok(data2, skb) || !data2->channel || | 739 | !hwsim_ps_rx_ok(data2, skb)) |
682 | data->channel->center_freq != data2->channel->center_freq || | 740 | continue; |
683 | !(data->group & data2->group)) | 741 | |
742 | if (!(data->group & data2->group)) | ||
684 | continue; | 743 | continue; |
685 | 744 | ||
745 | if (!hwsim_chans_compat(chan, data2->tmp_chan) && | ||
746 | !hwsim_chans_compat(chan, data2->channel)) { | ||
747 | ieee80211_iterate_active_interfaces_atomic( | ||
748 | data2->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
749 | mac80211_hwsim_tx_iter, &tx_iter_data); | ||
750 | if (!tx_iter_data.receive) | ||
751 | continue; | ||
752 | } | ||
753 | |||
686 | nskb = skb_copy(skb, GFP_ATOMIC); | 754 | nskb = skb_copy(skb, GFP_ATOMIC); |
687 | if (nskb == NULL) | 755 | if (nskb == NULL) |
688 | continue; | 756 | continue; |
@@ -713,18 +781,51 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, | |||
713 | struct ieee80211_tx_control *control, | 781 | struct ieee80211_tx_control *control, |
714 | struct sk_buff *skb) | 782 | struct sk_buff *skb) |
715 | { | 783 | { |
784 | struct mac80211_hwsim_data *data = hw->priv; | ||
785 | struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); | ||
786 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
787 | struct ieee80211_channel *channel; | ||
716 | bool ack; | 788 | bool ack; |
717 | struct ieee80211_tx_info *txi; | ||
718 | u32 _portid; | 789 | u32 _portid; |
719 | 790 | ||
720 | mac80211_hwsim_monitor_rx(hw, skb); | 791 | if (WARN_ON(skb->len < 10)) { |
721 | |||
722 | if (skb->len < 10) { | ||
723 | /* Should not happen; just a sanity check for addr1 use */ | 792 | /* Should not happen; just a sanity check for addr1 use */ |
724 | dev_kfree_skb(skb); | 793 | dev_kfree_skb(skb); |
725 | return; | 794 | return; |
726 | } | 795 | } |
727 | 796 | ||
797 | if (channels == 1) { | ||
798 | channel = data->channel; | ||
799 | } else if (txi->hw_queue == 4) { | ||
800 | channel = data->tmp_chan; | ||
801 | } else { | ||
802 | chanctx_conf = rcu_dereference(txi->control.vif->chanctx_conf); | ||
803 | if (chanctx_conf) | ||
804 | channel = chanctx_conf->channel; | ||
805 | else | ||
806 | channel = NULL; | ||
807 | } | ||
808 | |||
809 | if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) { | ||
810 | dev_kfree_skb(skb); | ||
811 | return; | ||
812 | } | ||
813 | |||
814 | if (data->idle && !data->tmp_chan) { | ||
815 | wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); | ||
816 | dev_kfree_skb(skb); | ||
817 | return; | ||
818 | } | ||
819 | |||
820 | if (txi->control.vif) | ||
821 | hwsim_check_magic(txi->control.vif); | ||
822 | if (control->sta) | ||
823 | hwsim_check_sta_magic(control->sta); | ||
824 | |||
825 | txi->rate_driver_data[0] = channel; | ||
826 | |||
827 | mac80211_hwsim_monitor_rx(hw, skb, channel); | ||
828 | |||
728 | /* wmediumd mode check */ | 829 | /* wmediumd mode check */ |
729 | _portid = ACCESS_ONCE(wmediumd_portid); | 830 | _portid = ACCESS_ONCE(wmediumd_portid); |
730 | 831 | ||
@@ -732,15 +833,13 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, | |||
732 | return mac80211_hwsim_tx_frame_nl(hw, skb, _portid); | 833 | return mac80211_hwsim_tx_frame_nl(hw, skb, _portid); |
733 | 834 | ||
734 | /* NO wmediumd detected, perfect medium simulation */ | 835 | /* NO wmediumd detected, perfect medium simulation */ |
735 | ack = mac80211_hwsim_tx_frame_no_nl(hw, skb); | 836 | ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel); |
736 | 837 | ||
737 | if (ack && skb->len >= 16) { | 838 | if (ack && skb->len >= 16) { |
738 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 839 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
739 | mac80211_hwsim_monitor_ack(hw, hdr->addr2); | 840 | mac80211_hwsim_monitor_ack(channel, hdr->addr2); |
740 | } | 841 | } |
741 | 842 | ||
742 | txi = IEEE80211_SKB_CB(skb); | ||
743 | |||
744 | ieee80211_tx_info_clear_status(txi); | 843 | ieee80211_tx_info_clear_status(txi); |
745 | 844 | ||
746 | /* frame was transmitted at most favorable rate at first attempt */ | 845 | /* frame was transmitted at most favorable rate at first attempt */ |
@@ -778,6 +877,13 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, | |||
778 | __func__, ieee80211_vif_type_p2p(vif), | 877 | __func__, ieee80211_vif_type_p2p(vif), |
779 | vif->addr); | 878 | vif->addr); |
780 | hwsim_set_magic(vif); | 879 | hwsim_set_magic(vif); |
880 | |||
881 | vif->cab_queue = 0; | ||
882 | vif->hw_queue[IEEE80211_AC_VO] = 0; | ||
883 | vif->hw_queue[IEEE80211_AC_VI] = 1; | ||
884 | vif->hw_queue[IEEE80211_AC_BE] = 2; | ||
885 | vif->hw_queue[IEEE80211_AC_BK] = 3; | ||
886 | |||
781 | return 0; | 887 | return 0; |
782 | } | 888 | } |
783 | 889 | ||
@@ -807,14 +913,26 @@ static void mac80211_hwsim_remove_interface( | |||
807 | hwsim_clear_magic(vif); | 913 | hwsim_clear_magic(vif); |
808 | } | 914 | } |
809 | 915 | ||
916 | static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | ||
917 | struct sk_buff *skb, | ||
918 | struct ieee80211_channel *chan) | ||
919 | { | ||
920 | u32 _pid = ACCESS_ONCE(wmediumd_portid); | ||
921 | |||
922 | mac80211_hwsim_monitor_rx(hw, skb, chan); | ||
923 | |||
924 | if (_pid) | ||
925 | return mac80211_hwsim_tx_frame_nl(hw, skb, _pid); | ||
926 | |||
927 | mac80211_hwsim_tx_frame_no_nl(hw, skb, chan); | ||
928 | dev_kfree_skb(skb); | ||
929 | } | ||
810 | 930 | ||
811 | static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, | 931 | static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, |
812 | struct ieee80211_vif *vif) | 932 | struct ieee80211_vif *vif) |
813 | { | 933 | { |
814 | struct ieee80211_hw *hw = arg; | 934 | struct ieee80211_hw *hw = arg; |
815 | struct sk_buff *skb; | 935 | struct sk_buff *skb; |
816 | struct ieee80211_tx_info *info; | ||
817 | u32 _portid; | ||
818 | 936 | ||
819 | hwsim_check_magic(vif); | 937 | hwsim_check_magic(vif); |
820 | 938 | ||
@@ -826,18 +944,9 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, | |||
826 | skb = ieee80211_beacon_get(hw, vif); | 944 | skb = ieee80211_beacon_get(hw, vif); |
827 | if (skb == NULL) | 945 | if (skb == NULL) |
828 | return; | 946 | return; |
829 | info = IEEE80211_SKB_CB(skb); | ||
830 | |||
831 | mac80211_hwsim_monitor_rx(hw, skb); | ||
832 | |||
833 | /* wmediumd mode check */ | ||
834 | _portid = ACCESS_ONCE(wmediumd_portid); | ||
835 | |||
836 | if (_portid) | ||
837 | return mac80211_hwsim_tx_frame_nl(hw, skb, _portid); | ||
838 | 947 | ||
839 | mac80211_hwsim_tx_frame_no_nl(hw, skb); | 948 | mac80211_hwsim_tx_frame(hw, skb, |
840 | dev_kfree_skb(skb); | 949 | rcu_dereference(vif->chanctx_conf)->channel); |
841 | } | 950 | } |
842 | 951 | ||
843 | 952 | ||
@@ -850,7 +959,8 @@ static void mac80211_hwsim_beacon(unsigned long arg) | |||
850 | return; | 959 | return; |
851 | 960 | ||
852 | ieee80211_iterate_active_interfaces_atomic( | 961 | ieee80211_iterate_active_interfaces_atomic( |
853 | hw, mac80211_hwsim_beacon_tx, hw); | 962 | hw, IEEE80211_IFACE_ITER_NORMAL, |
963 | mac80211_hwsim_beacon_tx, hw); | ||
854 | 964 | ||
855 | data->beacon_timer.expires = jiffies + data->beacon_int; | 965 | data->beacon_timer.expires = jiffies + data->beacon_int; |
856 | add_timer(&data->beacon_timer); | 966 | add_timer(&data->beacon_timer); |
@@ -877,7 +987,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) | |||
877 | wiphy_debug(hw->wiphy, | 987 | wiphy_debug(hw->wiphy, |
878 | "%s (freq=%d/%s idle=%d ps=%d smps=%s)\n", | 988 | "%s (freq=%d/%s idle=%d ps=%d smps=%s)\n", |
879 | __func__, | 989 | __func__, |
880 | conf->channel->center_freq, | 990 | conf->channel ? conf->channel->center_freq : 0, |
881 | hwsim_chantypes[conf->channel_type], | 991 | hwsim_chantypes[conf->channel_type], |
882 | !!(conf->flags & IEEE80211_CONF_IDLE), | 992 | !!(conf->flags & IEEE80211_CONF_IDLE), |
883 | !!(conf->flags & IEEE80211_CONF_PS), | 993 | !!(conf->flags & IEEE80211_CONF_PS), |
@@ -886,6 +996,9 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) | |||
886 | data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); | 996 | data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); |
887 | 997 | ||
888 | data->channel = conf->channel; | 998 | data->channel = conf->channel; |
999 | |||
1000 | WARN_ON(data->channel && channels > 1); | ||
1001 | |||
889 | data->power_level = conf->power_level; | 1002 | data->power_level = conf->power_level; |
890 | if (!data->started || !data->beacon_int) | 1003 | if (!data->started || !data->beacon_int) |
891 | del_timer(&data->beacon_timer); | 1004 | del_timer(&data->beacon_timer); |
@@ -972,6 +1085,9 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, | |||
972 | wiphy_debug(hw->wiphy, " BASIC_RATES: 0x%llx\n", | 1085 | wiphy_debug(hw->wiphy, " BASIC_RATES: 0x%llx\n", |
973 | (unsigned long long) info->basic_rates); | 1086 | (unsigned long long) info->basic_rates); |
974 | } | 1087 | } |
1088 | |||
1089 | if (changed & BSS_CHANGED_TXPOWER) | ||
1090 | wiphy_debug(hw->wiphy, " TX Power: %d dBm\n", info->txpower); | ||
975 | } | 1091 | } |
976 | 1092 | ||
977 | static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw, | 1093 | static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw, |
@@ -1166,45 +1282,102 @@ static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop) | |||
1166 | /* Not implemented, queues only on kernel side */ | 1282 | /* Not implemented, queues only on kernel side */ |
1167 | } | 1283 | } |
1168 | 1284 | ||
1169 | struct hw_scan_done { | 1285 | static void hw_scan_work(struct work_struct *work) |
1170 | struct delayed_work w; | ||
1171 | struct ieee80211_hw *hw; | ||
1172 | }; | ||
1173 | |||
1174 | static void hw_scan_done(struct work_struct *work) | ||
1175 | { | 1286 | { |
1176 | struct hw_scan_done *hsd = | 1287 | struct mac80211_hwsim_data *hwsim = |
1177 | container_of(work, struct hw_scan_done, w.work); | 1288 | container_of(work, struct mac80211_hwsim_data, hw_scan.work); |
1289 | struct cfg80211_scan_request *req = hwsim->hw_scan_request; | ||
1290 | int dwell, i; | ||
1178 | 1291 | ||
1179 | ieee80211_scan_completed(hsd->hw, false); | 1292 | mutex_lock(&hwsim->mutex); |
1180 | kfree(hsd); | 1293 | if (hwsim->scan_chan_idx >= req->n_channels) { |
1294 | wiphy_debug(hwsim->hw->wiphy, "hw scan complete\n"); | ||
1295 | ieee80211_scan_completed(hwsim->hw, false); | ||
1296 | hwsim->hw_scan_request = NULL; | ||
1297 | hwsim->hw_scan_vif = NULL; | ||
1298 | hwsim->tmp_chan = NULL; | ||
1299 | mutex_unlock(&hwsim->mutex); | ||
1300 | return; | ||
1301 | } | ||
1302 | |||
1303 | wiphy_debug(hwsim->hw->wiphy, "hw scan %d MHz\n", | ||
1304 | req->channels[hwsim->scan_chan_idx]->center_freq); | ||
1305 | |||
1306 | hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx]; | ||
1307 | if (hwsim->tmp_chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || | ||
1308 | !req->n_ssids) { | ||
1309 | dwell = 120; | ||
1310 | } else { | ||
1311 | dwell = 30; | ||
1312 | /* send probes */ | ||
1313 | for (i = 0; i < req->n_ssids; i++) { | ||
1314 | struct sk_buff *probe; | ||
1315 | |||
1316 | probe = ieee80211_probereq_get(hwsim->hw, | ||
1317 | hwsim->hw_scan_vif, | ||
1318 | req->ssids[i].ssid, | ||
1319 | req->ssids[i].ssid_len, | ||
1320 | req->ie, req->ie_len); | ||
1321 | if (!probe) | ||
1322 | continue; | ||
1323 | local_bh_disable(); | ||
1324 | mac80211_hwsim_tx_frame(hwsim->hw, probe, | ||
1325 | hwsim->tmp_chan); | ||
1326 | local_bh_enable(); | ||
1327 | } | ||
1328 | } | ||
1329 | ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, | ||
1330 | msecs_to_jiffies(dwell)); | ||
1331 | hwsim->scan_chan_idx++; | ||
1332 | mutex_unlock(&hwsim->mutex); | ||
1181 | } | 1333 | } |
1182 | 1334 | ||
1183 | static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, | 1335 | static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, |
1184 | struct ieee80211_vif *vif, | 1336 | struct ieee80211_vif *vif, |
1185 | struct cfg80211_scan_request *req) | 1337 | struct cfg80211_scan_request *req) |
1186 | { | 1338 | { |
1187 | struct hw_scan_done *hsd = kzalloc(sizeof(*hsd), GFP_KERNEL); | 1339 | struct mac80211_hwsim_data *hwsim = hw->priv; |
1188 | int i; | 1340 | int i; |
1189 | 1341 | ||
1190 | if (!hsd) | 1342 | mutex_lock(&hwsim->mutex); |
1191 | return -ENOMEM; | 1343 | if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { |
1192 | 1344 | mutex_unlock(&hwsim->mutex); | |
1193 | hsd->hw = hw; | 1345 | return -EBUSY; |
1194 | INIT_DELAYED_WORK(&hsd->w, hw_scan_done); | 1346 | } |
1347 | hwsim->hw_scan_request = req; | ||
1348 | hwsim->hw_scan_vif = vif; | ||
1349 | hwsim->scan_chan_idx = 0; | ||
1350 | mutex_unlock(&hwsim->mutex); | ||
1195 | 1351 | ||
1196 | printk(KERN_DEBUG "hwsim hw_scan request\n"); | 1352 | wiphy_debug(hw->wiphy, "hwsim hw_scan request\n"); |
1197 | for (i = 0; i < req->n_channels; i++) | 1353 | for (i = 0; i < req->n_channels; i++) |
1198 | printk(KERN_DEBUG "hwsim hw_scan freq %d\n", | 1354 | printk(KERN_DEBUG "hwsim hw_scan freq %d\n", |
1199 | req->channels[i]->center_freq); | 1355 | req->channels[i]->center_freq); |
1200 | print_hex_dump(KERN_DEBUG, "scan IEs: ", DUMP_PREFIX_OFFSET, | 1356 | print_hex_dump(KERN_DEBUG, "scan IEs: ", DUMP_PREFIX_OFFSET, |
1201 | 16, 1, req->ie, req->ie_len, 1); | 1357 | 16, 1, req->ie, req->ie_len, 1); |
1202 | 1358 | ||
1203 | ieee80211_queue_delayed_work(hw, &hsd->w, 2 * HZ); | 1359 | ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0); |
1204 | 1360 | ||
1205 | return 0; | 1361 | return 0; |
1206 | } | 1362 | } |
1207 | 1363 | ||
1364 | static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw, | ||
1365 | struct ieee80211_vif *vif) | ||
1366 | { | ||
1367 | struct mac80211_hwsim_data *hwsim = hw->priv; | ||
1368 | |||
1369 | wiphy_debug(hw->wiphy, "hwsim cancel_hw_scan\n"); | ||
1370 | |||
1371 | cancel_delayed_work_sync(&hwsim->hw_scan); | ||
1372 | |||
1373 | mutex_lock(&hwsim->mutex); | ||
1374 | ieee80211_scan_completed(hwsim->hw, true); | ||
1375 | hwsim->tmp_chan = NULL; | ||
1376 | hwsim->hw_scan_request = NULL; | ||
1377 | hwsim->hw_scan_vif = NULL; | ||
1378 | mutex_unlock(&hwsim->mutex); | ||
1379 | } | ||
1380 | |||
1208 | static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw) | 1381 | static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw) |
1209 | { | 1382 | { |
1210 | struct mac80211_hwsim_data *hwsim = hw->priv; | 1383 | struct mac80211_hwsim_data *hwsim = hw->priv; |
@@ -1235,6 +1408,105 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw) | |||
1235 | mutex_unlock(&hwsim->mutex); | 1408 | mutex_unlock(&hwsim->mutex); |
1236 | } | 1409 | } |
1237 | 1410 | ||
1411 | static void hw_roc_done(struct work_struct *work) | ||
1412 | { | ||
1413 | struct mac80211_hwsim_data *hwsim = | ||
1414 | container_of(work, struct mac80211_hwsim_data, roc_done.work); | ||
1415 | |||
1416 | mutex_lock(&hwsim->mutex); | ||
1417 | ieee80211_remain_on_channel_expired(hwsim->hw); | ||
1418 | hwsim->tmp_chan = NULL; | ||
1419 | mutex_unlock(&hwsim->mutex); | ||
1420 | |||
1421 | wiphy_debug(hwsim->hw->wiphy, "hwsim ROC expired\n"); | ||
1422 | } | ||
1423 | |||
1424 | static int mac80211_hwsim_roc(struct ieee80211_hw *hw, | ||
1425 | struct ieee80211_channel *chan, | ||
1426 | enum nl80211_channel_type channel_type, | ||
1427 | int duration) | ||
1428 | { | ||
1429 | struct mac80211_hwsim_data *hwsim = hw->priv; | ||
1430 | |||
1431 | mutex_lock(&hwsim->mutex); | ||
1432 | if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) { | ||
1433 | mutex_unlock(&hwsim->mutex); | ||
1434 | return -EBUSY; | ||
1435 | } | ||
1436 | |||
1437 | hwsim->tmp_chan = chan; | ||
1438 | mutex_unlock(&hwsim->mutex); | ||
1439 | |||
1440 | wiphy_debug(hw->wiphy, "hwsim ROC (%d MHz, %d ms)\n", | ||
1441 | chan->center_freq, duration); | ||
1442 | |||
1443 | ieee80211_ready_on_channel(hw); | ||
1444 | |||
1445 | ieee80211_queue_delayed_work(hw, &hwsim->roc_done, | ||
1446 | msecs_to_jiffies(duration)); | ||
1447 | return 0; | ||
1448 | } | ||
1449 | |||
1450 | static int mac80211_hwsim_croc(struct ieee80211_hw *hw) | ||
1451 | { | ||
1452 | struct mac80211_hwsim_data *hwsim = hw->priv; | ||
1453 | |||
1454 | cancel_delayed_work_sync(&hwsim->roc_done); | ||
1455 | |||
1456 | mutex_lock(&hwsim->mutex); | ||
1457 | hwsim->tmp_chan = NULL; | ||
1458 | mutex_unlock(&hwsim->mutex); | ||
1459 | |||
1460 | wiphy_debug(hw->wiphy, "hwsim ROC canceled\n"); | ||
1461 | |||
1462 | return 0; | ||
1463 | } | ||
1464 | |||
1465 | static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw, | ||
1466 | struct ieee80211_chanctx_conf *ctx) | ||
1467 | { | ||
1468 | hwsim_set_chanctx_magic(ctx); | ||
1469 | wiphy_debug(hw->wiphy, "add channel context %d MHz/%d\n", | ||
1470 | ctx->channel->center_freq, ctx->channel_type); | ||
1471 | return 0; | ||
1472 | } | ||
1473 | |||
1474 | static void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw, | ||
1475 | struct ieee80211_chanctx_conf *ctx) | ||
1476 | { | ||
1477 | wiphy_debug(hw->wiphy, "remove channel context %d MHz/%d\n", | ||
1478 | ctx->channel->center_freq, ctx->channel_type); | ||
1479 | hwsim_check_chanctx_magic(ctx); | ||
1480 | hwsim_clear_chanctx_magic(ctx); | ||
1481 | } | ||
1482 | |||
1483 | static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw, | ||
1484 | struct ieee80211_chanctx_conf *ctx, | ||
1485 | u32 changed) | ||
1486 | { | ||
1487 | hwsim_check_chanctx_magic(ctx); | ||
1488 | wiphy_debug(hw->wiphy, "change channel context %#x (%d MHz/%d)\n", | ||
1489 | changed, ctx->channel->center_freq, ctx->channel_type); | ||
1490 | } | ||
1491 | |||
1492 | static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw, | ||
1493 | struct ieee80211_vif *vif, | ||
1494 | struct ieee80211_chanctx_conf *ctx) | ||
1495 | { | ||
1496 | hwsim_check_magic(vif); | ||
1497 | hwsim_check_chanctx_magic(ctx); | ||
1498 | |||
1499 | return 0; | ||
1500 | } | ||
1501 | |||
1502 | static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw, | ||
1503 | struct ieee80211_vif *vif, | ||
1504 | struct ieee80211_chanctx_conf *ctx) | ||
1505 | { | ||
1506 | hwsim_check_magic(vif); | ||
1507 | hwsim_check_chanctx_magic(ctx); | ||
1508 | } | ||
1509 | |||
1238 | static struct ieee80211_ops mac80211_hwsim_ops = | 1510 | static struct ieee80211_ops mac80211_hwsim_ops = |
1239 | { | 1511 | { |
1240 | .tx = mac80211_hwsim_tx, | 1512 | .tx = mac80211_hwsim_tx, |
@@ -1315,7 +1587,6 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) | |||
1315 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | 1587 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; |
1316 | struct sk_buff *skb; | 1588 | struct sk_buff *skb; |
1317 | struct ieee80211_pspoll *pspoll; | 1589 | struct ieee80211_pspoll *pspoll; |
1318 | u32 _portid; | ||
1319 | 1590 | ||
1320 | if (!vp->assoc) | 1591 | if (!vp->assoc) |
1321 | return; | 1592 | return; |
@@ -1335,25 +1606,18 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) | |||
1335 | memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); | 1606 | memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); |
1336 | memcpy(pspoll->ta, mac, ETH_ALEN); | 1607 | memcpy(pspoll->ta, mac, ETH_ALEN); |
1337 | 1608 | ||
1338 | /* wmediumd mode check */ | 1609 | rcu_read_lock(); |
1339 | _portid = ACCESS_ONCE(wmediumd_portid); | 1610 | mac80211_hwsim_tx_frame(data->hw, skb, |
1340 | 1611 | rcu_dereference(vif->chanctx_conf)->channel); | |
1341 | if (_portid) | 1612 | rcu_read_unlock(); |
1342 | return mac80211_hwsim_tx_frame_nl(data->hw, skb, _portid); | ||
1343 | |||
1344 | if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb)) | ||
1345 | printk(KERN_DEBUG "%s: PS-poll frame not ack'ed\n", __func__); | ||
1346 | dev_kfree_skb(skb); | ||
1347 | } | 1613 | } |
1348 | 1614 | ||
1349 | |||
1350 | static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, | 1615 | static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, |
1351 | struct ieee80211_vif *vif, int ps) | 1616 | struct ieee80211_vif *vif, int ps) |
1352 | { | 1617 | { |
1353 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | 1618 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; |
1354 | struct sk_buff *skb; | 1619 | struct sk_buff *skb; |
1355 | struct ieee80211_hdr *hdr; | 1620 | struct ieee80211_hdr *hdr; |
1356 | u32 _portid; | ||
1357 | 1621 | ||
1358 | if (!vp->assoc) | 1622 | if (!vp->assoc) |
1359 | return; | 1623 | return; |
@@ -1374,15 +1638,10 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, | |||
1374 | memcpy(hdr->addr2, mac, ETH_ALEN); | 1638 | memcpy(hdr->addr2, mac, ETH_ALEN); |
1375 | memcpy(hdr->addr3, vp->bssid, ETH_ALEN); | 1639 | memcpy(hdr->addr3, vp->bssid, ETH_ALEN); |
1376 | 1640 | ||
1377 | /* wmediumd mode check */ | 1641 | rcu_read_lock(); |
1378 | _portid = ACCESS_ONCE(wmediumd_portid); | 1642 | mac80211_hwsim_tx_frame(data->hw, skb, |
1379 | 1643 | rcu_dereference(vif->chanctx_conf)->channel); | |
1380 | if (_portid) | 1644 | rcu_read_unlock(); |
1381 | return mac80211_hwsim_tx_frame_nl(data->hw, skb, _portid); | ||
1382 | |||
1383 | if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb)) | ||
1384 | printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); | ||
1385 | dev_kfree_skb(skb); | ||
1386 | } | 1645 | } |
1387 | 1646 | ||
1388 | 1647 | ||
@@ -1423,14 +1682,17 @@ static int hwsim_fops_ps_write(void *dat, u64 val) | |||
1423 | 1682 | ||
1424 | if (val == PS_MANUAL_POLL) { | 1683 | if (val == PS_MANUAL_POLL) { |
1425 | ieee80211_iterate_active_interfaces(data->hw, | 1684 | ieee80211_iterate_active_interfaces(data->hw, |
1685 | IEEE80211_IFACE_ITER_NORMAL, | ||
1426 | hwsim_send_ps_poll, data); | 1686 | hwsim_send_ps_poll, data); |
1427 | data->ps_poll_pending = true; | 1687 | data->ps_poll_pending = true; |
1428 | } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { | 1688 | } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { |
1429 | ieee80211_iterate_active_interfaces(data->hw, | 1689 | ieee80211_iterate_active_interfaces(data->hw, |
1690 | IEEE80211_IFACE_ITER_NORMAL, | ||
1430 | hwsim_send_nullfunc_ps, | 1691 | hwsim_send_nullfunc_ps, |
1431 | data); | 1692 | data); |
1432 | } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { | 1693 | } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { |
1433 | ieee80211_iterate_active_interfaces(data->hw, | 1694 | ieee80211_iterate_active_interfaces(data->hw, |
1695 | IEEE80211_IFACE_ITER_NORMAL, | ||
1434 | hwsim_send_nullfunc_no_ps, | 1696 | hwsim_send_nullfunc_no_ps, |
1435 | data); | 1697 | data); |
1436 | } | 1698 | } |
@@ -1551,7 +1813,8 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, | |||
1551 | (hwsim_flags & HWSIM_TX_STAT_ACK)) { | 1813 | (hwsim_flags & HWSIM_TX_STAT_ACK)) { |
1552 | if (skb->len >= 16) { | 1814 | if (skb->len >= 16) { |
1553 | hdr = (struct ieee80211_hdr *) skb->data; | 1815 | hdr = (struct ieee80211_hdr *) skb->data; |
1554 | mac80211_hwsim_monitor_ack(data2->hw, hdr->addr2); | 1816 | mac80211_hwsim_monitor_ack(txi->rate_driver_data[0], |
1817 | hdr->addr2); | ||
1555 | } | 1818 | } |
1556 | txi->flags |= IEEE80211_TX_STAT_ACK; | 1819 | txi->flags |= IEEE80211_TX_STAT_ACK; |
1557 | } | 1820 | } |
@@ -1566,7 +1829,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, | |||
1566 | struct genl_info *info) | 1829 | struct genl_info *info) |
1567 | { | 1830 | { |
1568 | 1831 | ||
1569 | struct mac80211_hwsim_data *data2; | 1832 | struct mac80211_hwsim_data *data2; |
1570 | struct ieee80211_rx_status rx_status; | 1833 | struct ieee80211_rx_status rx_status; |
1571 | struct mac_address *dst; | 1834 | struct mac_address *dst; |
1572 | int frame_data_len; | 1835 | int frame_data_len; |
@@ -1574,9 +1837,9 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, | |||
1574 | struct sk_buff *skb = NULL; | 1837 | struct sk_buff *skb = NULL; |
1575 | 1838 | ||
1576 | if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || | 1839 | if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || |
1577 | !info->attrs[HWSIM_ATTR_FRAME] || | 1840 | !info->attrs[HWSIM_ATTR_FRAME] || |
1578 | !info->attrs[HWSIM_ATTR_RX_RATE] || | 1841 | !info->attrs[HWSIM_ATTR_RX_RATE] || |
1579 | !info->attrs[HWSIM_ATTR_SIGNAL]) | 1842 | !info->attrs[HWSIM_ATTR_SIGNAL]) |
1580 | goto out; | 1843 | goto out; |
1581 | 1844 | ||
1582 | dst = (struct mac_address *)nla_data( | 1845 | dst = (struct mac_address *)nla_data( |
@@ -1604,7 +1867,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, | |||
1604 | 1867 | ||
1605 | /* check if radio is configured properly */ | 1868 | /* check if radio is configured properly */ |
1606 | 1869 | ||
1607 | if (data2->idle || !data2->started || !data2->channel) | 1870 | if (data2->idle || !data2->started) |
1608 | goto out; | 1871 | goto out; |
1609 | 1872 | ||
1610 | /*A frame is received from user space*/ | 1873 | /*A frame is received from user space*/ |
@@ -1688,6 +1951,11 @@ static struct notifier_block hwsim_netlink_notifier = { | |||
1688 | static int hwsim_init_netlink(void) | 1951 | static int hwsim_init_netlink(void) |
1689 | { | 1952 | { |
1690 | int rc; | 1953 | int rc; |
1954 | |||
1955 | /* userspace test API hasn't been adjusted for multi-channel */ | ||
1956 | if (channels > 1) | ||
1957 | return 0; | ||
1958 | |||
1691 | printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); | 1959 | printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); |
1692 | 1960 | ||
1693 | rc = genl_register_family_with_ops(&hwsim_genl_family, | 1961 | rc = genl_register_family_with_ops(&hwsim_genl_family, |
@@ -1710,6 +1978,10 @@ static void hwsim_exit_netlink(void) | |||
1710 | { | 1978 | { |
1711 | int ret; | 1979 | int ret; |
1712 | 1980 | ||
1981 | /* userspace test API hasn't been adjusted for multi-channel */ | ||
1982 | if (channels > 1) | ||
1983 | return; | ||
1984 | |||
1713 | printk(KERN_INFO "mac80211_hwsim: closing netlink\n"); | 1985 | printk(KERN_INFO "mac80211_hwsim: closing netlink\n"); |
1714 | /* unregister the notifier */ | 1986 | /* unregister the notifier */ |
1715 | netlink_unregister_notifier(&hwsim_netlink_notifier); | 1987 | netlink_unregister_notifier(&hwsim_netlink_notifier); |
@@ -1732,7 +2004,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = { | |||
1732 | { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, | 2004 | { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, |
1733 | }; | 2005 | }; |
1734 | 2006 | ||
1735 | static const struct ieee80211_iface_combination hwsim_if_comb = { | 2007 | static struct ieee80211_iface_combination hwsim_if_comb = { |
1736 | .limits = hwsim_if_limits, | 2008 | .limits = hwsim_if_limits, |
1737 | .n_limits = ARRAY_SIZE(hwsim_if_limits), | 2009 | .n_limits = ARRAY_SIZE(hwsim_if_limits), |
1738 | .max_interfaces = 2048, | 2010 | .max_interfaces = 2048, |
@@ -1750,10 +2022,30 @@ static int __init init_mac80211_hwsim(void) | |||
1750 | if (radios < 1 || radios > 100) | 2022 | if (radios < 1 || radios > 100) |
1751 | return -EINVAL; | 2023 | return -EINVAL; |
1752 | 2024 | ||
1753 | if (fake_hw_scan) { | 2025 | if (channels < 1) |
2026 | return -EINVAL; | ||
2027 | |||
2028 | if (channels > 1) { | ||
2029 | hwsim_if_comb.num_different_channels = channels; | ||
1754 | mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan; | 2030 | mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan; |
2031 | mac80211_hwsim_ops.cancel_hw_scan = | ||
2032 | mac80211_hwsim_cancel_hw_scan; | ||
1755 | mac80211_hwsim_ops.sw_scan_start = NULL; | 2033 | mac80211_hwsim_ops.sw_scan_start = NULL; |
1756 | mac80211_hwsim_ops.sw_scan_complete = NULL; | 2034 | mac80211_hwsim_ops.sw_scan_complete = NULL; |
2035 | mac80211_hwsim_ops.remain_on_channel = | ||
2036 | mac80211_hwsim_roc; | ||
2037 | mac80211_hwsim_ops.cancel_remain_on_channel = | ||
2038 | mac80211_hwsim_croc; | ||
2039 | mac80211_hwsim_ops.add_chanctx = | ||
2040 | mac80211_hwsim_add_chanctx; | ||
2041 | mac80211_hwsim_ops.remove_chanctx = | ||
2042 | mac80211_hwsim_remove_chanctx; | ||
2043 | mac80211_hwsim_ops.change_chanctx = | ||
2044 | mac80211_hwsim_change_chanctx; | ||
2045 | mac80211_hwsim_ops.assign_vif_chanctx = | ||
2046 | mac80211_hwsim_assign_vif_chanctx; | ||
2047 | mac80211_hwsim_ops.unassign_vif_chanctx = | ||
2048 | mac80211_hwsim_unassign_vif_chanctx; | ||
1757 | } | 2049 | } |
1758 | 2050 | ||
1759 | spin_lock_init(&hwsim_radio_lock); | 2051 | spin_lock_init(&hwsim_radio_lock); |
@@ -1803,13 +2095,18 @@ static int __init init_mac80211_hwsim(void) | |||
1803 | hw->wiphy->iface_combinations = &hwsim_if_comb; | 2095 | hw->wiphy->iface_combinations = &hwsim_if_comb; |
1804 | hw->wiphy->n_iface_combinations = 1; | 2096 | hw->wiphy->n_iface_combinations = 1; |
1805 | 2097 | ||
1806 | if (fake_hw_scan) { | 2098 | if (channels > 1) { |
1807 | hw->wiphy->max_scan_ssids = 255; | 2099 | hw->wiphy->max_scan_ssids = 255; |
1808 | hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; | 2100 | hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; |
2101 | hw->wiphy->max_remain_on_channel_duration = 1000; | ||
1809 | } | 2102 | } |
1810 | 2103 | ||
2104 | INIT_DELAYED_WORK(&data->roc_done, hw_roc_done); | ||
2105 | INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work); | ||
2106 | |||
1811 | hw->channel_change_time = 1; | 2107 | hw->channel_change_time = 1; |
1812 | hw->queues = 4; | 2108 | hw->queues = 5; |
2109 | hw->offchannel_tx_hw_queue = 4; | ||
1813 | hw->wiphy->interface_modes = | 2110 | hw->wiphy->interface_modes = |
1814 | BIT(NL80211_IFTYPE_STATION) | | 2111 | BIT(NL80211_IFTYPE_STATION) | |
1815 | BIT(NL80211_IFTYPE_AP) | | 2112 | BIT(NL80211_IFTYPE_AP) | |
@@ -1824,7 +2121,8 @@ static int __init init_mac80211_hwsim(void) | |||
1824 | IEEE80211_HW_SUPPORTS_STATIC_SMPS | | 2121 | IEEE80211_HW_SUPPORTS_STATIC_SMPS | |
1825 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | | 2122 | IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS | |
1826 | IEEE80211_HW_AMPDU_AGGREGATION | | 2123 | IEEE80211_HW_AMPDU_AGGREGATION | |
1827 | IEEE80211_HW_WANT_MONITOR_VIF; | 2124 | IEEE80211_HW_WANT_MONITOR_VIF | |
2125 | IEEE80211_HW_QUEUE_CONTROL; | ||
1828 | 2126 | ||
1829 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | | 2127 | hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | |
1830 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 2128 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index e29505c90cc..41be319665e 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
@@ -324,6 +324,7 @@ mwifiex_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, | |||
324 | */ | 324 | */ |
325 | static int | 325 | static int |
326 | mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, | 326 | mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, |
327 | struct wireless_dev *wdev, | ||
327 | enum nl80211_tx_power_setting type, | 328 | enum nl80211_tx_power_setting type, |
328 | int mbm) | 329 | int mbm) |
329 | { | 330 | { |
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index bd1f0cb5608..5390af36c06 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -490,9 +490,12 @@ static int rndis_scan(struct wiphy *wiphy, | |||
490 | static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed); | 490 | static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed); |
491 | 491 | ||
492 | static int rndis_set_tx_power(struct wiphy *wiphy, | 492 | static int rndis_set_tx_power(struct wiphy *wiphy, |
493 | struct wireless_dev *wdev, | ||
493 | enum nl80211_tx_power_setting type, | 494 | enum nl80211_tx_power_setting type, |
494 | int mbm); | 495 | int mbm); |
495 | static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm); | 496 | static int rndis_get_tx_power(struct wiphy *wiphy, |
497 | struct wireless_dev *wdev, | ||
498 | int *dbm); | ||
496 | 499 | ||
497 | static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, | 500 | static int rndis_connect(struct wiphy *wiphy, struct net_device *dev, |
498 | struct cfg80211_connect_params *sme); | 501 | struct cfg80211_connect_params *sme); |
@@ -1903,6 +1906,7 @@ static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
1903 | } | 1906 | } |
1904 | 1907 | ||
1905 | static int rndis_set_tx_power(struct wiphy *wiphy, | 1908 | static int rndis_set_tx_power(struct wiphy *wiphy, |
1909 | struct wireless_dev *wdev, | ||
1906 | enum nl80211_tx_power_setting type, | 1910 | enum nl80211_tx_power_setting type, |
1907 | int mbm) | 1911 | int mbm) |
1908 | { | 1912 | { |
@@ -1930,7 +1934,9 @@ static int rndis_set_tx_power(struct wiphy *wiphy, | |||
1930 | return -ENOTSUPP; | 1934 | return -ENOTSUPP; |
1931 | } | 1935 | } |
1932 | 1936 | ||
1933 | static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm) | 1937 | static int rndis_get_tx_power(struct wiphy *wiphy, |
1938 | struct wireless_dev *wdev, | ||
1939 | int *dbm) | ||
1934 | { | 1940 | { |
1935 | struct rndis_wlan_private *priv = wiphy_priv(wiphy); | 1941 | struct rndis_wlan_private *priv = wiphy_priv(wiphy); |
1936 | struct usbnet *usbdev = priv->usbdev; | 1942 | struct usbnet *usbdev = priv->usbdev; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 69097d1faeb..67d167993d4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -157,6 +157,7 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work) | |||
157 | * requested configurations. | 157 | * requested configurations. |
158 | */ | 158 | */ |
159 | ieee80211_iterate_active_interfaces(rt2x00dev->hw, | 159 | ieee80211_iterate_active_interfaces(rt2x00dev->hw, |
160 | IEEE80211_IFACE_ITER_RESUME_ALL, | ||
160 | rt2x00lib_intf_scheduled_iter, | 161 | rt2x00lib_intf_scheduled_iter, |
161 | rt2x00dev); | 162 | rt2x00dev); |
162 | } | 163 | } |
@@ -225,9 +226,9 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) | |||
225 | return; | 226 | return; |
226 | 227 | ||
227 | /* send buffered bc/mc frames out for every bssid */ | 228 | /* send buffered bc/mc frames out for every bssid */ |
228 | ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, | 229 | ieee80211_iterate_active_interfaces_atomic( |
229 | rt2x00lib_bc_buffer_iter, | 230 | rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
230 | rt2x00dev); | 231 | rt2x00lib_bc_buffer_iter, rt2x00dev); |
231 | /* | 232 | /* |
232 | * Devices with pre tbtt interrupt don't need to update the beacon | 233 | * Devices with pre tbtt interrupt don't need to update the beacon |
233 | * here as they will fetch the next beacon directly prior to | 234 | * here as they will fetch the next beacon directly prior to |
@@ -237,9 +238,9 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) | |||
237 | return; | 238 | return; |
238 | 239 | ||
239 | /* fetch next beacon */ | 240 | /* fetch next beacon */ |
240 | ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, | 241 | ieee80211_iterate_active_interfaces_atomic( |
241 | rt2x00lib_beaconupdate_iter, | 242 | rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
242 | rt2x00dev); | 243 | rt2x00lib_beaconupdate_iter, rt2x00dev); |
243 | } | 244 | } |
244 | EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); | 245 | EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); |
245 | 246 | ||
@@ -249,9 +250,9 @@ void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev) | |||
249 | return; | 250 | return; |
250 | 251 | ||
251 | /* fetch next beacon */ | 252 | /* fetch next beacon */ |
252 | ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, | 253 | ieee80211_iterate_active_interfaces_atomic( |
253 | rt2x00lib_beaconupdate_iter, | 254 | rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
254 | rt2x00dev); | 255 | rt2x00lib_beaconupdate_iter, rt2x00dev); |
255 | } | 256 | } |
256 | EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt); | 257 | EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt); |
257 | 258 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 98a9e48f8e4..ed7a1bb3f24 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c | |||
@@ -424,9 +424,9 @@ int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, | |||
424 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | 424 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
425 | return 0; | 425 | return 0; |
426 | 426 | ||
427 | ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, | 427 | ieee80211_iterate_active_interfaces_atomic( |
428 | rt2x00mac_set_tim_iter, | 428 | rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
429 | rt2x00dev); | 429 | rt2x00mac_set_tim_iter, rt2x00dev); |
430 | 430 | ||
431 | /* queue work to upodate the beacon template */ | 431 | /* queue work to upodate the beacon template */ |
432 | ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work); | 432 | ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work); |
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 25530c8760c..380cf1ff6cd 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c | |||
@@ -677,7 +677,7 @@ static void wl12xx_get_vif_count(struct ieee80211_hw *hw, | |||
677 | memset(data, 0, sizeof(*data)); | 677 | memset(data, 0, sizeof(*data)); |
678 | data->cur_vif = cur_vif; | 678 | data->cur_vif = cur_vif; |
679 | 679 | ||
680 | ieee80211_iterate_active_interfaces(hw, | 680 | ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, |
681 | wl12xx_vif_count_iter, data); | 681 | wl12xx_vif_count_iter, data); |
682 | } | 682 | } |
683 | 683 | ||
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 85764a90073..4530d496095 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -905,6 +905,38 @@ struct ieee80211_tdls_data { | |||
905 | } u; | 905 | } u; |
906 | } __packed; | 906 | } __packed; |
907 | 907 | ||
908 | /* | ||
909 | * Peer-to-Peer IE attribute related definitions. | ||
910 | */ | ||
911 | /** | ||
912 | * enum ieee80211_p2p_attr_id - identifies type of peer-to-peer attribute. | ||
913 | */ | ||
914 | enum ieee80211_p2p_attr_id { | ||
915 | IEEE80211_P2P_ATTR_STATUS = 0, | ||
916 | IEEE80211_P2P_ATTR_MINOR_REASON, | ||
917 | IEEE80211_P2P_ATTR_CAPABILITY, | ||
918 | IEEE80211_P2P_ATTR_DEVICE_ID, | ||
919 | IEEE80211_P2P_ATTR_GO_INTENT, | ||
920 | IEEE80211_P2P_ATTR_GO_CONFIG_TIMEOUT, | ||
921 | IEEE80211_P2P_ATTR_LISTEN_CHANNEL, | ||
922 | IEEE80211_P2P_ATTR_GROUP_BSSID, | ||
923 | IEEE80211_P2P_ATTR_EXT_LISTEN_TIMING, | ||
924 | IEEE80211_P2P_ATTR_INTENDED_IFACE_ADDR, | ||
925 | IEEE80211_P2P_ATTR_MANAGABILITY, | ||
926 | IEEE80211_P2P_ATTR_CHANNEL_LIST, | ||
927 | IEEE80211_P2P_ATTR_ABSENCE_NOTICE, | ||
928 | IEEE80211_P2P_ATTR_DEVICE_INFO, | ||
929 | IEEE80211_P2P_ATTR_GROUP_INFO, | ||
930 | IEEE80211_P2P_ATTR_GROUP_ID, | ||
931 | IEEE80211_P2P_ATTR_INTERFACE, | ||
932 | IEEE80211_P2P_ATTR_OPER_CHANNEL, | ||
933 | IEEE80211_P2P_ATTR_INVITE_FLAGS, | ||
934 | /* 19 - 220: Reserved */ | ||
935 | IEEE80211_P2P_ATTR_VENDOR_SPECIFIC = 221, | ||
936 | |||
937 | IEEE80211_P2P_ATTR_MAX | ||
938 | }; | ||
939 | |||
908 | /** | 940 | /** |
909 | * struct ieee80211_bar - HT Block Ack Request | 941 | * struct ieee80211_bar - HT Block Ack Request |
910 | * | 942 | * |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index c6964572890..81d725038f9 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -1545,13 +1545,19 @@ struct cfg80211_gtk_rekey_data { | |||
1545 | * to a merge. | 1545 | * to a merge. |
1546 | * @leave_ibss: Leave the IBSS. | 1546 | * @leave_ibss: Leave the IBSS. |
1547 | * | 1547 | * |
1548 | * @set_mcast_rate: Set the specified multicast rate (only if vif is in ADHOC or | ||
1549 | * MESH mode) | ||
1550 | * | ||
1548 | * @set_wiphy_params: Notify that wiphy parameters have changed; | 1551 | * @set_wiphy_params: Notify that wiphy parameters have changed; |
1549 | * @changed bitfield (see &enum wiphy_params_flags) describes which values | 1552 | * @changed bitfield (see &enum wiphy_params_flags) describes which values |
1550 | * have changed. The actual parameter values are available in | 1553 | * have changed. The actual parameter values are available in |
1551 | * struct wiphy. If returning an error, no value should be changed. | 1554 | * struct wiphy. If returning an error, no value should be changed. |
1552 | * | 1555 | * |
1553 | * @set_tx_power: set the transmit power according to the parameters, | 1556 | * @set_tx_power: set the transmit power according to the parameters, |
1554 | * the power passed is in mBm, to get dBm use MBM_TO_DBM(). | 1557 | * the power passed is in mBm, to get dBm use MBM_TO_DBM(). The |
1558 | * wdev may be %NULL if power was set for the wiphy, and will | ||
1559 | * always be %NULL unless the driver supports per-vif TX power | ||
1560 | * (as advertised by the nl80211 feature flag.) | ||
1555 | * @get_tx_power: store the current TX power into the dbm variable; | 1561 | * @get_tx_power: store the current TX power into the dbm variable; |
1556 | * return 0 if successful | 1562 | * return 0 if successful |
1557 | * | 1563 | * |
@@ -1746,11 +1752,15 @@ struct cfg80211_ops { | |||
1746 | struct cfg80211_ibss_params *params); | 1752 | struct cfg80211_ibss_params *params); |
1747 | int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); | 1753 | int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); |
1748 | 1754 | ||
1755 | int (*set_mcast_rate)(struct wiphy *wiphy, struct net_device *dev, | ||
1756 | int rate[IEEE80211_NUM_BANDS]); | ||
1757 | |||
1749 | int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed); | 1758 | int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed); |
1750 | 1759 | ||
1751 | int (*set_tx_power)(struct wiphy *wiphy, | 1760 | int (*set_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev, |
1752 | enum nl80211_tx_power_setting type, int mbm); | 1761 | enum nl80211_tx_power_setting type, int mbm); |
1753 | int (*get_tx_power)(struct wiphy *wiphy, int *dbm); | 1762 | int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev, |
1763 | int *dbm); | ||
1754 | 1764 | ||
1755 | int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev, | 1765 | int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev, |
1756 | const u8 *addr); | 1766 | const u8 *addr); |
@@ -3550,7 +3560,6 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, | |||
3550 | * @len: length of the frame | 3560 | * @len: length of the frame |
3551 | * @freq: frequency the frame was received on | 3561 | * @freq: frequency the frame was received on |
3552 | * @sig_dbm: signal strength in mBm, or 0 if unknown | 3562 | * @sig_dbm: signal strength in mBm, or 0 if unknown |
3553 | * @gfp: allocation flags | ||
3554 | * | 3563 | * |
3555 | * Use this function to report to userspace when a beacon was | 3564 | * Use this function to report to userspace when a beacon was |
3556 | * received. It is not useful to call this when there is no | 3565 | * received. It is not useful to call this when there is no |
@@ -3558,7 +3567,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, | |||
3558 | */ | 3567 | */ |
3559 | void cfg80211_report_obss_beacon(struct wiphy *wiphy, | 3568 | void cfg80211_report_obss_beacon(struct wiphy *wiphy, |
3560 | const u8 *frame, size_t len, | 3569 | const u8 *frame, size_t len, |
3561 | int freq, int sig_dbm, gfp_t gfp); | 3570 | int freq, int sig_dbm); |
3562 | 3571 | ||
3563 | /** | 3572 | /** |
3564 | * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used | 3573 | * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used |
@@ -3608,6 +3617,25 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate); | |||
3608 | */ | 3617 | */ |
3609 | void cfg80211_unregister_wdev(struct wireless_dev *wdev); | 3618 | void cfg80211_unregister_wdev(struct wireless_dev *wdev); |
3610 | 3619 | ||
3620 | /** | ||
3621 | * cfg80211_get_p2p_attr - find and copy a P2P attribute from IE buffer | ||
3622 | * @ies: the input IE buffer | ||
3623 | * @len: the input length | ||
3624 | * @attr: the attribute ID to find | ||
3625 | * @buf: output buffer, can be %NULL if the data isn't needed, e.g. | ||
3626 | * if the function is only called to get the needed buffer size | ||
3627 | * @bufsize: size of the output buffer | ||
3628 | * | ||
3629 | * The function finds a given P2P attribute in the (vendor) IEs and | ||
3630 | * copies its contents to the given buffer. | ||
3631 | * | ||
3632 | * The return value is a negative error code (-%EILSEQ or -%ENOENT) if | ||
3633 | * the data is malformed or the attribute can't be found (respectively), | ||
3634 | * or the length of the found attribute (which can be zero). | ||
3635 | */ | ||
3636 | unsigned int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, | ||
3637 | u8 attr, u8 *buf, unsigned int bufsize); | ||
3638 | |||
3611 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ | 3639 | /* Logging, debugging and troubleshooting/diagnostic helpers. */ |
3612 | 3640 | ||
3613 | /* wiphy_printk helpers, similar to dev_printk */ | 3641 | /* wiphy_printk helpers, similar to dev_printk */ |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 00b7204708b..a789dd1d4c1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -207,6 +207,9 @@ struct ieee80211_chanctx_conf { | |||
207 | * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode) | 207 | * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode) |
208 | * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode) | 208 | * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode) |
209 | * @BSS_CHANGED_PS: PS changed for this BSS (STA mode) | 209 | * @BSS_CHANGED_PS: PS changed for this BSS (STA mode) |
210 | * @BSS_CHANGED_TXPOWER: TX power setting changed for this interface | ||
211 | * @BSS_CHANGED_P2P_PS: P2P powersave settings (CTWindow, opportunistic PS) | ||
212 | * changed (currently only in P2P client mode, GO mode will be later) | ||
210 | */ | 213 | */ |
211 | enum ieee80211_bss_change { | 214 | enum ieee80211_bss_change { |
212 | BSS_CHANGED_ASSOC = 1<<0, | 215 | BSS_CHANGED_ASSOC = 1<<0, |
@@ -227,6 +230,8 @@ enum ieee80211_bss_change { | |||
227 | BSS_CHANGED_SSID = 1<<15, | 230 | BSS_CHANGED_SSID = 1<<15, |
228 | BSS_CHANGED_AP_PROBE_RESP = 1<<16, | 231 | BSS_CHANGED_AP_PROBE_RESP = 1<<16, |
229 | BSS_CHANGED_PS = 1<<17, | 232 | BSS_CHANGED_PS = 1<<17, |
233 | BSS_CHANGED_TXPOWER = 1<<18, | ||
234 | BSS_CHANGED_P2P_PS = 1<<19, | ||
230 | 235 | ||
231 | /* when adding here, make sure to change ieee80211_reconfig */ | 236 | /* when adding here, make sure to change ieee80211_reconfig */ |
232 | }; | 237 | }; |
@@ -309,6 +314,9 @@ enum ieee80211_rssi_event { | |||
309 | * @ssid: The SSID of the current vif. Only valid in AP-mode. | 314 | * @ssid: The SSID of the current vif. Only valid in AP-mode. |
310 | * @ssid_len: Length of SSID given in @ssid. | 315 | * @ssid_len: Length of SSID given in @ssid. |
311 | * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode. | 316 | * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode. |
317 | * @txpower: TX power in dBm | ||
318 | * @p2p_ctwindow: P2P CTWindow, only for P2P client interfaces | ||
319 | * @p2p_oppps: P2P opportunistic PS is enabled | ||
312 | */ | 320 | */ |
313 | struct ieee80211_bss_conf { | 321 | struct ieee80211_bss_conf { |
314 | const u8 *bssid; | 322 | const u8 *bssid; |
@@ -341,6 +349,9 @@ struct ieee80211_bss_conf { | |||
341 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 349 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
342 | size_t ssid_len; | 350 | size_t ssid_len; |
343 | bool hidden_ssid; | 351 | bool hidden_ssid; |
352 | int txpower; | ||
353 | u8 p2p_ctwindow; | ||
354 | bool p2p_oppps; | ||
344 | }; | 355 | }; |
345 | 356 | ||
346 | /** | 357 | /** |
@@ -884,7 +895,8 @@ enum ieee80211_smps_mode { | |||
884 | * powersave documentation below. This variable is valid only when | 895 | * powersave documentation below. This variable is valid only when |
885 | * the CONF_PS flag is set. | 896 | * the CONF_PS flag is set. |
886 | * | 897 | * |
887 | * @power_level: requested transmit power (in dBm) | 898 | * @power_level: requested transmit power (in dBm), backward compatibility |
899 | * value only that is set to the minimum of all interfaces | ||
888 | * | 900 | * |
889 | * @channel: the channel to tune to | 901 | * @channel: the channel to tune to |
890 | * @channel_type: the channel (HT) type | 902 | * @channel_type: the channel (HT) type |
@@ -2381,6 +2393,17 @@ enum ieee80211_rate_control_changed { | |||
2381 | * to vif. Possible use is for hw queue remapping. | 2393 | * to vif. Possible use is for hw queue remapping. |
2382 | * @unassign_vif_chanctx: Notifies device driver about channel context being | 2394 | * @unassign_vif_chanctx: Notifies device driver about channel context being |
2383 | * unbound from vif. | 2395 | * unbound from vif. |
2396 | * @start_ap: Start operation on the AP interface, this is called after all the | ||
2397 | * information in bss_conf is set and beacon can be retrieved. A channel | ||
2398 | * context is bound before this is called. Note that if the driver uses | ||
2399 | * software scan or ROC, this (and @stop_ap) isn't called when the AP is | ||
2400 | * just "paused" for scanning/ROC, which is indicated by the beacon being | ||
2401 | * disabled/enabled via @bss_info_changed. | ||
2402 | * @stop_ap: Stop operation on the AP interface. | ||
2403 | * | ||
2404 | * @restart_complete: Called after a call to ieee80211_restart_hw(), when the | ||
2405 | * reconfiguration has completed. This can help the driver implement the | ||
2406 | * reconfiguration step. This callback may sleep. | ||
2384 | */ | 2407 | */ |
2385 | struct ieee80211_ops { | 2408 | struct ieee80211_ops { |
2386 | void (*tx)(struct ieee80211_hw *hw, | 2409 | void (*tx)(struct ieee80211_hw *hw, |
@@ -2406,6 +2429,9 @@ struct ieee80211_ops { | |||
2406 | struct ieee80211_bss_conf *info, | 2429 | struct ieee80211_bss_conf *info, |
2407 | u32 changed); | 2430 | u32 changed); |
2408 | 2431 | ||
2432 | int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | ||
2433 | void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif); | ||
2434 | |||
2409 | u64 (*prepare_multicast)(struct ieee80211_hw *hw, | 2435 | u64 (*prepare_multicast)(struct ieee80211_hw *hw, |
2410 | struct netdev_hw_addr_list *mc_list); | 2436 | struct netdev_hw_addr_list *mc_list); |
2411 | void (*configure_filter)(struct ieee80211_hw *hw, | 2437 | void (*configure_filter)(struct ieee80211_hw *hw, |
@@ -2539,6 +2565,8 @@ struct ieee80211_ops { | |||
2539 | void (*unassign_vif_chanctx)(struct ieee80211_hw *hw, | 2565 | void (*unassign_vif_chanctx)(struct ieee80211_hw *hw, |
2540 | struct ieee80211_vif *vif, | 2566 | struct ieee80211_vif *vif, |
2541 | struct ieee80211_chanctx_conf *ctx); | 2567 | struct ieee80211_chanctx_conf *ctx); |
2568 | |||
2569 | void (*restart_complete)(struct ieee80211_hw *hw); | ||
2542 | }; | 2570 | }; |
2543 | 2571 | ||
2544 | /** | 2572 | /** |
@@ -3385,6 +3413,21 @@ void ieee80211_sched_scan_results(struct ieee80211_hw *hw); | |||
3385 | void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw); | 3413 | void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw); |
3386 | 3414 | ||
3387 | /** | 3415 | /** |
3416 | * enum ieee80211_interface_iteration_flags - interface iteration flags | ||
3417 | * @IEEE80211_IFACE_ITER_NORMAL: Iterate over all interfaces that have | ||
3418 | * been added to the driver; However, note that during hardware | ||
3419 | * reconfiguration (after restart_hw) it will iterate over a new | ||
3420 | * interface and over all the existing interfaces even if they | ||
3421 | * haven't been re-added to the driver yet. | ||
3422 | * @IEEE80211_IFACE_ITER_RESUME_ALL: During resume, iterate over all | ||
3423 | * interfaces, even if they haven't been re-added to the driver yet. | ||
3424 | */ | ||
3425 | enum ieee80211_interface_iteration_flags { | ||
3426 | IEEE80211_IFACE_ITER_NORMAL = 0, | ||
3427 | IEEE80211_IFACE_ITER_RESUME_ALL = BIT(0), | ||
3428 | }; | ||
3429 | |||
3430 | /** | ||
3388 | * ieee80211_iterate_active_interfaces - iterate active interfaces | 3431 | * ieee80211_iterate_active_interfaces - iterate active interfaces |
3389 | * | 3432 | * |
3390 | * This function iterates over the interfaces associated with a given | 3433 | * This function iterates over the interfaces associated with a given |
@@ -3392,13 +3435,15 @@ void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw); | |||
3392 | * This function allows the iterator function to sleep, when the iterator | 3435 | * This function allows the iterator function to sleep, when the iterator |
3393 | * function is atomic @ieee80211_iterate_active_interfaces_atomic can | 3436 | * function is atomic @ieee80211_iterate_active_interfaces_atomic can |
3394 | * be used. | 3437 | * be used. |
3395 | * Does not iterate over a new interface during add_interface() | 3438 | * Does not iterate over a new interface during add_interface(). |
3396 | * | 3439 | * |
3397 | * @hw: the hardware struct of which the interfaces should be iterated over | 3440 | * @hw: the hardware struct of which the interfaces should be iterated over |
3441 | * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags | ||
3398 | * @iterator: the iterator function to call | 3442 | * @iterator: the iterator function to call |
3399 | * @data: first argument of the iterator function | 3443 | * @data: first argument of the iterator function |
3400 | */ | 3444 | */ |
3401 | void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, | 3445 | void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, |
3446 | u32 iter_flags, | ||
3402 | void (*iterator)(void *data, u8 *mac, | 3447 | void (*iterator)(void *data, u8 *mac, |
3403 | struct ieee80211_vif *vif), | 3448 | struct ieee80211_vif *vif), |
3404 | void *data); | 3449 | void *data); |
@@ -3410,13 +3455,15 @@ void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, | |||
3410 | * hardware that are currently active and calls the callback for them. | 3455 | * hardware that are currently active and calls the callback for them. |
3411 | * This function requires the iterator callback function to be atomic, | 3456 | * This function requires the iterator callback function to be atomic, |
3412 | * if that is not desired, use @ieee80211_iterate_active_interfaces instead. | 3457 | * if that is not desired, use @ieee80211_iterate_active_interfaces instead. |
3413 | * Does not iterate over a new interface during add_interface() | 3458 | * Does not iterate over a new interface during add_interface(). |
3414 | * | 3459 | * |
3415 | * @hw: the hardware struct of which the interfaces should be iterated over | 3460 | * @hw: the hardware struct of which the interfaces should be iterated over |
3461 | * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags | ||
3416 | * @iterator: the iterator function to call, cannot sleep | 3462 | * @iterator: the iterator function to call, cannot sleep |
3417 | * @data: first argument of the iterator function | 3463 | * @data: first argument of the iterator function |
3418 | */ | 3464 | */ |
3419 | void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw, | 3465 | void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw, |
3466 | u32 iter_flags, | ||
3420 | void (*iterator)(void *data, | 3467 | void (*iterator)(void *data, |
3421 | u8 *mac, | 3468 | u8 *mac, |
3422 | struct ieee80211_vif *vif), | 3469 | struct ieee80211_vif *vif), |
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 617d0fbfc96..cbd2d6bb907 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -578,6 +578,9 @@ | |||
578 | * station, due to particular reason. %NL80211_ATTR_CONN_FAILED_REASON | 578 | * station, due to particular reason. %NL80211_ATTR_CONN_FAILED_REASON |
579 | * is used for this. | 579 | * is used for this. |
580 | * | 580 | * |
581 | * @NL80211_CMD_SET_MCAST_RATE: Change the rate used to send multicast frames | ||
582 | * for IBSS or MESH vif. | ||
583 | * | ||
581 | * @NL80211_CMD_MAX: highest used command number | 584 | * @NL80211_CMD_MAX: highest used command number |
582 | * @__NL80211_CMD_AFTER_LAST: internal use | 585 | * @__NL80211_CMD_AFTER_LAST: internal use |
583 | */ | 586 | */ |
@@ -726,6 +729,8 @@ enum nl80211_commands { | |||
726 | 729 | ||
727 | NL80211_CMD_CONN_FAILED, | 730 | NL80211_CMD_CONN_FAILED, |
728 | 731 | ||
732 | NL80211_CMD_SET_MCAST_RATE, | ||
733 | |||
729 | /* add new commands above here */ | 734 | /* add new commands above here */ |
730 | 735 | ||
731 | /* used to define NL80211_CMD_MAX below */ | 736 | /* used to define NL80211_CMD_MAX below */ |
@@ -3051,6 +3056,7 @@ enum nl80211_ap_sme_features { | |||
3051 | * @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan | 3056 | * @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan |
3052 | * @NL80211_FEATURE_SCAN_FLUSH: Scan flush is supported | 3057 | * @NL80211_FEATURE_SCAN_FLUSH: Scan flush is supported |
3053 | * @NL80211_FEATURE_AP_SCAN: Support scanning using an AP vif | 3058 | * @NL80211_FEATURE_AP_SCAN: Support scanning using an AP vif |
3059 | * @NL80211_FEATURE_VIF_TXPOWER: The driver supports per-vif TX power setting | ||
3054 | */ | 3060 | */ |
3055 | enum nl80211_feature_flags { | 3061 | enum nl80211_feature_flags { |
3056 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, | 3062 | NL80211_FEATURE_SK_TX_STATUS = 1 << 0, |
@@ -3062,6 +3068,7 @@ enum nl80211_feature_flags { | |||
3062 | NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6, | 3068 | NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6, |
3063 | NL80211_FEATURE_SCAN_FLUSH = 1 << 7, | 3069 | NL80211_FEATURE_SCAN_FLUSH = 1 << 7, |
3064 | NL80211_FEATURE_AP_SCAN = 1 << 8, | 3070 | NL80211_FEATURE_AP_SCAN = 1 << 8, |
3071 | NL80211_FEATURE_VIF_TXPOWER = 1 << 9, | ||
3065 | }; | 3072 | }; |
3066 | 3073 | ||
3067 | /** | 3074 | /** |
diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c index 493353534a0..537488cbf94 100644 --- a/net/mac80211/aes_cmac.c +++ b/net/mac80211/aes_cmac.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
12 | #include <linux/crypto.h> | 12 | #include <linux/crypto.h> |
13 | #include <linux/export.h> | ||
13 | #include <linux/err.h> | 14 | #include <linux/err.h> |
14 | #include <crypto/aes.h> | 15 | #include <crypto/aes.h> |
15 | 16 | ||
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5eab1325a0f..80e0618b25b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -922,6 +922,15 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
922 | return err; | 922 | return err; |
923 | changed |= err; | 923 | changed |= err; |
924 | 924 | ||
925 | err = drv_start_ap(sdata->local, sdata); | ||
926 | if (err) { | ||
927 | old = rtnl_dereference(sdata->u.ap.beacon); | ||
928 | if (old) | ||
929 | kfree_rcu(old, rcu_head); | ||
930 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); | ||
931 | return err; | ||
932 | } | ||
933 | |||
925 | ieee80211_bss_info_change_notify(sdata, changed); | 934 | ieee80211_bss_info_change_notify(sdata, changed); |
926 | 935 | ||
927 | netif_carrier_on(dev); | 936 | netif_carrier_on(dev); |
@@ -953,26 +962,38 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
953 | 962 | ||
954 | static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | 963 | static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) |
955 | { | 964 | { |
956 | struct ieee80211_sub_if_data *sdata, *vlan; | 965 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
957 | struct beacon_data *old; | 966 | struct ieee80211_sub_if_data *vlan; |
958 | 967 | struct ieee80211_local *local = sdata->local; | |
959 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 968 | struct beacon_data *old_beacon; |
969 | struct probe_resp *old_probe_resp; | ||
960 | 970 | ||
961 | old = rtnl_dereference(sdata->u.ap.beacon); | 971 | old_beacon = rtnl_dereference(sdata->u.ap.beacon); |
962 | if (!old) | 972 | if (!old_beacon) |
963 | return -ENOENT; | 973 | return -ENOENT; |
974 | old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp); | ||
964 | 975 | ||
976 | /* turn off carrier for this interface and dependent VLANs */ | ||
965 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | 977 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) |
966 | netif_carrier_off(vlan->dev); | 978 | netif_carrier_off(vlan->dev); |
967 | netif_carrier_off(dev); | 979 | netif_carrier_off(dev); |
968 | 980 | ||
981 | /* remove beacon and probe response */ | ||
969 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); | 982 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); |
983 | RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); | ||
984 | kfree_rcu(old_beacon, rcu_head); | ||
985 | if (old_probe_resp) | ||
986 | kfree_rcu(old_probe_resp, rcu_head); | ||
970 | 987 | ||
971 | kfree_rcu(old, rcu_head); | 988 | sta_info_flush(local, sdata); |
972 | |||
973 | sta_info_flush(sdata->local, sdata); | ||
974 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 989 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
975 | 990 | ||
991 | drv_stop_ap(sdata->local, sdata); | ||
992 | |||
993 | /* free all potentially still buffered bcast frames */ | ||
994 | local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); | ||
995 | skb_queue_purge(&sdata->u.ap.ps.bc_buf); | ||
996 | |||
976 | ieee80211_vif_release_channel(sdata); | 997 | ieee80211_vif_release_channel(sdata); |
977 | 998 | ||
978 | return 0; | 999 | return 0; |
@@ -1933,6 +1954,16 @@ static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | |||
1933 | return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev)); | 1954 | return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev)); |
1934 | } | 1955 | } |
1935 | 1956 | ||
1957 | static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, | ||
1958 | int rate[IEEE80211_NUM_BANDS]) | ||
1959 | { | ||
1960 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1961 | |||
1962 | memcpy(sdata->vif.bss_conf.mcast_rate, rate, sizeof(rate)); | ||
1963 | |||
1964 | return 0; | ||
1965 | } | ||
1966 | |||
1936 | static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | 1967 | static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) |
1937 | { | 1968 | { |
1938 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1969 | struct ieee80211_local *local = wiphy_priv(wiphy); |
@@ -1971,45 +2002,65 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
1971 | } | 2002 | } |
1972 | 2003 | ||
1973 | static int ieee80211_set_tx_power(struct wiphy *wiphy, | 2004 | static int ieee80211_set_tx_power(struct wiphy *wiphy, |
2005 | struct wireless_dev *wdev, | ||
1974 | enum nl80211_tx_power_setting type, int mbm) | 2006 | enum nl80211_tx_power_setting type, int mbm) |
1975 | { | 2007 | { |
1976 | struct ieee80211_local *local = wiphy_priv(wiphy); | 2008 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1977 | struct ieee80211_channel *chan = local->_oper_channel; | 2009 | struct ieee80211_sub_if_data *sdata; |
1978 | u32 changes = 0; | ||
1979 | 2010 | ||
1980 | /* FIXME */ | 2011 | if (wdev) { |
1981 | if (local->use_chanctx) | 2012 | sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
1982 | return -EOPNOTSUPP; | 2013 | |
2014 | switch (type) { | ||
2015 | case NL80211_TX_POWER_AUTOMATIC: | ||
2016 | sdata->user_power_level = IEEE80211_UNSET_POWER_LEVEL; | ||
2017 | break; | ||
2018 | case NL80211_TX_POWER_LIMITED: | ||
2019 | case NL80211_TX_POWER_FIXED: | ||
2020 | if (mbm < 0 || (mbm % 100)) | ||
2021 | return -EOPNOTSUPP; | ||
2022 | sdata->user_power_level = MBM_TO_DBM(mbm); | ||
2023 | break; | ||
2024 | } | ||
2025 | |||
2026 | ieee80211_recalc_txpower(sdata); | ||
2027 | |||
2028 | return 0; | ||
2029 | } | ||
1983 | 2030 | ||
1984 | switch (type) { | 2031 | switch (type) { |
1985 | case NL80211_TX_POWER_AUTOMATIC: | 2032 | case NL80211_TX_POWER_AUTOMATIC: |
1986 | local->user_power_level = -1; | 2033 | local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; |
1987 | break; | 2034 | break; |
1988 | case NL80211_TX_POWER_LIMITED: | 2035 | case NL80211_TX_POWER_LIMITED: |
1989 | if (mbm < 0 || (mbm % 100)) | ||
1990 | return -EOPNOTSUPP; | ||
1991 | local->user_power_level = MBM_TO_DBM(mbm); | ||
1992 | break; | ||
1993 | case NL80211_TX_POWER_FIXED: | 2036 | case NL80211_TX_POWER_FIXED: |
1994 | if (mbm < 0 || (mbm % 100)) | 2037 | if (mbm < 0 || (mbm % 100)) |
1995 | return -EOPNOTSUPP; | 2038 | return -EOPNOTSUPP; |
1996 | /* TODO: move to cfg80211 when it knows the channel */ | ||
1997 | if (MBM_TO_DBM(mbm) > chan->max_power) | ||
1998 | return -EINVAL; | ||
1999 | local->user_power_level = MBM_TO_DBM(mbm); | 2039 | local->user_power_level = MBM_TO_DBM(mbm); |
2000 | break; | 2040 | break; |
2001 | } | 2041 | } |
2002 | 2042 | ||
2003 | ieee80211_hw_config(local, changes); | 2043 | mutex_lock(&local->iflist_mtx); |
2044 | list_for_each_entry(sdata, &local->interfaces, list) | ||
2045 | sdata->user_power_level = local->user_power_level; | ||
2046 | list_for_each_entry(sdata, &local->interfaces, list) | ||
2047 | ieee80211_recalc_txpower(sdata); | ||
2048 | mutex_unlock(&local->iflist_mtx); | ||
2004 | 2049 | ||
2005 | return 0; | 2050 | return 0; |
2006 | } | 2051 | } |
2007 | 2052 | ||
2008 | static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm) | 2053 | static int ieee80211_get_tx_power(struct wiphy *wiphy, |
2054 | struct wireless_dev *wdev, | ||
2055 | int *dbm) | ||
2009 | { | 2056 | { |
2010 | struct ieee80211_local *local = wiphy_priv(wiphy); | 2057 | struct ieee80211_local *local = wiphy_priv(wiphy); |
2058 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | ||
2011 | 2059 | ||
2012 | *dbm = local->hw.conf.power_level; | 2060 | if (!local->use_chanctx) |
2061 | *dbm = local->hw.conf.power_level; | ||
2062 | else | ||
2063 | *dbm = sdata->vif.bss_conf.txpower; | ||
2013 | 2064 | ||
2014 | return 0; | 2065 | return 0; |
2015 | } | 2066 | } |
@@ -2341,13 +2392,22 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, | |||
2341 | list_add_tail(&roc->list, &local->roc_list); | 2392 | list_add_tail(&roc->list, &local->roc_list); |
2342 | 2393 | ||
2343 | /* | 2394 | /* |
2344 | * cookie is either the roc (for normal roc) | 2395 | * cookie is either the roc cookie (for normal roc) |
2345 | * or the SKB (for mgmt TX) | 2396 | * or the SKB (for mgmt TX) |
2346 | */ | 2397 | */ |
2347 | if (txskb) | 2398 | if (!txskb) { |
2399 | /* local->mtx protects this */ | ||
2400 | local->roc_cookie_counter++; | ||
2401 | roc->cookie = local->roc_cookie_counter; | ||
2402 | /* wow, you wrapped 64 bits ... more likely a bug */ | ||
2403 | if (WARN_ON(roc->cookie == 0)) { | ||
2404 | roc->cookie = 1; | ||
2405 | local->roc_cookie_counter++; | ||
2406 | } | ||
2407 | *cookie = roc->cookie; | ||
2408 | } else { | ||
2348 | *cookie = (unsigned long)txskb; | 2409 | *cookie = (unsigned long)txskb; |
2349 | else | 2410 | } |
2350 | *cookie = (unsigned long)roc; | ||
2351 | 2411 | ||
2352 | return 0; | 2412 | return 0; |
2353 | } | 2413 | } |
@@ -2382,7 +2442,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, | |||
2382 | struct ieee80211_roc_work *dep, *tmp2; | 2442 | struct ieee80211_roc_work *dep, *tmp2; |
2383 | 2443 | ||
2384 | list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) { | 2444 | list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) { |
2385 | if (!mgmt_tx && (unsigned long)dep != cookie) | 2445 | if (!mgmt_tx && dep->cookie != cookie) |
2386 | continue; | 2446 | continue; |
2387 | else if (mgmt_tx && dep->mgmt_tx_cookie != cookie) | 2447 | else if (mgmt_tx && dep->mgmt_tx_cookie != cookie) |
2388 | continue; | 2448 | continue; |
@@ -2394,7 +2454,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, | |||
2394 | return 0; | 2454 | return 0; |
2395 | } | 2455 | } |
2396 | 2456 | ||
2397 | if (!mgmt_tx && (unsigned long)roc != cookie) | 2457 | if (!mgmt_tx && roc->cookie != cookie) |
2398 | continue; | 2458 | continue; |
2399 | else if (mgmt_tx && roc->mgmt_tx_cookie != cookie) | 2459 | else if (mgmt_tx && roc->mgmt_tx_cookie != cookie) |
2400 | continue; | 2460 | continue; |
@@ -3130,6 +3190,7 @@ struct cfg80211_ops mac80211_config_ops = { | |||
3130 | .disassoc = ieee80211_disassoc, | 3190 | .disassoc = ieee80211_disassoc, |
3131 | .join_ibss = ieee80211_join_ibss, | 3191 | .join_ibss = ieee80211_join_ibss, |
3132 | .leave_ibss = ieee80211_leave_ibss, | 3192 | .leave_ibss = ieee80211_leave_ibss, |
3193 | .set_mcast_rate = ieee80211_set_mcast_rate, | ||
3133 | .set_wiphy_params = ieee80211_set_wiphy_params, | 3194 | .set_wiphy_params = ieee80211_set_wiphy_params, |
3134 | .set_tx_power = ieee80211_set_tx_power, | 3195 | .set_tx_power = ieee80211_set_tx_power, |
3135 | .get_tx_power = ieee80211_get_tx_power, | 3196 | .get_tx_power = ieee80211_get_tx_power, |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index f84b86028a9..a2b06d40aeb 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -173,6 +173,8 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | |||
173 | rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); | 173 | rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); |
174 | ctx->refcount++; | 174 | ctx->refcount++; |
175 | 175 | ||
176 | ieee80211_recalc_txpower(sdata); | ||
177 | |||
176 | return 0; | 178 | return 0; |
177 | } | 179 | } |
178 | 180 | ||
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 3393ad5b8ab..ba9bd0ef119 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <linux/device.h> | 11 | #include <linux/device.h> |
12 | #include <linux/if.h> | 12 | #include <linux/if.h> |
13 | #include <linux/if_ether.h> | ||
13 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
14 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
15 | #include <linux/rtnetlink.h> | 16 | #include <linux/rtnetlink.h> |
@@ -168,6 +169,29 @@ IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz, | |||
168 | IEEE80211_IF_FILE(flags, flags, HEX); | 169 | IEEE80211_IF_FILE(flags, flags, HEX); |
169 | IEEE80211_IF_FILE(state, state, LHEX); | 170 | IEEE80211_IF_FILE(state, state, LHEX); |
170 | IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC); | 171 | IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC); |
172 | IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC); | ||
173 | IEEE80211_IF_FILE(ap_power_level, ap_power_level, DEC); | ||
174 | IEEE80211_IF_FILE(user_power_level, user_power_level, DEC); | ||
175 | |||
176 | static ssize_t | ||
177 | ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata, | ||
178 | char *buf, int buflen) | ||
179 | { | ||
180 | int len; | ||
181 | |||
182 | len = scnprintf(buf, buflen, "AC queues: VO:%d VI:%d BE:%d BK:%d\n", | ||
183 | sdata->vif.hw_queue[IEEE80211_AC_VO], | ||
184 | sdata->vif.hw_queue[IEEE80211_AC_VI], | ||
185 | sdata->vif.hw_queue[IEEE80211_AC_BE], | ||
186 | sdata->vif.hw_queue[IEEE80211_AC_BK]); | ||
187 | |||
188 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
189 | len += scnprintf(buf + len, buflen - len, "cab queue: %d\n", | ||
190 | sdata->vif.cab_queue); | ||
191 | |||
192 | return len; | ||
193 | } | ||
194 | __IEEE80211_IF_FILE(hw_queues, NULL); | ||
171 | 195 | ||
172 | /* STA attributes */ | 196 | /* STA attributes */ |
173 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); | 197 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); |
@@ -245,27 +269,6 @@ static ssize_t ieee80211_if_fmt_tkip_mic_test( | |||
245 | return -EOPNOTSUPP; | 269 | return -EOPNOTSUPP; |
246 | } | 270 | } |
247 | 271 | ||
248 | static int hwaddr_aton(const char *txt, u8 *addr) | ||
249 | { | ||
250 | int i; | ||
251 | |||
252 | for (i = 0; i < ETH_ALEN; i++) { | ||
253 | int a, b; | ||
254 | |||
255 | a = hex_to_bin(*txt++); | ||
256 | if (a < 0) | ||
257 | return -1; | ||
258 | b = hex_to_bin(*txt++); | ||
259 | if (b < 0) | ||
260 | return -1; | ||
261 | *addr++ = (a << 4) | b; | ||
262 | if (i < 5 && *txt++ != ':') | ||
263 | return -1; | ||
264 | } | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static ssize_t ieee80211_if_parse_tkip_mic_test( | 272 | static ssize_t ieee80211_if_parse_tkip_mic_test( |
270 | struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) | 273 | struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) |
271 | { | 274 | { |
@@ -275,13 +278,7 @@ static ssize_t ieee80211_if_parse_tkip_mic_test( | |||
275 | struct ieee80211_hdr *hdr; | 278 | struct ieee80211_hdr *hdr; |
276 | __le16 fc; | 279 | __le16 fc; |
277 | 280 | ||
278 | /* | 281 | if (!mac_pton(buf, addr)) |
279 | * Assume colon-delimited MAC address with possible white space | ||
280 | * following. | ||
281 | */ | ||
282 | if (buflen < 3 * ETH_ALEN - 1) | ||
283 | return -EINVAL; | ||
284 | if (hwaddr_aton(buf, addr) < 0) | ||
285 | return -EINVAL; | 282 | return -EINVAL; |
286 | 283 | ||
287 | if (!ieee80211_sdata_running(sdata)) | 284 | if (!ieee80211_sdata_running(sdata)) |
@@ -307,13 +304,16 @@ static ssize_t ieee80211_if_parse_tkip_mic_test( | |||
307 | case NL80211_IFTYPE_STATION: | 304 | case NL80211_IFTYPE_STATION: |
308 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | 305 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); |
309 | /* BSSID SA DA */ | 306 | /* BSSID SA DA */ |
310 | if (sdata->vif.bss_conf.bssid == NULL) { | 307 | mutex_lock(&sdata->u.mgd.mtx); |
308 | if (!sdata->u.mgd.associated) { | ||
309 | mutex_unlock(&sdata->u.mgd.mtx); | ||
311 | dev_kfree_skb(skb); | 310 | dev_kfree_skb(skb); |
312 | return -ENOTCONN; | 311 | return -ENOTCONN; |
313 | } | 312 | } |
314 | memcpy(hdr->addr1, sdata->vif.bss_conf.bssid, ETH_ALEN); | 313 | memcpy(hdr->addr1, sdata->u.mgd.associated->bssid, ETH_ALEN); |
315 | memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); | 314 | memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); |
316 | memcpy(hdr->addr3, addr, ETH_ALEN); | 315 | memcpy(hdr->addr3, addr, ETH_ALEN); |
316 | mutex_unlock(&sdata->u.mgd.mtx); | ||
317 | break; | 317 | break; |
318 | default: | 318 | default: |
319 | dev_kfree_skb(skb); | 319 | dev_kfree_skb(skb); |
@@ -443,7 +443,7 @@ static ssize_t ieee80211_if_parse_tsf( | |||
443 | } | 443 | } |
444 | ret = kstrtoull(buf, 10, &tsf); | 444 | ret = kstrtoull(buf, 10, &tsf); |
445 | if (ret < 0) | 445 | if (ret < 0) |
446 | return -EINVAL; | 446 | return ret; |
447 | if (tsf_is_delta) | 447 | if (tsf_is_delta) |
448 | tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf; | 448 | tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf; |
449 | if (local->ops->set_tsf) { | 449 | if (local->ops->set_tsf) { |
@@ -531,6 +531,7 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata) | |||
531 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); | 531 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
532 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); | 532 | DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz); |
533 | DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); | 533 | DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz); |
534 | DEBUGFS_ADD(hw_queues); | ||
534 | } | 535 | } |
535 | 536 | ||
536 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) | 537 | static void add_sta_files(struct ieee80211_sub_if_data *sdata) |
@@ -632,6 +633,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata) | |||
632 | DEBUGFS_ADD(flags); | 633 | DEBUGFS_ADD(flags); |
633 | DEBUGFS_ADD(state); | 634 | DEBUGFS_ADD(state); |
634 | DEBUGFS_ADD(channel_type); | 635 | DEBUGFS_ADD(channel_type); |
636 | DEBUGFS_ADD(txpower); | ||
637 | DEBUGFS_ADD(user_power_level); | ||
638 | DEBUGFS_ADD(ap_power_level); | ||
635 | 639 | ||
636 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | 640 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) |
637 | add_common_files(sdata); | 641 | add_common_files(sdata); |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 77407b31e1f..4dc2577886f 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -936,4 +936,39 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local, | |||
936 | trace_drv_return_void(local); | 936 | trace_drv_return_void(local); |
937 | } | 937 | } |
938 | 938 | ||
939 | static inline int drv_start_ap(struct ieee80211_local *local, | ||
940 | struct ieee80211_sub_if_data *sdata) | ||
941 | { | ||
942 | int ret = 0; | ||
943 | |||
944 | check_sdata_in_driver(sdata); | ||
945 | |||
946 | trace_drv_start_ap(local, sdata, &sdata->vif.bss_conf); | ||
947 | if (local->ops->start_ap) | ||
948 | ret = local->ops->start_ap(&local->hw, &sdata->vif); | ||
949 | trace_drv_return_int(local, ret); | ||
950 | return ret; | ||
951 | } | ||
952 | |||
953 | static inline void drv_stop_ap(struct ieee80211_local *local, | ||
954 | struct ieee80211_sub_if_data *sdata) | ||
955 | { | ||
956 | check_sdata_in_driver(sdata); | ||
957 | |||
958 | trace_drv_stop_ap(local, sdata); | ||
959 | if (local->ops->stop_ap) | ||
960 | local->ops->stop_ap(&local->hw, &sdata->vif); | ||
961 | trace_drv_return_void(local); | ||
962 | } | ||
963 | |||
964 | static inline void drv_restart_complete(struct ieee80211_local *local) | ||
965 | { | ||
966 | might_sleep(); | ||
967 | |||
968 | trace_drv_restart_complete(local); | ||
969 | if (local->ops->restart_complete) | ||
970 | local->ops->restart_complete(&local->hw); | ||
971 | trace_drv_return_void(local); | ||
972 | } | ||
973 | |||
939 | #endif /* __MAC80211_DRIVER_OPS */ | 974 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3026519b236..e1fb97cc9a4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -56,6 +56,9 @@ struct ieee80211_local; | |||
56 | #define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) | 56 | #define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) |
57 | #define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) | 57 | #define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) |
58 | 58 | ||
59 | /* power level hasn't been configured (or set to automatic) */ | ||
60 | #define IEEE80211_UNSET_POWER_LEVEL INT_MIN | ||
61 | |||
59 | /* | 62 | /* |
60 | * Some APs experience problems when working with U-APSD. Decrease the | 63 | * Some APs experience problems when working with U-APSD. Decrease the |
61 | * probability of that happening by using legacy mode for all ACs but VO. | 64 | * probability of that happening by using legacy mode for all ACs but VO. |
@@ -353,7 +356,7 @@ struct ieee80211_roc_work { | |||
353 | 356 | ||
354 | u32 duration, req_duration; | 357 | u32 duration, req_duration; |
355 | struct sk_buff *frame; | 358 | struct sk_buff *frame; |
356 | u64 mgmt_tx_cookie; | 359 | u64 cookie, mgmt_tx_cookie; |
357 | }; | 360 | }; |
358 | 361 | ||
359 | /* flags used in struct ieee80211_if_managed.flags */ | 362 | /* flags used in struct ieee80211_if_managed.flags */ |
@@ -470,6 +473,8 @@ struct ieee80211_if_managed { | |||
470 | 473 | ||
471 | u8 use_4addr; | 474 | u8 use_4addr; |
472 | 475 | ||
476 | u8 p2p_noa_index; | ||
477 | |||
473 | /* Signal strength from the last Beacon frame in the current BSS. */ | 478 | /* Signal strength from the last Beacon frame in the current BSS. */ |
474 | int last_beacon_signal; | 479 | int last_beacon_signal; |
475 | 480 | ||
@@ -743,6 +748,9 @@ struct ieee80211_sub_if_data { | |||
743 | u8 needed_rx_chains; | 748 | u8 needed_rx_chains; |
744 | enum ieee80211_smps_mode smps_mode; | 749 | enum ieee80211_smps_mode smps_mode; |
745 | 750 | ||
751 | int user_power_level; /* in dBm */ | ||
752 | int ap_power_level; /* in dBm */ | ||
753 | |||
746 | /* | 754 | /* |
747 | * AP this belongs to: self in AP mode and | 755 | * AP this belongs to: self in AP mode and |
748 | * corresponding AP in VLAN mode, NULL for | 756 | * corresponding AP in VLAN mode, NULL for |
@@ -1117,8 +1125,7 @@ struct ieee80211_local { | |||
1117 | int dynamic_ps_user_timeout; | 1125 | int dynamic_ps_user_timeout; |
1118 | bool disable_dynamic_ps; | 1126 | bool disable_dynamic_ps; |
1119 | 1127 | ||
1120 | int user_power_level; /* in dBm */ | 1128 | int user_power_level; /* in dBm, for all interfaces */ |
1121 | int ap_power_level; /* in dBm */ | ||
1122 | 1129 | ||
1123 | enum ieee80211_smps_mode smps_mode; | 1130 | enum ieee80211_smps_mode smps_mode; |
1124 | 1131 | ||
@@ -1137,6 +1144,7 @@ struct ieee80211_local { | |||
1137 | struct list_head roc_list; | 1144 | struct list_head roc_list; |
1138 | struct work_struct hw_roc_start, hw_roc_done; | 1145 | struct work_struct hw_roc_start, hw_roc_done; |
1139 | unsigned long hw_roc_start_time; | 1146 | unsigned long hw_roc_start_time; |
1147 | u64 roc_cookie_counter; | ||
1140 | 1148 | ||
1141 | struct idr ack_status_frames; | 1149 | struct idr ack_status_frames; |
1142 | spinlock_t ack_status_lock; | 1150 | spinlock_t ack_status_lock; |
@@ -1365,6 +1373,9 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, | |||
1365 | int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up); | 1373 | int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up); |
1366 | void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); | 1374 | void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); |
1367 | 1375 | ||
1376 | bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); | ||
1377 | void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); | ||
1378 | |||
1368 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) | 1379 | static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) |
1369 | { | 1380 | { |
1370 | return test_bit(SDATA_STATE_RUNNING, &sdata->state); | 1381 | return test_bit(SDATA_STATE_RUNNING, &sdata->state); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index bc3e3e1db09..80ce90b29d9 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -42,6 +42,41 @@ | |||
42 | * by either the RTNL, the iflist_mtx or RCU. | 42 | * by either the RTNL, the iflist_mtx or RCU. |
43 | */ | 43 | */ |
44 | 44 | ||
45 | bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) | ||
46 | { | ||
47 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
48 | int power; | ||
49 | |||
50 | rcu_read_lock(); | ||
51 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
52 | if (!chanctx_conf) { | ||
53 | rcu_read_unlock(); | ||
54 | return false; | ||
55 | } | ||
56 | |||
57 | power = chanctx_conf->channel->max_power; | ||
58 | rcu_read_unlock(); | ||
59 | |||
60 | if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL) | ||
61 | power = min(power, sdata->user_power_level); | ||
62 | |||
63 | if (sdata->ap_power_level != IEEE80211_UNSET_POWER_LEVEL) | ||
64 | power = min(power, sdata->ap_power_level); | ||
65 | |||
66 | if (power != sdata->vif.bss_conf.txpower) { | ||
67 | sdata->vif.bss_conf.txpower = power; | ||
68 | ieee80211_hw_config(sdata->local, 0); | ||
69 | return true; | ||
70 | } | ||
71 | |||
72 | return false; | ||
73 | } | ||
74 | |||
75 | void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) | ||
76 | { | ||
77 | if (__ieee80211_recalc_txpower(sdata)) | ||
78 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER); | ||
79 | } | ||
45 | 80 | ||
46 | static u32 ieee80211_idle_off(struct ieee80211_local *local, | 81 | static u32 ieee80211_idle_off(struct ieee80211_local *local, |
47 | const char *reason) | 82 | const char *reason) |
@@ -744,31 +779,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
744 | /* APs need special treatment */ | 779 | /* APs need special treatment */ |
745 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 780 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
746 | struct ieee80211_sub_if_data *vlan, *tmpsdata; | 781 | struct ieee80211_sub_if_data *vlan, *tmpsdata; |
747 | struct beacon_data *old_beacon = | ||
748 | rtnl_dereference(sdata->u.ap.beacon); | ||
749 | struct probe_resp *old_probe_resp = | ||
750 | rtnl_dereference(sdata->u.ap.probe_resp); | ||
751 | |||
752 | /* sdata_running will return false, so this will disable */ | ||
753 | ieee80211_bss_info_change_notify(sdata, | ||
754 | BSS_CHANGED_BEACON_ENABLED); | ||
755 | |||
756 | /* remove beacon and probe response */ | ||
757 | RCU_INIT_POINTER(sdata->u.ap.beacon, NULL); | ||
758 | RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL); | ||
759 | synchronize_rcu(); | ||
760 | kfree(old_beacon); | ||
761 | kfree(old_probe_resp); | ||
762 | 782 | ||
763 | /* down all dependent devices, that is VLANs */ | 783 | /* down all dependent devices, that is VLANs */ |
764 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, | 784 | list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, |
765 | u.vlan.list) | 785 | u.vlan.list) |
766 | dev_close(vlan->dev); | 786 | dev_close(vlan->dev); |
767 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); | 787 | WARN_ON(!list_empty(&sdata->u.ap.vlans)); |
768 | |||
769 | /* free all potentially still buffered bcast frames */ | ||
770 | local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); | ||
771 | skb_queue_purge(&sdata->u.ap.ps.bc_buf); | ||
772 | } else if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 788 | } else if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
773 | ieee80211_mgd_stop(sdata); | 789 | ieee80211_mgd_stop(sdata); |
774 | } | 790 | } |
@@ -1529,6 +1545,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1529 | 1545 | ||
1530 | ieee80211_set_default_queues(sdata); | 1546 | ieee80211_set_default_queues(sdata); |
1531 | 1547 | ||
1548 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; | ||
1549 | sdata->user_power_level = local->user_power_level; | ||
1550 | |||
1532 | /* setup type-dependent data */ | 1551 | /* setup type-dependent data */ |
1533 | ieee80211_setup_sdata(sdata, type); | 1552 | ieee80211_setup_sdata(sdata, type); |
1534 | 1553 | ||
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index fd8345c2005..70e87600cac 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -95,11 +95,13 @@ static void ieee80211_reconfig_filter(struct work_struct *work) | |||
95 | 95 | ||
96 | static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) | 96 | static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) |
97 | { | 97 | { |
98 | struct ieee80211_sub_if_data *sdata; | ||
98 | struct ieee80211_channel *chan; | 99 | struct ieee80211_channel *chan; |
99 | u32 changed = 0; | 100 | u32 changed = 0; |
100 | int power; | 101 | int power; |
101 | enum nl80211_channel_type channel_type; | 102 | enum nl80211_channel_type channel_type; |
102 | u32 offchannel_flag; | 103 | u32 offchannel_flag; |
104 | bool scanning = false; | ||
103 | 105 | ||
104 | offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; | 106 | offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; |
105 | if (local->scan_channel) { | 107 | if (local->scan_channel) { |
@@ -146,16 +148,18 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) | |||
146 | changed |= IEEE80211_CONF_CHANGE_SMPS; | 148 | changed |= IEEE80211_CONF_CHANGE_SMPS; |
147 | } | 149 | } |
148 | 150 | ||
149 | if (test_bit(SCAN_SW_SCANNING, &local->scanning) || | 151 | scanning = test_bit(SCAN_SW_SCANNING, &local->scanning) || |
150 | test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || | 152 | test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || |
151 | test_bit(SCAN_HW_SCANNING, &local->scanning) || | 153 | test_bit(SCAN_HW_SCANNING, &local->scanning); |
152 | !local->ap_power_level) | 154 | power = chan->max_power; |
153 | power = chan->max_power; | ||
154 | else | ||
155 | power = min(chan->max_power, local->ap_power_level); | ||
156 | 155 | ||
157 | if (local->user_power_level >= 0) | 156 | rcu_read_lock(); |
158 | power = min(power, local->user_power_level); | 157 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
158 | if (!rcu_access_pointer(sdata->vif.chanctx_conf)) | ||
159 | continue; | ||
160 | power = min(power, sdata->vif.bss_conf.txpower); | ||
161 | } | ||
162 | rcu_read_unlock(); | ||
159 | 163 | ||
160 | if (local->hw.conf.power_level != power) { | 164 | if (local->hw.conf.power_level != power) { |
161 | changed |= IEEE80211_CONF_CHANGE_POWER; | 165 | changed |= IEEE80211_CONF_CHANGE_POWER; |
@@ -600,7 +604,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
600 | 604 | ||
601 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | | 605 | wiphy->features |= NL80211_FEATURE_SK_TX_STATUS | |
602 | NL80211_FEATURE_SAE | | 606 | NL80211_FEATURE_SAE | |
603 | NL80211_FEATURE_HT_IBSS; | 607 | NL80211_FEATURE_HT_IBSS | |
608 | NL80211_FEATURE_VIF_TXPOWER; | ||
604 | 609 | ||
605 | if (!ops->hw_scan) | 610 | if (!ops->hw_scan) |
606 | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | | 611 | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | |
@@ -633,7 +638,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
633 | local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS | | 638 | local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS | |
634 | IEEE80211_RADIOTAP_MCS_HAVE_GI | | 639 | IEEE80211_RADIOTAP_MCS_HAVE_GI | |
635 | IEEE80211_RADIOTAP_MCS_HAVE_BW; | 640 | IEEE80211_RADIOTAP_MCS_HAVE_BW; |
636 | local->user_power_level = -1; | 641 | local->user_power_level = IEEE80211_UNSET_POWER_LEVEL; |
637 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; | 642 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; |
638 | 643 | ||
639 | INIT_LIST_HEAD(&local->interfaces); | 644 | INIT_LIST_HEAD(&local->interfaces); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1d1fdf0791f..61614461e08 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -820,10 +820,10 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
820 | cbss->beacon_interval)); | 820 | cbss->beacon_interval)); |
821 | } | 821 | } |
822 | 822 | ||
823 | static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | 823 | static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, |
824 | struct ieee80211_channel *channel, | 824 | struct ieee80211_channel *channel, |
825 | const u8 *country_ie, u8 country_ie_len, | 825 | const u8 *country_ie, u8 country_ie_len, |
826 | const u8 *pwr_constr_elem) | 826 | const u8 *pwr_constr_elem) |
827 | { | 827 | { |
828 | struct ieee80211_country_ie_triplet *triplet; | 828 | struct ieee80211_country_ie_triplet *triplet; |
829 | int chan = ieee80211_frequency_to_channel(channel->center_freq); | 829 | int chan = ieee80211_frequency_to_channel(channel->center_freq); |
@@ -832,7 +832,7 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | |||
832 | 832 | ||
833 | /* Invalid IE */ | 833 | /* Invalid IE */ |
834 | if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) | 834 | if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) |
835 | return; | 835 | return 0; |
836 | 836 | ||
837 | triplet = (void *)(country_ie + 3); | 837 | triplet = (void *)(country_ie + 3); |
838 | country_ie_len -= 3; | 838 | country_ie_len -= 3; |
@@ -873,19 +873,21 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | |||
873 | } | 873 | } |
874 | 874 | ||
875 | if (!have_chan_pwr) | 875 | if (!have_chan_pwr) |
876 | return; | 876 | return 0; |
877 | 877 | ||
878 | new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem); | 878 | new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem); |
879 | 879 | ||
880 | if (sdata->local->ap_power_level == new_ap_level) | 880 | if (sdata->ap_power_level == new_ap_level) |
881 | return; | 881 | return 0; |
882 | 882 | ||
883 | sdata_info(sdata, | 883 | sdata_info(sdata, |
884 | "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", | 884 | "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", |
885 | new_ap_level, chan_pwr, *pwr_constr_elem, | 885 | new_ap_level, chan_pwr, *pwr_constr_elem, |
886 | sdata->u.mgd.bssid); | 886 | sdata->u.mgd.bssid); |
887 | sdata->local->ap_power_level = new_ap_level; | 887 | sdata->ap_power_level = new_ap_level; |
888 | ieee80211_hw_config(sdata->local, 0); | 888 | if (__ieee80211_recalc_txpower(sdata)) |
889 | return BSS_CHANGED_TXPOWER; | ||
890 | return 0; | ||
889 | } | 891 | } |
890 | 892 | ||
891 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) | 893 | void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif) |
@@ -1363,6 +1365,22 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
1363 | 1365 | ||
1364 | sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE; | 1366 | sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE; |
1365 | 1367 | ||
1368 | if (sdata->vif.p2p) { | ||
1369 | u8 noa[2]; | ||
1370 | int ret; | ||
1371 | |||
1372 | ret = cfg80211_get_p2p_attr(cbss->information_elements, | ||
1373 | cbss->len_information_elements, | ||
1374 | IEEE80211_P2P_ATTR_ABSENCE_NOTICE, | ||
1375 | noa, sizeof(noa)); | ||
1376 | if (ret >= 2) { | ||
1377 | bss_conf->p2p_oppps = noa[1] & 0x80; | ||
1378 | bss_conf->p2p_ctwindow = noa[1] & 0x7f; | ||
1379 | bss_info_changed |= BSS_CHANGED_P2P_PS; | ||
1380 | sdata->u.mgd.p2p_noa_index = noa[0]; | ||
1381 | } | ||
1382 | } | ||
1383 | |||
1366 | /* just to be sure */ | 1384 | /* just to be sure */ |
1367 | ieee80211_stop_poll(sdata); | 1385 | ieee80211_stop_poll(sdata); |
1368 | 1386 | ||
@@ -1485,11 +1503,14 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1485 | changed |= BSS_CHANGED_ASSOC; | 1503 | changed |= BSS_CHANGED_ASSOC; |
1486 | sdata->vif.bss_conf.assoc = false; | 1504 | sdata->vif.bss_conf.assoc = false; |
1487 | 1505 | ||
1506 | sdata->vif.bss_conf.p2p_ctwindow = 0; | ||
1507 | sdata->vif.bss_conf.p2p_oppps = false; | ||
1508 | |||
1488 | /* on the next assoc, re-program HT parameters */ | 1509 | /* on the next assoc, re-program HT parameters */ |
1489 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); | 1510 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); |
1490 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); | 1511 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); |
1491 | 1512 | ||
1492 | local->ap_power_level = 0; | 1513 | sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; |
1493 | 1514 | ||
1494 | del_timer_sync(&local->dynamic_ps_timer); | 1515 | del_timer_sync(&local->dynamic_ps_timer); |
1495 | cancel_work_sync(&local->dynamic_ps_enable_work); | 1516 | cancel_work_sync(&local->dynamic_ps_enable_work); |
@@ -2592,6 +2613,27 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2592 | } | 2613 | } |
2593 | } | 2614 | } |
2594 | 2615 | ||
2616 | if (sdata->vif.p2p) { | ||
2617 | u8 noa[2]; | ||
2618 | int ret; | ||
2619 | |||
2620 | ret = cfg80211_get_p2p_attr(mgmt->u.beacon.variable, | ||
2621 | len - baselen, | ||
2622 | IEEE80211_P2P_ATTR_ABSENCE_NOTICE, | ||
2623 | noa, sizeof(noa)); | ||
2624 | if (ret >= 2 && sdata->u.mgd.p2p_noa_index != noa[0]) { | ||
2625 | bss_conf->p2p_oppps = noa[1] & 0x80; | ||
2626 | bss_conf->p2p_ctwindow = noa[1] & 0x7f; | ||
2627 | changed |= BSS_CHANGED_P2P_PS; | ||
2628 | sdata->u.mgd.p2p_noa_index = noa[0]; | ||
2629 | /* | ||
2630 | * make sure we update all information, the CRC | ||
2631 | * mechanism doesn't look at P2P attributes. | ||
2632 | */ | ||
2633 | ifmgd->beacon_crc_valid = false; | ||
2634 | } | ||
2635 | } | ||
2636 | |||
2595 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) | 2637 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) |
2596 | return; | 2638 | return; |
2597 | ifmgd->beacon_crc = ncrc; | 2639 | ifmgd->beacon_crc = ncrc; |
@@ -2623,10 +2665,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2623 | if (elems.country_elem && elems.pwr_constr_elem && | 2665 | if (elems.country_elem && elems.pwr_constr_elem && |
2624 | mgmt->u.probe_resp.capab_info & | 2666 | mgmt->u.probe_resp.capab_info & |
2625 | cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) | 2667 | cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) |
2626 | ieee80211_handle_pwr_constr(sdata, chan, | 2668 | changed |= ieee80211_handle_pwr_constr(sdata, chan, |
2627 | elems.country_elem, | 2669 | elems.country_elem, |
2628 | elems.country_elem_len, | 2670 | elems.country_elem_len, |
2629 | elems.pwr_constr_elem); | 2671 | elems.pwr_constr_elem); |
2630 | 2672 | ||
2631 | ieee80211_bss_info_change_notify(sdata, changed); | 2673 | ieee80211_bss_info_change_notify(sdata, changed); |
2632 | } | 2674 | } |
@@ -3660,40 +3702,44 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
3660 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3702 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3661 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | 3703 | u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; |
3662 | bool tx = !req->local_state_change; | 3704 | bool tx = !req->local_state_change; |
3705 | bool sent_frame = false; | ||
3663 | 3706 | ||
3664 | mutex_lock(&ifmgd->mtx); | 3707 | mutex_lock(&ifmgd->mtx); |
3665 | 3708 | ||
3666 | if (ifmgd->auth_data) { | ||
3667 | ieee80211_destroy_auth_data(sdata, false); | ||
3668 | mutex_unlock(&ifmgd->mtx); | ||
3669 | return 0; | ||
3670 | } | ||
3671 | |||
3672 | sdata_info(sdata, | 3709 | sdata_info(sdata, |
3673 | "deauthenticating from %pM by local choice (reason=%d)\n", | 3710 | "deauthenticating from %pM by local choice (reason=%d)\n", |
3674 | req->bssid, req->reason_code); | 3711 | req->bssid, req->reason_code); |
3675 | 3712 | ||
3676 | if (ifmgd->associated && | 3713 | if (ifmgd->auth_data) { |
3677 | ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { | ||
3678 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | ||
3679 | req->reason_code, tx, frame_buf); | ||
3680 | } else { | ||
3681 | drv_mgd_prepare_tx(sdata->local, sdata); | 3714 | drv_mgd_prepare_tx(sdata->local, sdata); |
3682 | ieee80211_send_deauth_disassoc(sdata, req->bssid, | 3715 | ieee80211_send_deauth_disassoc(sdata, req->bssid, |
3683 | IEEE80211_STYPE_DEAUTH, | 3716 | IEEE80211_STYPE_DEAUTH, |
3684 | req->reason_code, tx, | 3717 | req->reason_code, tx, |
3685 | frame_buf); | 3718 | frame_buf); |
3719 | ieee80211_destroy_auth_data(sdata, false); | ||
3720 | mutex_unlock(&ifmgd->mtx); | ||
3721 | |||
3722 | sent_frame = tx; | ||
3723 | goto out; | ||
3686 | } | 3724 | } |
3687 | 3725 | ||
3726 | if (ifmgd->associated && | ||
3727 | ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { | ||
3728 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | ||
3729 | req->reason_code, tx, frame_buf); | ||
3730 | sent_frame = tx; | ||
3731 | } | ||
3688 | mutex_unlock(&ifmgd->mtx); | 3732 | mutex_unlock(&ifmgd->mtx); |
3689 | 3733 | ||
3690 | __cfg80211_send_deauth(sdata->dev, frame_buf, | 3734 | out: |
3691 | IEEE80211_DEAUTH_FRAME_LEN); | ||
3692 | |||
3693 | mutex_lock(&sdata->local->mtx); | 3735 | mutex_lock(&sdata->local->mtx); |
3694 | ieee80211_recalc_idle(sdata->local); | 3736 | ieee80211_recalc_idle(sdata->local); |
3695 | mutex_unlock(&sdata->local->mtx); | 3737 | mutex_unlock(&sdata->local->mtx); |
3696 | 3738 | ||
3739 | if (sent_frame) | ||
3740 | __cfg80211_send_deauth(sdata->dev, frame_buf, | ||
3741 | IEEE80211_DEAUTH_FRAME_LEN); | ||
3742 | |||
3697 | return 0; | 3743 | return 0; |
3698 | } | 3744 | } |
3699 | 3745 | ||
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index c349f3aaf59..0cd42d52880 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -204,7 +204,7 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) | |||
204 | roc->frame = NULL; | 204 | roc->frame = NULL; |
205 | } | 205 | } |
206 | } else { | 206 | } else { |
207 | cfg80211_ready_on_channel(&roc->sdata->wdev, (unsigned long)roc, | 207 | cfg80211_ready_on_channel(&roc->sdata->wdev, roc->cookie, |
208 | roc->chan, roc->chan_type, | 208 | roc->chan, roc->chan_type, |
209 | roc->req_duration, GFP_KERNEL); | 209 | roc->req_duration, GFP_KERNEL); |
210 | } | 210 | } |
@@ -320,9 +320,8 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) | |||
320 | 320 | ||
321 | if (!roc->mgmt_tx_cookie) | 321 | if (!roc->mgmt_tx_cookie) |
322 | cfg80211_remain_on_channel_expired(&roc->sdata->wdev, | 322 | cfg80211_remain_on_channel_expired(&roc->sdata->wdev, |
323 | (unsigned long)roc, | 323 | roc->cookie, roc->chan, |
324 | roc->chan, roc->chan_type, | 324 | roc->chan_type, GFP_KERNEL); |
325 | GFP_KERNEL); | ||
326 | 325 | ||
327 | list_for_each_entry_safe(dep, tmp, &roc->dependents, list) | 326 | list_for_each_entry_safe(dep, tmp, &roc->dependents, list) |
328 | ieee80211_roc_notify_destroy(dep); | 327 | ieee80211_roc_notify_destroy(dep); |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 9f404ac901a..0f1c434638b 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -135,6 +135,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
135 | ieee80211_bss_info_change_notify(sdata, | 135 | ieee80211_bss_info_change_notify(sdata, |
136 | BSS_CHANGED_BEACON_ENABLED); | 136 | BSS_CHANGED_BEACON_ENABLED); |
137 | 137 | ||
138 | if (sdata->vif.type == NL80211_IFTYPE_AP && | ||
139 | rcu_access_pointer(sdata->u.ap.beacon)) | ||
140 | drv_stop_ap(local, sdata); | ||
141 | |||
138 | /* the interface is leaving the channel and is removed */ | 142 | /* the interface is leaving the channel and is removed */ |
139 | ieee80211_vif_release_channel(sdata); | 143 | ieee80211_vif_release_channel(sdata); |
140 | drv_remove_interface(local, sdata); | 144 | drv_remove_interface(local, sdata); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8c1f1527d67..6ad330341b7 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -54,8 +54,7 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | |||
54 | return skb; | 54 | return skb; |
55 | } | 55 | } |
56 | 56 | ||
57 | static inline int should_drop_frame(struct sk_buff *skb, | 57 | static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len) |
58 | int present_fcs_len) | ||
59 | { | 58 | { |
60 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 59 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
61 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 60 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
@@ -130,15 +129,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
130 | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); | 129 | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); |
131 | rthdr->it_len = cpu_to_le16(rtap_len); | 130 | rthdr->it_len = cpu_to_le16(rtap_len); |
132 | 131 | ||
133 | pos = (unsigned char *)(rthdr+1); | 132 | pos = (unsigned char *)(rthdr + 1); |
134 | 133 | ||
135 | /* the order of the following fields is important */ | 134 | /* the order of the following fields is important */ |
136 | 135 | ||
137 | /* IEEE80211_RADIOTAP_TSFT */ | 136 | /* IEEE80211_RADIOTAP_TSFT */ |
138 | if (status->flag & RX_FLAG_MACTIME_MPDU) { | 137 | if (status->flag & RX_FLAG_MACTIME_MPDU) { |
139 | put_unaligned_le64(status->mactime, pos); | 138 | put_unaligned_le64(status->mactime, pos); |
140 | rthdr->it_present |= | 139 | rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); |
141 | cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); | ||
142 | pos += 8; | 140 | pos += 8; |
143 | } | 141 | } |
144 | 142 | ||
@@ -374,7 +372,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
374 | return origskb; | 372 | return origskb; |
375 | } | 373 | } |
376 | 374 | ||
377 | |||
378 | static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) | 375 | static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) |
379 | { | 376 | { |
380 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 377 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
@@ -481,8 +478,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
481 | struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; | 478 | struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data; |
482 | struct ieee80211_mmie *mmie; | 479 | struct ieee80211_mmie *mmie; |
483 | 480 | ||
484 | if (skb->len < 24 + sizeof(*mmie) || | 481 | if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da)) |
485 | !is_multicast_ether_addr(hdr->da)) | ||
486 | return -1; | 482 | return -1; |
487 | 483 | ||
488 | if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr)) | 484 | if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr)) |
@@ -497,9 +493,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
497 | return le16_to_cpu(mmie->key_id); | 493 | return le16_to_cpu(mmie->key_id); |
498 | } | 494 | } |
499 | 495 | ||
500 | 496 | static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |
501 | static ieee80211_rx_result | ||
502 | ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | ||
503 | { | 497 | { |
504 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 498 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
505 | char *dev_addr = rx->sdata->vif.addr; | 499 | char *dev_addr = rx->sdata->vif.addr; |
@@ -507,7 +501,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
507 | if (ieee80211_is_data(hdr->frame_control)) { | 501 | if (ieee80211_is_data(hdr->frame_control)) { |
508 | if (is_multicast_ether_addr(hdr->addr1)) { | 502 | if (is_multicast_ether_addr(hdr->addr1)) { |
509 | if (ieee80211_has_tods(hdr->frame_control) || | 503 | if (ieee80211_has_tods(hdr->frame_control) || |
510 | !ieee80211_has_fromds(hdr->frame_control)) | 504 | !ieee80211_has_fromds(hdr->frame_control)) |
511 | return RX_DROP_MONITOR; | 505 | return RX_DROP_MONITOR; |
512 | if (ether_addr_equal(hdr->addr3, dev_addr)) | 506 | if (ether_addr_equal(hdr->addr3, dev_addr)) |
513 | return RX_DROP_MONITOR; | 507 | return RX_DROP_MONITOR; |
@@ -539,7 +533,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
539 | mgmt = (struct ieee80211_mgmt *)hdr; | 533 | mgmt = (struct ieee80211_mgmt *)hdr; |
540 | category = mgmt->u.action.category; | 534 | category = mgmt->u.action.category; |
541 | if (category != WLAN_CATEGORY_MESH_ACTION && | 535 | if (category != WLAN_CATEGORY_MESH_ACTION && |
542 | category != WLAN_CATEGORY_SELF_PROTECTED) | 536 | category != WLAN_CATEGORY_SELF_PROTECTED) |
543 | return RX_DROP_MONITOR; | 537 | return RX_DROP_MONITOR; |
544 | return RX_CONTINUE; | 538 | return RX_CONTINUE; |
545 | } | 539 | } |
@@ -551,7 +545,6 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
551 | return RX_CONTINUE; | 545 | return RX_CONTINUE; |
552 | 546 | ||
553 | return RX_DROP_MONITOR; | 547 | return RX_DROP_MONITOR; |
554 | |||
555 | } | 548 | } |
556 | 549 | ||
557 | return RX_CONTINUE; | 550 | return RX_CONTINUE; |
@@ -575,7 +568,6 @@ static inline u16 seq_sub(u16 sq1, u16 sq2) | |||
575 | return (sq1 - sq2) & SEQ_MASK; | 568 | return (sq1 - sq2) & SEQ_MASK; |
576 | } | 569 | } |
577 | 570 | ||
578 | |||
579 | static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, | 571 | static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, |
580 | struct tid_ampdu_rx *tid_agg_rx, | 572 | struct tid_ampdu_rx *tid_agg_rx, |
581 | int index) | 573 | int index) |
@@ -1585,18 +1577,15 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1585 | return RX_CONTINUE; | 1577 | return RX_CONTINUE; |
1586 | } | 1578 | } |
1587 | 1579 | ||
1588 | static int | 1580 | static int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) |
1589 | ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) | ||
1590 | { | 1581 | { |
1591 | if (unlikely(!rx->sta || | 1582 | if (unlikely(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED))) |
1592 | !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED))) | ||
1593 | return -EACCES; | 1583 | return -EACCES; |
1594 | 1584 | ||
1595 | return 0; | 1585 | return 0; |
1596 | } | 1586 | } |
1597 | 1587 | ||
1598 | static int | 1588 | static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) |
1599 | ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) | ||
1600 | { | 1589 | { |
1601 | struct sk_buff *skb = rx->skb; | 1590 | struct sk_buff *skb = rx->skb; |
1602 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 1591 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
@@ -1618,8 +1607,7 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) | |||
1618 | return 0; | 1607 | return 0; |
1619 | } | 1608 | } |
1620 | 1609 | ||
1621 | static int | 1610 | static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) |
1622 | ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) | ||
1623 | { | 1611 | { |
1624 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1612 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
1625 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | 1613 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
@@ -2003,7 +1991,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
2003 | } else { | 1991 | } else { |
2004 | /* unable to resolve next hop */ | 1992 | /* unable to resolve next hop */ |
2005 | mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3, | 1993 | mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3, |
2006 | 0, reason, fwd_hdr->addr2, sdata); | 1994 | 0, reason, fwd_hdr->addr2, sdata); |
2007 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route); | 1995 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route); |
2008 | kfree_skb(fwd_skb); | 1996 | kfree_skb(fwd_skb); |
2009 | return RX_DROP_MONITOR; | 1997 | return RX_DROP_MONITOR; |
@@ -2212,7 +2200,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) | |||
2212 | 2200 | ||
2213 | cfg80211_report_obss_beacon(rx->local->hw.wiphy, | 2201 | cfg80211_report_obss_beacon(rx->local->hw.wiphy, |
2214 | rx->skb->data, rx->skb->len, | 2202 | rx->skb->data, rx->skb->len, |
2215 | status->freq, sig, GFP_ATOMIC); | 2203 | status->freq, sig); |
2216 | rx->flags |= IEEE80211_RX_BEACON_REPORTED; | 2204 | rx->flags |= IEEE80211_RX_BEACON_REPORTED; |
2217 | } | 2205 | } |
2218 | 2206 | ||
@@ -2412,7 +2400,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2412 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | 2400 | if (!ieee80211_vif_is_mesh(&sdata->vif)) |
2413 | break; | 2401 | break; |
2414 | if (mesh_action_is_path_sel(mgmt) && | 2402 | if (mesh_action_is_path_sel(mgmt) && |
2415 | (!mesh_path_sel_is_hwmp(sdata))) | 2403 | !mesh_path_sel_is_hwmp(sdata)) |
2416 | break; | 2404 | break; |
2417 | goto queue; | 2405 | goto queue; |
2418 | } | 2406 | } |
@@ -2468,7 +2456,6 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) | |||
2468 | return RX_QUEUED; | 2456 | return RX_QUEUED; |
2469 | } | 2457 | } |
2470 | 2458 | ||
2471 | |||
2472 | return RX_CONTINUE; | 2459 | return RX_CONTINUE; |
2473 | } | 2460 | } |
2474 | 2461 | ||
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 21fa5c72ea1..2d931ad0e90 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -325,6 +325,75 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band | |||
325 | 325 | ||
326 | } | 326 | } |
327 | 327 | ||
328 | static void ieee80211_report_used_skb(struct ieee80211_local *local, | ||
329 | struct sk_buff *skb, bool dropped) | ||
330 | { | ||
331 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
332 | struct ieee80211_hdr *hdr = (void *)skb->data; | ||
333 | bool acked = info->flags & IEEE80211_TX_STAT_ACK; | ||
334 | |||
335 | if (dropped) | ||
336 | acked = false; | ||
337 | |||
338 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { | ||
339 | struct ieee80211_sub_if_data *sdata = NULL; | ||
340 | struct ieee80211_sub_if_data *iter_sdata; | ||
341 | u64 cookie = (unsigned long)skb; | ||
342 | |||
343 | rcu_read_lock(); | ||
344 | |||
345 | if (skb->dev) { | ||
346 | list_for_each_entry_rcu(iter_sdata, &local->interfaces, | ||
347 | list) { | ||
348 | if (!iter_sdata->dev) | ||
349 | continue; | ||
350 | |||
351 | if (skb->dev == iter_sdata->dev) { | ||
352 | sdata = iter_sdata; | ||
353 | break; | ||
354 | } | ||
355 | } | ||
356 | } else { | ||
357 | sdata = rcu_dereference(local->p2p_sdata); | ||
358 | } | ||
359 | |||
360 | if (!sdata) | ||
361 | skb->dev = NULL; | ||
362 | else if (ieee80211_is_nullfunc(hdr->frame_control) || | ||
363 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | ||
364 | cfg80211_probe_status(sdata->dev, hdr->addr1, | ||
365 | cookie, acked, GFP_ATOMIC); | ||
366 | } else { | ||
367 | cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data, | ||
368 | skb->len, acked, GFP_ATOMIC); | ||
369 | } | ||
370 | |||
371 | rcu_read_unlock(); | ||
372 | } | ||
373 | |||
374 | if (unlikely(info->ack_frame_id)) { | ||
375 | struct sk_buff *ack_skb; | ||
376 | unsigned long flags; | ||
377 | |||
378 | spin_lock_irqsave(&local->ack_status_lock, flags); | ||
379 | ack_skb = idr_find(&local->ack_status_frames, | ||
380 | info->ack_frame_id); | ||
381 | if (ack_skb) | ||
382 | idr_remove(&local->ack_status_frames, | ||
383 | info->ack_frame_id); | ||
384 | spin_unlock_irqrestore(&local->ack_status_lock, flags); | ||
385 | |||
386 | if (ack_skb) { | ||
387 | if (!dropped) { | ||
388 | /* consumes ack_skb */ | ||
389 | skb_complete_wifi_ack(ack_skb, acked); | ||
390 | } else { | ||
391 | dev_kfree_skb_any(ack_skb); | ||
392 | } | ||
393 | } | ||
394 | } | ||
395 | } | ||
396 | |||
328 | /* | 397 | /* |
329 | * Use a static threshold for now, best value to be determined | 398 | * Use a static threshold for now, best value to be determined |
330 | * by testing ... | 399 | * by testing ... |
@@ -516,62 +585,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
516 | msecs_to_jiffies(10)); | 585 | msecs_to_jiffies(10)); |
517 | } | 586 | } |
518 | 587 | ||
519 | if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) { | 588 | ieee80211_report_used_skb(local, skb, false); |
520 | u64 cookie = (unsigned long)skb; | ||
521 | bool found = false; | ||
522 | |||
523 | acked = info->flags & IEEE80211_TX_STAT_ACK; | ||
524 | |||
525 | rcu_read_lock(); | ||
526 | |||
527 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
528 | if (!sdata->dev) | ||
529 | continue; | ||
530 | |||
531 | if (skb->dev != sdata->dev) | ||
532 | continue; | ||
533 | |||
534 | found = true; | ||
535 | break; | ||
536 | } | ||
537 | |||
538 | if (!skb->dev) { | ||
539 | sdata = rcu_dereference(local->p2p_sdata); | ||
540 | if (sdata) | ||
541 | found = true; | ||
542 | } | ||
543 | |||
544 | if (!found) | ||
545 | skb->dev = NULL; | ||
546 | else if (ieee80211_is_nullfunc(hdr->frame_control) || | ||
547 | ieee80211_is_qos_nullfunc(hdr->frame_control)) { | ||
548 | cfg80211_probe_status(sdata->dev, hdr->addr1, | ||
549 | cookie, acked, GFP_ATOMIC); | ||
550 | } else { | ||
551 | cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data, | ||
552 | skb->len, acked, GFP_ATOMIC); | ||
553 | } | ||
554 | |||
555 | rcu_read_unlock(); | ||
556 | } | ||
557 | |||
558 | if (unlikely(info->ack_frame_id)) { | ||
559 | struct sk_buff *ack_skb; | ||
560 | unsigned long flags; | ||
561 | |||
562 | spin_lock_irqsave(&local->ack_status_lock, flags); | ||
563 | ack_skb = idr_find(&local->ack_status_frames, | ||
564 | info->ack_frame_id); | ||
565 | if (ack_skb) | ||
566 | idr_remove(&local->ack_status_frames, | ||
567 | info->ack_frame_id); | ||
568 | spin_unlock_irqrestore(&local->ack_status_lock, flags); | ||
569 | |||
570 | /* consumes ack_skb */ | ||
571 | if (ack_skb) | ||
572 | skb_complete_wifi_ack(ack_skb, | ||
573 | info->flags & IEEE80211_TX_STAT_ACK); | ||
574 | } | ||
575 | 589 | ||
576 | /* this was a transmitted frame, but now we want to reuse it */ | 590 | /* this was a transmitted frame, but now we want to reuse it */ |
577 | skb_orphan(skb); | 591 | skb_orphan(skb); |
@@ -647,25 +661,8 @@ EXPORT_SYMBOL(ieee80211_report_low_ack); | |||
647 | void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) | 661 | void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb) |
648 | { | 662 | { |
649 | struct ieee80211_local *local = hw_to_local(hw); | 663 | struct ieee80211_local *local = hw_to_local(hw); |
650 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
651 | |||
652 | if (unlikely(info->ack_frame_id)) { | ||
653 | struct sk_buff *ack_skb; | ||
654 | unsigned long flags; | ||
655 | |||
656 | spin_lock_irqsave(&local->ack_status_lock, flags); | ||
657 | ack_skb = idr_find(&local->ack_status_frames, | ||
658 | info->ack_frame_id); | ||
659 | if (ack_skb) | ||
660 | idr_remove(&local->ack_status_frames, | ||
661 | info->ack_frame_id); | ||
662 | spin_unlock_irqrestore(&local->ack_status_lock, flags); | ||
663 | |||
664 | /* consumes ack_skb */ | ||
665 | if (ack_skb) | ||
666 | dev_kfree_skb_any(ack_skb); | ||
667 | } | ||
668 | 664 | ||
665 | ieee80211_report_used_skb(local, skb, true); | ||
669 | dev_kfree_skb_any(skb); | 666 | dev_kfree_skb_any(skb); |
670 | } | 667 | } |
671 | EXPORT_SYMBOL(ieee80211_free_txskb); | 668 | EXPORT_SYMBOL(ieee80211_free_txskb); |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 0638541b625..758836c85a8 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -342,6 +342,9 @@ TRACE_EVENT(drv_bss_info_changed, | |||
342 | __field(bool, ps); | 342 | __field(bool, ps); |
343 | __dynamic_array(u8, ssid, info->ssid_len); | 343 | __dynamic_array(u8, ssid, info->ssid_len); |
344 | __field(bool, hidden_ssid); | 344 | __field(bool, hidden_ssid); |
345 | __field(int, txpower) | ||
346 | __field(u8, p2p_ctwindow) | ||
347 | __field(bool, p2p_oppps) | ||
345 | ), | 348 | ), |
346 | 349 | ||
347 | TP_fast_assign( | 350 | TP_fast_assign( |
@@ -376,6 +379,9 @@ TRACE_EVENT(drv_bss_info_changed, | |||
376 | __entry->ps = info->ps; | 379 | __entry->ps = info->ps; |
377 | memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); | 380 | memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); |
378 | __entry->hidden_ssid = info->hidden_ssid; | 381 | __entry->hidden_ssid = info->hidden_ssid; |
382 | __entry->txpower = info->txpower; | ||
383 | __entry->p2p_ctwindow = info->p2p_ctwindow; | ||
384 | __entry->p2p_oppps = info->p2p_oppps; | ||
379 | ), | 385 | ), |
380 | 386 | ||
381 | TP_printk( | 387 | TP_printk( |
@@ -1043,34 +1049,6 @@ DEFINE_EVENT(local_only_evt, drv_cancel_remain_on_channel, | |||
1043 | TP_ARGS(local) | 1049 | TP_ARGS(local) |
1044 | ); | 1050 | ); |
1045 | 1051 | ||
1046 | TRACE_EVENT(drv_offchannel_tx, | ||
1047 | TP_PROTO(struct ieee80211_local *local, struct sk_buff *skb, | ||
1048 | struct ieee80211_channel *chan, | ||
1049 | enum nl80211_channel_type channel_type, | ||
1050 | unsigned int wait), | ||
1051 | |||
1052 | TP_ARGS(local, skb, chan, channel_type, wait), | ||
1053 | |||
1054 | TP_STRUCT__entry( | ||
1055 | LOCAL_ENTRY | ||
1056 | __field(int, center_freq) | ||
1057 | __field(int, channel_type) | ||
1058 | __field(unsigned int, wait) | ||
1059 | ), | ||
1060 | |||
1061 | TP_fast_assign( | ||
1062 | LOCAL_ASSIGN; | ||
1063 | __entry->center_freq = chan->center_freq; | ||
1064 | __entry->channel_type = channel_type; | ||
1065 | __entry->wait = wait; | ||
1066 | ), | ||
1067 | |||
1068 | TP_printk( | ||
1069 | LOCAL_PR_FMT " freq:%dMHz, wait:%dms", | ||
1070 | LOCAL_PR_ARG, __entry->center_freq, __entry->wait | ||
1071 | ) | ||
1072 | ); | ||
1073 | |||
1074 | TRACE_EVENT(drv_set_ringparam, | 1052 | TRACE_EVENT(drv_set_ringparam, |
1075 | TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx), | 1053 | TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx), |
1076 | 1054 | ||
@@ -1396,6 +1374,48 @@ DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx, | |||
1396 | TP_ARGS(local, sdata, ctx) | 1374 | TP_ARGS(local, sdata, ctx) |
1397 | ); | 1375 | ); |
1398 | 1376 | ||
1377 | TRACE_EVENT(drv_start_ap, | ||
1378 | TP_PROTO(struct ieee80211_local *local, | ||
1379 | struct ieee80211_sub_if_data *sdata, | ||
1380 | struct ieee80211_bss_conf *info), | ||
1381 | |||
1382 | TP_ARGS(local, sdata, info), | ||
1383 | |||
1384 | TP_STRUCT__entry( | ||
1385 | LOCAL_ENTRY | ||
1386 | VIF_ENTRY | ||
1387 | __field(u8, dtimper) | ||
1388 | __field(u16, bcnint) | ||
1389 | __dynamic_array(u8, ssid, info->ssid_len); | ||
1390 | __field(bool, hidden_ssid); | ||
1391 | ), | ||
1392 | |||
1393 | TP_fast_assign( | ||
1394 | LOCAL_ASSIGN; | ||
1395 | VIF_ASSIGN; | ||
1396 | __entry->dtimper = info->dtim_period; | ||
1397 | __entry->bcnint = info->beacon_int; | ||
1398 | memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len); | ||
1399 | __entry->hidden_ssid = info->hidden_ssid; | ||
1400 | ), | ||
1401 | |||
1402 | TP_printk( | ||
1403 | LOCAL_PR_FMT VIF_PR_FMT, | ||
1404 | LOCAL_PR_ARG, VIF_PR_ARG | ||
1405 | ) | ||
1406 | ); | ||
1407 | |||
1408 | DEFINE_EVENT(local_sdata_evt, drv_stop_ap, | ||
1409 | TP_PROTO(struct ieee80211_local *local, | ||
1410 | struct ieee80211_sub_if_data *sdata), | ||
1411 | TP_ARGS(local, sdata) | ||
1412 | ); | ||
1413 | |||
1414 | DEFINE_EVENT(local_only_evt, drv_restart_complete, | ||
1415 | TP_PROTO(struct ieee80211_local *local), | ||
1416 | TP_ARGS(local) | ||
1417 | ); | ||
1418 | |||
1399 | /* | 1419 | /* |
1400 | * Tracing for API calls that drivers call. | 1420 | * Tracing for API calls that drivers call. |
1401 | */ | 1421 | */ |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 065f81cb561..b5468876287 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -2089,6 +2089,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2089 | head_need = max_t(int, 0, head_need); | 2089 | head_need = max_t(int, 0, head_need); |
2090 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { | 2090 | if (ieee80211_skb_resize(sdata, skb, head_need, true)) { |
2091 | ieee80211_free_txskb(&local->hw, skb); | 2091 | ieee80211_free_txskb(&local->hw, skb); |
2092 | skb = NULL; | ||
2092 | goto fail_rcu; | 2093 | goto fail_rcu; |
2093 | } | 2094 | } |
2094 | } | 2095 | } |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 9556391b05d..4e4f5851367 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -512,7 +512,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw) | |||
512 | EXPORT_SYMBOL(ieee80211_wake_queues); | 512 | EXPORT_SYMBOL(ieee80211_wake_queues); |
513 | 513 | ||
514 | void ieee80211_iterate_active_interfaces( | 514 | void ieee80211_iterate_active_interfaces( |
515 | struct ieee80211_hw *hw, | 515 | struct ieee80211_hw *hw, u32 iter_flags, |
516 | void (*iterator)(void *data, u8 *mac, | 516 | void (*iterator)(void *data, u8 *mac, |
517 | struct ieee80211_vif *vif), | 517 | struct ieee80211_vif *vif), |
518 | void *data) | 518 | void *data) |
@@ -530,6 +530,9 @@ void ieee80211_iterate_active_interfaces( | |||
530 | default: | 530 | default: |
531 | break; | 531 | break; |
532 | } | 532 | } |
533 | if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) && | ||
534 | !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
535 | continue; | ||
533 | if (ieee80211_sdata_running(sdata)) | 536 | if (ieee80211_sdata_running(sdata)) |
534 | iterator(data, sdata->vif.addr, | 537 | iterator(data, sdata->vif.addr, |
535 | &sdata->vif); | 538 | &sdata->vif); |
@@ -537,7 +540,9 @@ void ieee80211_iterate_active_interfaces( | |||
537 | 540 | ||
538 | sdata = rcu_dereference_protected(local->monitor_sdata, | 541 | sdata = rcu_dereference_protected(local->monitor_sdata, |
539 | lockdep_is_held(&local->iflist_mtx)); | 542 | lockdep_is_held(&local->iflist_mtx)); |
540 | if (sdata) | 543 | if (sdata && |
544 | (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || | ||
545 | sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
541 | iterator(data, sdata->vif.addr, &sdata->vif); | 546 | iterator(data, sdata->vif.addr, &sdata->vif); |
542 | 547 | ||
543 | mutex_unlock(&local->iflist_mtx); | 548 | mutex_unlock(&local->iflist_mtx); |
@@ -545,7 +550,7 @@ void ieee80211_iterate_active_interfaces( | |||
545 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); | 550 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); |
546 | 551 | ||
547 | void ieee80211_iterate_active_interfaces_atomic( | 552 | void ieee80211_iterate_active_interfaces_atomic( |
548 | struct ieee80211_hw *hw, | 553 | struct ieee80211_hw *hw, u32 iter_flags, |
549 | void (*iterator)(void *data, u8 *mac, | 554 | void (*iterator)(void *data, u8 *mac, |
550 | struct ieee80211_vif *vif), | 555 | struct ieee80211_vif *vif), |
551 | void *data) | 556 | void *data) |
@@ -563,13 +568,18 @@ void ieee80211_iterate_active_interfaces_atomic( | |||
563 | default: | 568 | default: |
564 | break; | 569 | break; |
565 | } | 570 | } |
571 | if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) && | ||
572 | !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
573 | continue; | ||
566 | if (ieee80211_sdata_running(sdata)) | 574 | if (ieee80211_sdata_running(sdata)) |
567 | iterator(data, sdata->vif.addr, | 575 | iterator(data, sdata->vif.addr, |
568 | &sdata->vif); | 576 | &sdata->vif); |
569 | } | 577 | } |
570 | 578 | ||
571 | sdata = rcu_dereference(local->monitor_sdata); | 579 | sdata = rcu_dereference(local->monitor_sdata); |
572 | if (sdata) | 580 | if (sdata && |
581 | (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || | ||
582 | sdata->flags & IEEE80211_SDATA_IN_DRIVER)) | ||
573 | iterator(data, sdata->vif.addr, &sdata->vif); | 583 | iterator(data, sdata->vif.addr, &sdata->vif); |
574 | 584 | ||
575 | rcu_read_unlock(); | 585 | rcu_read_unlock(); |
@@ -1412,6 +1422,23 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1412 | WARN_ON(drv_add_chanctx(local, ctx)); | 1422 | WARN_ON(drv_add_chanctx(local, ctx)); |
1413 | mutex_unlock(&local->chanctx_mtx); | 1423 | mutex_unlock(&local->chanctx_mtx); |
1414 | 1424 | ||
1425 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
1426 | struct ieee80211_chanctx_conf *ctx_conf; | ||
1427 | |||
1428 | if (!ieee80211_sdata_running(sdata)) | ||
1429 | continue; | ||
1430 | |||
1431 | mutex_lock(&local->chanctx_mtx); | ||
1432 | ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
1433 | lockdep_is_held(&local->chanctx_mtx)); | ||
1434 | if (ctx_conf) { | ||
1435 | ctx = container_of(ctx_conf, struct ieee80211_chanctx, | ||
1436 | conf); | ||
1437 | drv_assign_vif_chanctx(local, sdata, ctx); | ||
1438 | } | ||
1439 | mutex_unlock(&local->chanctx_mtx); | ||
1440 | } | ||
1441 | |||
1415 | /* add STAs back */ | 1442 | /* add STAs back */ |
1416 | mutex_lock(&local->sta_mtx); | 1443 | mutex_lock(&local->sta_mtx); |
1417 | list_for_each_entry(sta, &local->sta_list, list) { | 1444 | list_for_each_entry(sta, &local->sta_list, list) { |
@@ -1452,22 +1479,11 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1452 | 1479 | ||
1453 | /* Finally also reconfigure all the BSS information */ | 1480 | /* Finally also reconfigure all the BSS information */ |
1454 | list_for_each_entry(sdata, &local->interfaces, list) { | 1481 | list_for_each_entry(sdata, &local->interfaces, list) { |
1455 | struct ieee80211_chanctx_conf *ctx_conf; | ||
1456 | u32 changed; | 1482 | u32 changed; |
1457 | 1483 | ||
1458 | if (!ieee80211_sdata_running(sdata)) | 1484 | if (!ieee80211_sdata_running(sdata)) |
1459 | continue; | 1485 | continue; |
1460 | 1486 | ||
1461 | mutex_lock(&local->chanctx_mtx); | ||
1462 | ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf, | ||
1463 | lockdep_is_held(&local->chanctx_mtx)); | ||
1464 | if (ctx_conf) { | ||
1465 | ctx = container_of(ctx_conf, struct ieee80211_chanctx, | ||
1466 | conf); | ||
1467 | drv_assign_vif_chanctx(local, sdata, ctx); | ||
1468 | } | ||
1469 | mutex_unlock(&local->chanctx_mtx); | ||
1470 | |||
1471 | /* common change flags for all interface types */ | 1487 | /* common change flags for all interface types */ |
1472 | changed = BSS_CHANGED_ERP_CTS_PROT | | 1488 | changed = BSS_CHANGED_ERP_CTS_PROT | |
1473 | BSS_CHANGED_ERP_PREAMBLE | | 1489 | BSS_CHANGED_ERP_PREAMBLE | |
@@ -1478,7 +1494,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1478 | BSS_CHANGED_BSSID | | 1494 | BSS_CHANGED_BSSID | |
1479 | BSS_CHANGED_CQM | | 1495 | BSS_CHANGED_CQM | |
1480 | BSS_CHANGED_QOS | | 1496 | BSS_CHANGED_QOS | |
1481 | BSS_CHANGED_IDLE; | 1497 | BSS_CHANGED_IDLE | |
1498 | BSS_CHANGED_TXPOWER; | ||
1482 | 1499 | ||
1483 | switch (sdata->vif.type) { | 1500 | switch (sdata->vif.type) { |
1484 | case NL80211_IFTYPE_STATION: | 1501 | case NL80211_IFTYPE_STATION: |
@@ -1495,9 +1512,13 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1495 | case NL80211_IFTYPE_AP: | 1512 | case NL80211_IFTYPE_AP: |
1496 | changed |= BSS_CHANGED_SSID; | 1513 | changed |= BSS_CHANGED_SSID; |
1497 | 1514 | ||
1498 | if (sdata->vif.type == NL80211_IFTYPE_AP) | 1515 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
1499 | changed |= BSS_CHANGED_AP_PROBE_RESP; | 1516 | changed |= BSS_CHANGED_AP_PROBE_RESP; |
1500 | 1517 | ||
1518 | if (rcu_access_pointer(sdata->u.ap.beacon)) | ||
1519 | drv_start_ap(local, sdata); | ||
1520 | } | ||
1521 | |||
1501 | /* fall through */ | 1522 | /* fall through */ |
1502 | case NL80211_IFTYPE_MESH_POINT: | 1523 | case NL80211_IFTYPE_MESH_POINT: |
1503 | changed |= BSS_CHANGED_BEACON | | 1524 | changed |= BSS_CHANGED_BEACON | |
@@ -1594,8 +1615,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1594 | * If this is for hw restart things are still running. | 1615 | * If this is for hw restart things are still running. |
1595 | * We may want to change that later, however. | 1616 | * We may want to change that later, however. |
1596 | */ | 1617 | */ |
1597 | if (!local->suspended) | 1618 | if (!local->suspended) { |
1619 | drv_restart_complete(local); | ||
1598 | return 0; | 1620 | return 0; |
1621 | } | ||
1599 | 1622 | ||
1600 | #ifdef CONFIG_PM | 1623 | #ifdef CONFIG_PM |
1601 | /* first set suspended false, then resuming */ | 1624 | /* first set suspended false, then resuming */ |
diff --git a/net/wireless/ap.c b/net/wireless/ap.c index e143505f05b..324e8d851dc 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c | |||
@@ -28,6 +28,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | |||
28 | if (!err) { | 28 | if (!err) { |
29 | wdev->beacon_interval = 0; | 29 | wdev->beacon_interval = 0; |
30 | wdev->channel = NULL; | 30 | wdev->channel = NULL; |
31 | wdev->ssid_len = 0; | ||
31 | } | 32 | } |
32 | 33 | ||
33 | return err; | 34 | return err; |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 26711f46a3b..14d99040035 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -326,6 +326,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
326 | mutex_init(&rdev->devlist_mtx); | 326 | mutex_init(&rdev->devlist_mtx); |
327 | mutex_init(&rdev->sched_scan_mtx); | 327 | mutex_init(&rdev->sched_scan_mtx); |
328 | INIT_LIST_HEAD(&rdev->wdev_list); | 328 | INIT_LIST_HEAD(&rdev->wdev_list); |
329 | INIT_LIST_HEAD(&rdev->beacon_registrations); | ||
330 | spin_lock_init(&rdev->beacon_registrations_lock); | ||
329 | spin_lock_init(&rdev->bss_lock); | 331 | spin_lock_init(&rdev->bss_lock); |
330 | INIT_LIST_HEAD(&rdev->bss_list); | 332 | INIT_LIST_HEAD(&rdev->bss_list); |
331 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); | 333 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); |
@@ -698,10 +700,15 @@ EXPORT_SYMBOL(wiphy_unregister); | |||
698 | void cfg80211_dev_free(struct cfg80211_registered_device *rdev) | 700 | void cfg80211_dev_free(struct cfg80211_registered_device *rdev) |
699 | { | 701 | { |
700 | struct cfg80211_internal_bss *scan, *tmp; | 702 | struct cfg80211_internal_bss *scan, *tmp; |
703 | struct cfg80211_beacon_registration *reg, *treg; | ||
701 | rfkill_destroy(rdev->rfkill); | 704 | rfkill_destroy(rdev->rfkill); |
702 | mutex_destroy(&rdev->mtx); | 705 | mutex_destroy(&rdev->mtx); |
703 | mutex_destroy(&rdev->devlist_mtx); | 706 | mutex_destroy(&rdev->devlist_mtx); |
704 | mutex_destroy(&rdev->sched_scan_mtx); | 707 | mutex_destroy(&rdev->sched_scan_mtx); |
708 | list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) { | ||
709 | list_del(®->list); | ||
710 | kfree(reg); | ||
711 | } | ||
705 | list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) | 712 | list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) |
706 | cfg80211_put_bss(&scan->pub); | 713 | cfg80211_put_bss(&scan->pub); |
707 | kfree(rdev); | 714 | kfree(rdev); |
diff --git a/net/wireless/core.h b/net/wireless/core.h index b8eb743fe7d..e53831c876b 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -55,7 +55,8 @@ struct cfg80211_registered_device { | |||
55 | int opencount; /* also protected by devlist_mtx */ | 55 | int opencount; /* also protected by devlist_mtx */ |
56 | wait_queue_head_t dev_wait; | 56 | wait_queue_head_t dev_wait; |
57 | 57 | ||
58 | u32 ap_beacons_nlportid; | 58 | struct list_head beacon_registrations; |
59 | spinlock_t beacon_registrations_lock; | ||
59 | 60 | ||
60 | /* protected by RTNL only */ | 61 | /* protected by RTNL only */ |
61 | int num_running_ifaces; | 62 | int num_running_ifaces; |
@@ -260,6 +261,10 @@ enum cfg80211_chan_mode { | |||
260 | CHAN_MODE_EXCLUSIVE, | 261 | CHAN_MODE_EXCLUSIVE, |
261 | }; | 262 | }; |
262 | 263 | ||
264 | struct cfg80211_beacon_registration { | ||
265 | struct list_head list; | ||
266 | u32 nlportid; | ||
267 | }; | ||
263 | 268 | ||
264 | /* free object */ | 269 | /* free object */ |
265 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); | 270 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8c0857815a9..c18b2fc9d49 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -1110,6 +1110,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag | |||
1110 | goto nla_put_failure; | 1110 | goto nla_put_failure; |
1111 | } | 1111 | } |
1112 | CMD(start_p2p_device, START_P2P_DEVICE); | 1112 | CMD(start_p2p_device, START_P2P_DEVICE); |
1113 | CMD(set_mcast_rate, SET_MCAST_RATE); | ||
1113 | 1114 | ||
1114 | #ifdef CONFIG_NL80211_TESTMODE | 1115 | #ifdef CONFIG_NL80211_TESTMODE |
1115 | CMD(testmode_cmd, TESTMODE); | 1116 | CMD(testmode_cmd, TESTMODE); |
@@ -1516,10 +1517,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1516 | result = 0; | 1517 | result = 0; |
1517 | 1518 | ||
1518 | mutex_lock(&rdev->mtx); | 1519 | mutex_lock(&rdev->mtx); |
1519 | } else if (nl80211_can_set_dev_channel(netdev->ieee80211_ptr)) | 1520 | } else |
1520 | wdev = netdev->ieee80211_ptr; | 1521 | wdev = netdev->ieee80211_ptr; |
1521 | else | ||
1522 | wdev = NULL; | ||
1523 | 1522 | ||
1524 | /* | 1523 | /* |
1525 | * end workaround code, by now the rdev is available | 1524 | * end workaround code, by now the rdev is available |
@@ -1579,15 +1578,21 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1579 | } | 1578 | } |
1580 | 1579 | ||
1581 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | 1580 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { |
1582 | result = __nl80211_set_channel(rdev, wdev, info); | 1581 | result = __nl80211_set_channel(rdev, |
1582 | nl80211_can_set_dev_channel(wdev) ? wdev : NULL, | ||
1583 | info); | ||
1583 | if (result) | 1584 | if (result) |
1584 | goto bad_res; | 1585 | goto bad_res; |
1585 | } | 1586 | } |
1586 | 1587 | ||
1587 | if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) { | 1588 | if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) { |
1589 | struct wireless_dev *txp_wdev = wdev; | ||
1588 | enum nl80211_tx_power_setting type; | 1590 | enum nl80211_tx_power_setting type; |
1589 | int idx, mbm = 0; | 1591 | int idx, mbm = 0; |
1590 | 1592 | ||
1593 | if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER)) | ||
1594 | txp_wdev = NULL; | ||
1595 | |||
1591 | if (!rdev->ops->set_tx_power) { | 1596 | if (!rdev->ops->set_tx_power) { |
1592 | result = -EOPNOTSUPP; | 1597 | result = -EOPNOTSUPP; |
1593 | goto bad_res; | 1598 | goto bad_res; |
@@ -1607,7 +1612,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1607 | mbm = nla_get_u32(info->attrs[idx]); | 1612 | mbm = nla_get_u32(info->attrs[idx]); |
1608 | } | 1613 | } |
1609 | 1614 | ||
1610 | result = rdev_set_tx_power(rdev, type, mbm); | 1615 | result = rdev_set_tx_power(rdev, txp_wdev, type, mbm); |
1611 | if (result) | 1616 | if (result) |
1612 | goto bad_res; | 1617 | goto bad_res; |
1613 | } | 1618 | } |
@@ -1782,6 +1787,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag | |||
1782 | goto nla_put_failure; | 1787 | goto nla_put_failure; |
1783 | } | 1788 | } |
1784 | 1789 | ||
1790 | if (wdev->ssid_len) { | ||
1791 | if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid)) | ||
1792 | goto nla_put_failure; | ||
1793 | } | ||
1794 | |||
1785 | return genlmsg_end(msg, hdr); | 1795 | return genlmsg_end(msg, hdr); |
1786 | 1796 | ||
1787 | nla_put_failure: | 1797 | nla_put_failure: |
@@ -2644,6 +2654,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2644 | wdev->preset_chantype = params.channel_type; | 2654 | wdev->preset_chantype = params.channel_type; |
2645 | wdev->beacon_interval = params.beacon_interval; | 2655 | wdev->beacon_interval = params.beacon_interval; |
2646 | wdev->channel = params.channel; | 2656 | wdev->channel = params.channel; |
2657 | wdev->ssid_len = params.ssid_len; | ||
2658 | memcpy(wdev->ssid, params.ssid, wdev->ssid_len); | ||
2647 | } | 2659 | } |
2648 | return err; | 2660 | return err; |
2649 | } | 2661 | } |
@@ -5444,6 +5456,36 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) | |||
5444 | return cfg80211_leave_ibss(rdev, dev, false); | 5456 | return cfg80211_leave_ibss(rdev, dev, false); |
5445 | } | 5457 | } |
5446 | 5458 | ||
5459 | static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info) | ||
5460 | { | ||
5461 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5462 | struct net_device *dev = info->user_ptr[1]; | ||
5463 | int mcast_rate[IEEE80211_NUM_BANDS]; | ||
5464 | u32 nla_rate; | ||
5465 | int err; | ||
5466 | |||
5467 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | ||
5468 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) | ||
5469 | return -EOPNOTSUPP; | ||
5470 | |||
5471 | if (!rdev->ops->set_mcast_rate) | ||
5472 | return -EOPNOTSUPP; | ||
5473 | |||
5474 | memset(mcast_rate, 0, sizeof(mcast_rate)); | ||
5475 | |||
5476 | if (!info->attrs[NL80211_ATTR_MCAST_RATE]) | ||
5477 | return -EINVAL; | ||
5478 | |||
5479 | nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]); | ||
5480 | if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate)) | ||
5481 | return -EINVAL; | ||
5482 | |||
5483 | err = rdev->ops->set_mcast_rate(&rdev->wiphy, dev, mcast_rate); | ||
5484 | |||
5485 | return err; | ||
5486 | } | ||
5487 | |||
5488 | |||
5447 | #ifdef CONFIG_NL80211_TESTMODE | 5489 | #ifdef CONFIG_NL80211_TESTMODE |
5448 | static struct genl_multicast_group nl80211_testmode_mcgrp = { | 5490 | static struct genl_multicast_group nl80211_testmode_mcgrp = { |
5449 | .name = "testmode", | 5491 | .name = "testmode", |
@@ -6899,16 +6941,35 @@ static int nl80211_probe_client(struct sk_buff *skb, | |||
6899 | static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) | 6941 | static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) |
6900 | { | 6942 | { |
6901 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6943 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6944 | struct cfg80211_beacon_registration *reg, *nreg; | ||
6945 | int rv; | ||
6902 | 6946 | ||
6903 | if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS)) | 6947 | if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS)) |
6904 | return -EOPNOTSUPP; | 6948 | return -EOPNOTSUPP; |
6905 | 6949 | ||
6906 | if (rdev->ap_beacons_nlportid) | 6950 | nreg = kzalloc(sizeof(*nreg), GFP_KERNEL); |
6907 | return -EBUSY; | 6951 | if (!nreg) |
6952 | return -ENOMEM; | ||
6953 | |||
6954 | /* First, check if already registered. */ | ||
6955 | spin_lock_bh(&rdev->beacon_registrations_lock); | ||
6956 | list_for_each_entry(reg, &rdev->beacon_registrations, list) { | ||
6957 | if (reg->nlportid == info->snd_portid) { | ||
6958 | rv = -EALREADY; | ||
6959 | goto out_err; | ||
6960 | } | ||
6961 | } | ||
6962 | /* Add it to the list */ | ||
6963 | nreg->nlportid = info->snd_portid; | ||
6964 | list_add(&nreg->list, &rdev->beacon_registrations); | ||
6908 | 6965 | ||
6909 | rdev->ap_beacons_nlportid = info->snd_portid; | 6966 | spin_unlock_bh(&rdev->beacon_registrations_lock); |
6910 | 6967 | ||
6911 | return 0; | 6968 | return 0; |
6969 | out_err: | ||
6970 | spin_unlock_bh(&rdev->beacon_registrations_lock); | ||
6971 | kfree(nreg); | ||
6972 | return rv; | ||
6912 | } | 6973 | } |
6913 | 6974 | ||
6914 | static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info) | 6975 | static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info) |
@@ -7625,6 +7686,14 @@ static struct genl_ops nl80211_ops[] = { | |||
7625 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | | 7686 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
7626 | NL80211_FLAG_NEED_RTNL, | 7687 | NL80211_FLAG_NEED_RTNL, |
7627 | }, | 7688 | }, |
7689 | { | ||
7690 | .cmd = NL80211_CMD_SET_MCAST_RATE, | ||
7691 | .doit = nl80211_set_mcast_rate, | ||
7692 | .policy = nl80211_policy, | ||
7693 | .flags = GENL_ADMIN_PERM, | ||
7694 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
7695 | NL80211_FLAG_NEED_RTNL, | ||
7696 | }, | ||
7628 | }; | 7697 | }; |
7629 | 7698 | ||
7630 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 7699 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
@@ -8914,43 +8983,46 @@ EXPORT_SYMBOL(cfg80211_probe_status); | |||
8914 | 8983 | ||
8915 | void cfg80211_report_obss_beacon(struct wiphy *wiphy, | 8984 | void cfg80211_report_obss_beacon(struct wiphy *wiphy, |
8916 | const u8 *frame, size_t len, | 8985 | const u8 *frame, size_t len, |
8917 | int freq, int sig_dbm, gfp_t gfp) | 8986 | int freq, int sig_dbm) |
8918 | { | 8987 | { |
8919 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 8988 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
8920 | struct sk_buff *msg; | 8989 | struct sk_buff *msg; |
8921 | void *hdr; | 8990 | void *hdr; |
8922 | u32 nlportid = ACCESS_ONCE(rdev->ap_beacons_nlportid); | 8991 | struct cfg80211_beacon_registration *reg; |
8923 | 8992 | ||
8924 | trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm); | 8993 | trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm); |
8925 | 8994 | ||
8926 | if (!nlportid) | 8995 | spin_lock_bh(&rdev->beacon_registrations_lock); |
8927 | return; | 8996 | list_for_each_entry(reg, &rdev->beacon_registrations, list) { |
8928 | 8997 | msg = nlmsg_new(len + 100, GFP_ATOMIC); | |
8929 | msg = nlmsg_new(len + 100, gfp); | 8998 | if (!msg) { |
8930 | if (!msg) | 8999 | spin_unlock_bh(&rdev->beacon_registrations_lock); |
8931 | return; | 9000 | return; |
9001 | } | ||
8932 | 9002 | ||
8933 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); | 9003 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); |
8934 | if (!hdr) { | 9004 | if (!hdr) |
8935 | nlmsg_free(msg); | 9005 | goto nla_put_failure; |
8936 | return; | ||
8937 | } | ||
8938 | 9006 | ||
8939 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 9007 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
8940 | (freq && | 9008 | (freq && |
8941 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) || | 9009 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) || |
8942 | (sig_dbm && | 9010 | (sig_dbm && |
8943 | nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || | 9011 | nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || |
8944 | nla_put(msg, NL80211_ATTR_FRAME, len, frame)) | 9012 | nla_put(msg, NL80211_ATTR_FRAME, len, frame)) |
8945 | goto nla_put_failure; | 9013 | goto nla_put_failure; |
8946 | 9014 | ||
8947 | genlmsg_end(msg, hdr); | 9015 | genlmsg_end(msg, hdr); |
8948 | 9016 | ||
8949 | genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid); | 9017 | genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid); |
9018 | } | ||
9019 | spin_unlock_bh(&rdev->beacon_registrations_lock); | ||
8950 | return; | 9020 | return; |
8951 | 9021 | ||
8952 | nla_put_failure: | 9022 | nla_put_failure: |
8953 | genlmsg_cancel(msg, hdr); | 9023 | spin_unlock_bh(&rdev->beacon_registrations_lock); |
9024 | if (hdr) | ||
9025 | genlmsg_cancel(msg, hdr); | ||
8954 | nlmsg_free(msg); | 9026 | nlmsg_free(msg); |
8955 | } | 9027 | } |
8956 | EXPORT_SYMBOL(cfg80211_report_obss_beacon); | 9028 | EXPORT_SYMBOL(cfg80211_report_obss_beacon); |
@@ -8962,6 +9034,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
8962 | struct netlink_notify *notify = _notify; | 9034 | struct netlink_notify *notify = _notify; |
8963 | struct cfg80211_registered_device *rdev; | 9035 | struct cfg80211_registered_device *rdev; |
8964 | struct wireless_dev *wdev; | 9036 | struct wireless_dev *wdev; |
9037 | struct cfg80211_beacon_registration *reg, *tmp; | ||
8965 | 9038 | ||
8966 | if (state != NETLINK_URELEASE) | 9039 | if (state != NETLINK_URELEASE) |
8967 | return NOTIFY_DONE; | 9040 | return NOTIFY_DONE; |
@@ -8971,8 +9044,17 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
8971 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { | 9044 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { |
8972 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) | 9045 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) |
8973 | cfg80211_mlme_unregister_socket(wdev, notify->portid); | 9046 | cfg80211_mlme_unregister_socket(wdev, notify->portid); |
8974 | if (rdev->ap_beacons_nlportid == notify->portid) | 9047 | |
8975 | rdev->ap_beacons_nlportid = 0; | 9048 | spin_lock_bh(&rdev->beacon_registrations_lock); |
9049 | list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations, | ||
9050 | list) { | ||
9051 | if (reg->nlportid == notify->portid) { | ||
9052 | list_del(®->list); | ||
9053 | kfree(reg); | ||
9054 | break; | ||
9055 | } | ||
9056 | } | ||
9057 | spin_unlock_bh(&rdev->beacon_registrations_lock); | ||
8976 | } | 9058 | } |
8977 | 9059 | ||
8978 | rcu_read_unlock(); | 9060 | rcu_read_unlock(); |
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index eb5f8974e14..6e5fa659068 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
@@ -476,21 +476,22 @@ rdev_set_wiphy_params(struct cfg80211_registered_device *rdev, u32 changed) | |||
476 | } | 476 | } |
477 | 477 | ||
478 | static inline int rdev_set_tx_power(struct cfg80211_registered_device *rdev, | 478 | static inline int rdev_set_tx_power(struct cfg80211_registered_device *rdev, |
479 | struct wireless_dev *wdev, | ||
479 | enum nl80211_tx_power_setting type, int mbm) | 480 | enum nl80211_tx_power_setting type, int mbm) |
480 | { | 481 | { |
481 | int ret; | 482 | int ret; |
482 | trace_rdev_set_tx_power(&rdev->wiphy, type, mbm); | 483 | trace_rdev_set_tx_power(&rdev->wiphy, wdev, type, mbm); |
483 | ret = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm); | 484 | ret = rdev->ops->set_tx_power(&rdev->wiphy, wdev, type, mbm); |
484 | trace_rdev_return_int(&rdev->wiphy, ret); | 485 | trace_rdev_return_int(&rdev->wiphy, ret); |
485 | return ret; | 486 | return ret; |
486 | } | 487 | } |
487 | 488 | ||
488 | static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev, | 489 | static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev, |
489 | int *dbm) | 490 | struct wireless_dev *wdev, int *dbm) |
490 | { | 491 | { |
491 | int ret; | 492 | int ret; |
492 | trace_rdev_get_tx_power(&rdev->wiphy); | 493 | trace_rdev_get_tx_power(&rdev->wiphy, wdev); |
493 | ret = rdev->ops->get_tx_power(&rdev->wiphy, dbm); | 494 | ret = rdev->ops->get_tx_power(&rdev->wiphy, wdev, dbm); |
494 | trace_rdev_return_int_int(&rdev->wiphy, ret, *dbm); | 495 | trace_rdev_return_int_int(&rdev->wiphy, ret, *dbm); |
495 | return ret; | 496 | return ret; |
496 | } | 497 | } |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 0ca71caf85f..8e03c6382a8 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -26,7 +26,7 @@ | |||
26 | #define WIPHY_PR_ARG MAC_PR_ARG(wiphy_mac) | 26 | #define WIPHY_PR_ARG MAC_PR_ARG(wiphy_mac) |
27 | 27 | ||
28 | #define WDEV_ENTRY __field(u32, id) | 28 | #define WDEV_ENTRY __field(u32, id) |
29 | #define WDEV_ASSIGN (__entry->id) = (wdev->identifier) | 29 | #define WDEV_ASSIGN (__entry->id) = (wdev ? wdev->identifier : 0) |
30 | #define WDEV_PR_FMT ", wdev id: %u" | 30 | #define WDEV_PR_FMT ", wdev id: %u" |
31 | #define WDEV_PR_ARG (__entry->id) | 31 | #define WDEV_PR_ARG (__entry->id) |
32 | 32 | ||
@@ -260,11 +260,6 @@ DEFINE_EVENT(wiphy_only_evt, rdev_get_antenna, | |||
260 | TP_ARGS(wiphy) | 260 | TP_ARGS(wiphy) |
261 | ); | 261 | ); |
262 | 262 | ||
263 | DEFINE_EVENT(wiphy_only_evt, rdev_get_tx_power, | ||
264 | TP_PROTO(struct wiphy *wiphy), | ||
265 | TP_ARGS(wiphy) | ||
266 | ); | ||
267 | |||
268 | DEFINE_EVENT(wiphy_only_evt, rdev_rfkill_poll, | 263 | DEFINE_EVENT(wiphy_only_evt, rdev_rfkill_poll, |
269 | TP_PROTO(struct wiphy *wiphy), | 264 | TP_PROTO(struct wiphy *wiphy), |
270 | TP_ARGS(wiphy) | 265 | TP_ARGS(wiphy) |
@@ -1230,22 +1225,29 @@ TRACE_EVENT(rdev_set_wiphy_params, | |||
1230 | WIPHY_PR_ARG, __entry->changed) | 1225 | WIPHY_PR_ARG, __entry->changed) |
1231 | ); | 1226 | ); |
1232 | 1227 | ||
1228 | DEFINE_EVENT(wiphy_wdev_evt, rdev_get_tx_power, | ||
1229 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), | ||
1230 | TP_ARGS(wiphy, wdev) | ||
1231 | ); | ||
1232 | |||
1233 | TRACE_EVENT(rdev_set_tx_power, | 1233 | TRACE_EVENT(rdev_set_tx_power, |
1234 | TP_PROTO(struct wiphy *wiphy, enum nl80211_tx_power_setting type, | 1234 | TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, |
1235 | int mbm), | 1235 | enum nl80211_tx_power_setting type, int mbm), |
1236 | TP_ARGS(wiphy, type, mbm), | 1236 | TP_ARGS(wiphy, wdev, type, mbm), |
1237 | TP_STRUCT__entry( | 1237 | TP_STRUCT__entry( |
1238 | WIPHY_ENTRY | 1238 | WIPHY_ENTRY |
1239 | WDEV_ENTRY | ||
1239 | __field(enum nl80211_tx_power_setting, type) | 1240 | __field(enum nl80211_tx_power_setting, type) |
1240 | __field(int, mbm) | 1241 | __field(int, mbm) |
1241 | ), | 1242 | ), |
1242 | TP_fast_assign( | 1243 | TP_fast_assign( |
1243 | WIPHY_ASSIGN; | 1244 | WIPHY_ASSIGN; |
1245 | WDEV_ASSIGN; | ||
1244 | __entry->type = type; | 1246 | __entry->type = type; |
1245 | __entry->mbm = mbm; | 1247 | __entry->mbm = mbm; |
1246 | ), | 1248 | ), |
1247 | TP_printk(WIPHY_PR_FMT ", type: %d, mbm: %d", | 1249 | TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", type: %d, mbm: %d", |
1248 | WIPHY_PR_ARG, __entry->type, __entry->mbm) | 1250 | WIPHY_PR_ARG, WDEV_PR_ARG,__entry->type, __entry->mbm) |
1249 | ); | 1251 | ); |
1250 | 1252 | ||
1251 | TRACE_EVENT(rdev_return_int_int, | 1253 | TRACE_EVENT(rdev_return_int_int, |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 5b6c1df72f3..b99f01cda1f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -980,6 +980,105 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate) | |||
980 | } | 980 | } |
981 | EXPORT_SYMBOL(cfg80211_calculate_bitrate); | 981 | EXPORT_SYMBOL(cfg80211_calculate_bitrate); |
982 | 982 | ||
983 | unsigned int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len, | ||
984 | u8 attr, u8 *buf, unsigned int bufsize) | ||
985 | { | ||
986 | u8 *out = buf; | ||
987 | u16 attr_remaining = 0; | ||
988 | bool desired_attr = false; | ||
989 | u16 desired_len = 0; | ||
990 | |||
991 | while (len > 0) { | ||
992 | unsigned int iedatalen; | ||
993 | unsigned int copy; | ||
994 | const u8 *iedata; | ||
995 | |||
996 | if (len < 2) | ||
997 | return -EILSEQ; | ||
998 | iedatalen = ies[1]; | ||
999 | if (iedatalen + 2 > len) | ||
1000 | return -EILSEQ; | ||
1001 | |||
1002 | if (ies[0] != WLAN_EID_VENDOR_SPECIFIC) | ||
1003 | goto cont; | ||
1004 | |||
1005 | if (iedatalen < 4) | ||
1006 | goto cont; | ||
1007 | |||
1008 | iedata = ies + 2; | ||
1009 | |||
1010 | /* check WFA OUI, P2P subtype */ | ||
1011 | if (iedata[0] != 0x50 || iedata[1] != 0x6f || | ||
1012 | iedata[2] != 0x9a || iedata[3] != 0x09) | ||
1013 | goto cont; | ||
1014 | |||
1015 | iedatalen -= 4; | ||
1016 | iedata += 4; | ||
1017 | |||
1018 | /* check attribute continuation into this IE */ | ||
1019 | copy = min_t(unsigned int, attr_remaining, iedatalen); | ||
1020 | if (copy && desired_attr) { | ||
1021 | desired_len += copy; | ||
1022 | if (out) { | ||
1023 | memcpy(out, iedata, min(bufsize, copy)); | ||
1024 | out += min(bufsize, copy); | ||
1025 | bufsize -= min(bufsize, copy); | ||
1026 | } | ||
1027 | |||
1028 | |||
1029 | if (copy == attr_remaining) | ||
1030 | return desired_len; | ||
1031 | } | ||
1032 | |||
1033 | attr_remaining -= copy; | ||
1034 | if (attr_remaining) | ||
1035 | goto cont; | ||
1036 | |||
1037 | iedatalen -= copy; | ||
1038 | iedata += copy; | ||
1039 | |||
1040 | while (iedatalen > 0) { | ||
1041 | u16 attr_len; | ||
1042 | |||
1043 | /* P2P attribute ID & size must fit */ | ||
1044 | if (iedatalen < 3) | ||
1045 | return -EILSEQ; | ||
1046 | desired_attr = iedata[0] == attr; | ||
1047 | attr_len = get_unaligned_le16(iedata + 1); | ||
1048 | iedatalen -= 3; | ||
1049 | iedata += 3; | ||
1050 | |||
1051 | copy = min_t(unsigned int, attr_len, iedatalen); | ||
1052 | |||
1053 | if (desired_attr) { | ||
1054 | desired_len += copy; | ||
1055 | if (out) { | ||
1056 | memcpy(out, iedata, min(bufsize, copy)); | ||
1057 | out += min(bufsize, copy); | ||
1058 | bufsize -= min(bufsize, copy); | ||
1059 | } | ||
1060 | |||
1061 | if (copy == attr_len) | ||
1062 | return desired_len; | ||
1063 | } | ||
1064 | |||
1065 | iedata += copy; | ||
1066 | iedatalen -= copy; | ||
1067 | attr_remaining = attr_len - copy; | ||
1068 | } | ||
1069 | |||
1070 | cont: | ||
1071 | len -= ies[1] + 2; | ||
1072 | ies += ies[1] + 2; | ||
1073 | } | ||
1074 | |||
1075 | if (attr_remaining && desired_attr) | ||
1076 | return -EILSEQ; | ||
1077 | |||
1078 | return -ENOENT; | ||
1079 | } | ||
1080 | EXPORT_SYMBOL(cfg80211_get_p2p_attr); | ||
1081 | |||
983 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 1082 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
984 | u32 beacon_int) | 1083 | u32 beacon_int) |
985 | { | 1084 | { |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 6488d2dbc1d..742ab6ec4c9 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -895,7 +895,7 @@ static int cfg80211_wext_siwtxpower(struct net_device *dev, | |||
895 | return 0; | 895 | return 0; |
896 | } | 896 | } |
897 | 897 | ||
898 | return rdev_set_tx_power(rdev, type, DBM_TO_MBM(dbm)); | 898 | return rdev_set_tx_power(rdev, wdev, type, DBM_TO_MBM(dbm)); |
899 | } | 899 | } |
900 | 900 | ||
901 | static int cfg80211_wext_giwtxpower(struct net_device *dev, | 901 | static int cfg80211_wext_giwtxpower(struct net_device *dev, |
@@ -914,7 +914,7 @@ static int cfg80211_wext_giwtxpower(struct net_device *dev, | |||
914 | if (!rdev->ops->get_tx_power) | 914 | if (!rdev->ops->get_tx_power) |
915 | return -EOPNOTSUPP; | 915 | return -EOPNOTSUPP; |
916 | 916 | ||
917 | err = rdev_get_tx_power(rdev, &val); | 917 | err = rdev_get_tx_power(rdev, wdev, &val); |
918 | if (err) | 918 | if (err) |
919 | return err; | 919 | return err; |
920 | 920 | ||