Johannes Berg says: ==================== My last pull request has been a while, we now have: * connection quality monitoring with multiple thresholds * support for FILS shared key authentication offload * pre-CAC regulatory compliance - only ETSI allows this * sanity check for some rate confusion that hit ChromeOS (but nobody else uses it, evidently) * some documentation updates * lots of cleanups ====================
Unified · Split
| @@ -2,6 +2,9 @@ · 1 unmodified line | ||
| 2 | 2 | cfg80211 subsystem |
| 3 | 3 | ================== |
| 4 | 4 | |
| 5 | +.. kernel-doc:: include/net/cfg80211.h | |
| 6 | + :doc: Introduction | |
| 7 | + | |
| 5 | 8 | Device registration |
| 6 | 9 | =================== |
| 7 | 10 | |
| @@ -179,6 +182,12 @@ Actions and configuration · 171 unmodified lines | ||
| 179 | 182 | .. kernel-doc:: include/net/cfg80211.h |
| 180 | 183 | :functions: cfg80211_ibss_joined |
| 181 | 184 | |
| 185 | +.. kernel-doc:: include/net/cfg80211.h | |
| 186 | + :functions: cfg80211_connect_resp_params | |
| 187 | + | |
| 188 | +.. kernel-doc:: include/net/cfg80211.h | |
| 189 | + :functions: cfg80211_connect_done | |
| 190 | + | |
| 182 | 191 | .. kernel-doc:: include/net/cfg80211.h |
| 183 | 192 | :functions: cfg80211_connect_result |
| 184 | 193 | |
| @@ -1917,6 +1917,8 @@ static int adm8211_probe(struct pci_dev *pdev, · 1916 unmodified lines | ||
| 1917 | 1917 | |
| 1918 | 1918 | dev->wiphy->bands[NL80211_BAND_2GHZ] = &priv->band; |
| 1919 | 1919 | |
| 1920 | + wiphy_ext_feature_set(dev->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 1921 | + | |
| 1920 | 1922 | err = ieee80211_register_hw(dev); |
| 1921 | 1923 | if (err) { |
| 1922 | 1924 | printk(KERN_ERR "%s (adm8211): Cannot register device\n", |
| @@ -1689,6 +1689,8 @@ static int ar5523_probe(struct usb_interface *intf, · 1688 unmodified lines | ||
| 1689 | 1689 | if (error) |
| 1690 | 1690 | goto out_cancel_rx_cmd; |
| 1691 | 1691 | |
| 1692 | + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 1693 | + | |
| 1692 | 1694 | usb_set_intfdata(intf, hw); |
| 1693 | 1695 | |
| 1694 | 1696 | error = ieee80211_register_hw(hw); |
| @@ -8267,6 +8267,8 @@ int ath10k_mac_register(struct ath10k *ar) · 8266 unmodified lines | ||
| 8267 | 8267 | ar->hw->wiphy->cipher_suites = cipher_suites; |
| 8268 | 8268 | ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); |
| 8269 | 8269 | |
| 8270 | + wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 8271 | + | |
| 8270 | 8272 | ret = ieee80211_register_hw(ar->hw); |
| 8271 | 8273 | if (ret) { |
| 8272 | 8274 | ath10k_err(ar, "failed to register ieee80211: %d\n", ret); |
| @@ -2564,6 +2564,8 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) · 2563 unmodified lines | ||
| 2564 | 2564 | |
| 2565 | 2565 | hw->extra_tx_headroom = 2; |
| 2566 | 2566 | |
| 2567 | + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 2568 | + | |
| 2567 | 2569 | /* |
| 2568 | 2570 | * Mark the device as detached to avoid processing |
| 2569 | 2571 | * interrupts until setup is complete. |
| @@ -1503,7 +1503,6 @@ static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy, · 1502 unmodified lines | ||
| 1503 | 1503 | const char *name, |
| 1504 | 1504 | unsigned char name_assign_type, |
| 1505 | 1505 | enum nl80211_iftype type, |
| 1506 | − u32 *flags, | |
| 1507 | 1506 | struct vif_params *params) |
| 1508 | 1507 | { |
| 1509 | 1508 | struct ath6kl *ar = wiphy_priv(wiphy); |
| @@ -1550,7 +1549,7 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy, · 40 unmodified lines | ||
| 1550 | 1549 | |
| 1551 | 1550 | static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, |
| 1552 | 1551 | struct net_device *ndev, |
| 1553 | − enum nl80211_iftype type, u32 *flags, | |
| 1552 | + enum nl80211_iftype type, | |
| 1554 | 1553 | struct vif_params *params) |
| 1555 | 1554 | { |
| 1556 | 1555 | struct ath6kl_vif *vif = netdev_priv(ndev); |
| @@ -780,6 +780,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, · 779 unmodified lines | ||
| 780 | 780 | } |
| 781 | 781 | |
| 782 | 782 | SET_IEEE80211_PERM_ADDR(hw, common->macaddr); |
| 783 | + | |
| 784 | + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 783 | 785 | } |
| 784 | 786 | |
| 785 | 787 | static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv) |
| @@ -955,6 +955,8 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) · 954 unmodified lines | ||
| 955 | 955 | ath9k_cmn_reload_chainmask(ah); |
| 956 | 956 | |
| 957 | 957 | SET_IEEE80211_PERM_ADDR(hw, common->macaddr); |
| 958 | + | |
| 959 | + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 958 | 960 | } |
| 959 | 961 | |
| 960 | 962 | int ath9k_init_device(u16 devid, struct ath_softc *sc, |
| @@ -1874,6 +1874,8 @@ void *carl9170_alloc(size_t priv_size) · 1873 unmodified lines | ||
| 1874 | 1874 | for (i = 0; i < ARRAY_SIZE(ar->noise); i++) |
| 1875 | 1875 | ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ |
| 1876 | 1876 | |
| 1877 | + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 1878 | + | |
| 1877 | 1879 | return ar; |
| 1878 | 1880 | |
| 1879 | 1881 | err_nomem: |
| @@ -1112,6 +1112,9 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) · 1111 unmodified lines | ||
| 1112 | 1112 | wcn->hw->sta_data_size = sizeof(struct wcn36xx_sta); |
| 1113 | 1113 | wcn->hw->vif_data_size = sizeof(struct wcn36xx_vif); |
| 1114 | 1114 | |
| 1115 | + wiphy_ext_feature_set(wcn->hw->wiphy, | |
| 1116 | + NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 1117 | + | |
| 1115 | 1118 | return ret; |
| 1116 | 1119 | } |
| 1117 | 1120 | |
| @@ -178,9 +178,8 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, · 177 unmodified lines | ||
| 178 | 178 | BIT(NL80211_STA_INFO_RX_DROP_MISC) | |
| 179 | 179 | BIT(NL80211_STA_INFO_TX_FAILED); |
| 180 | 180 | |
| 181 | − sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; | |
| 181 | + sinfo->txrate.flags = RATE_INFO_FLAGS_60G; | |
| 182 | 182 | sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs); |
| 183 | − sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G; | |
| 184 | 183 | sinfo->rxrate.mcs = stats->last_mcs_rx; |
| 185 | 184 | sinfo->rx_bytes = stats->rx_bytes; |
| 186 | 185 | sinfo->rx_packets = stats->rx_packets; |
| @@ -256,7 +255,7 @@ static struct wireless_dev * · 69 unmodified lines | ||
| 256 | 255 | wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name, |
| 257 | 256 | unsigned char name_assign_type, |
| 258 | 257 | enum nl80211_iftype type, |
| 259 | − u32 *flags, struct vif_params *params) | |
| 258 | + struct vif_params *params) | |
| 260 | 259 | { |
| 261 | 260 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); |
| 262 | 261 | struct net_device *ndev = wil_to_ndev(wil); |
| @@ -307,7 +306,7 @@ static int wil_cfg80211_del_iface(struct wiphy *wiphy, · 44 unmodified lines | ||
| 307 | 306 | |
| 308 | 307 | static int wil_cfg80211_change_iface(struct wiphy *wiphy, |
| 309 | 308 | struct net_device *ndev, |
| 310 | − enum nl80211_iftype type, u32 *flags, | |
| 309 | + enum nl80211_iftype type, | |
| 311 | 310 | struct vif_params *params) |
| 312 | 311 | { |
| 313 | 312 | struct wil6210_priv *wil = wiphy_to_wil(wiphy); |
| @@ -334,11 +333,8 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy, · 20 unmodified lines | ||
| 334 | 333 | case NL80211_IFTYPE_P2P_GO: |
| 335 | 334 | break; |
| 336 | 335 | case NL80211_IFTYPE_MONITOR: |
| 337 | − if (flags) | |
| 338 | − wil->monitor_flags = *flags; | |
| 339 | − else | |
| 340 | − wil->monitor_flags = 0; | |
| 341 | − | |
| 336 | + if (params->flags) | |
| 337 | + wil->monitor_flags = params->flags; | |
| 342 | 338 | break; |
| 343 | 339 | default: |
| 344 | 340 | return -EOPNOTSUPP; |
| @@ -2377,6 +2377,8 @@ static int at76_init_new_device(struct at76_priv *priv, · 2376 unmodified lines | ||
| 2377 | 2377 | |
| 2378 | 2378 | wiphy->hw_version = priv->board_type; |
| 2379 | 2379 | |
| 2380 | + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 2381 | + | |
| 2380 | 2382 | ret = ieee80211_register_hw(priv->hw); |
| 2381 | 2383 | if (ret) { |
| 2382 | 2384 | printk(KERN_ERR "cannot register mac80211 hw (status %d)!\n", |
| @@ -5598,6 +5598,8 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) · 5597 unmodified lines | ||
| 5598 | 5598 | |
| 5599 | 5599 | hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; |
| 5600 | 5600 | |
| 5601 | + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 5602 | + | |
| 5601 | 5603 | wl->hw_registred = false; |
| 5602 | 5604 | hw->max_rates = 2; |
| 5603 | 5605 | SET_IEEE80211_DEV(hw, dev->dev); |
| @@ -3850,6 +3850,8 @@ static int b43legacy_wireless_init(struct ssb_device *dev) · 3849 unmodified lines | ||
| 3850 | 3850 | else |
| 3851 | 3851 | SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac); |
| 3852 | 3852 | |
| 3853 | + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 3854 | + | |
| 3853 | 3855 | /* Get and initialize struct b43legacy_wl */ |
| 3854 | 3856 | wl = hw_to_b43legacy_wl(hw); |
| 3855 | 3857 | memset(wl, 0, sizeof(*wl)); |
| @@ -575,12 +575,11 @@ static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp) · 574 unmodified lines | ||
| 575 | 575 | * |
| 576 | 576 | * @wiphy: wiphy device of new interface. |
| 577 | 577 | * @name: name of the new interface. |
| 578 | − * @flags: not used. | |
| 579 | 578 | * @params: contains mac address for AP device. |
| 580 | 579 | */ |
| 581 | 580 | static |
| 582 | 581 | struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name, |
| 583 | − u32 *flags, struct vif_params *params) | |
| 582 | + struct vif_params *params) | |
| 584 | 583 | { |
| 585 | 584 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); |
| 586 | 585 | struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); |
| @@ -653,7 +652,6 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, · 66 unmodified lines | ||
| 653 | 652 | const char *name, |
| 654 | 653 | unsigned char name_assign_type, |
| 655 | 654 | enum nl80211_iftype type, |
| 656 | − u32 *flags, | |
| 657 | 655 | struct vif_params *params) |
| 658 | 656 | { |
| 659 | 657 | struct wireless_dev *wdev; |
| @@ -674,12 +672,12 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, · 14 unmodified lines | ||
| 674 | 672 | case NL80211_IFTYPE_MESH_POINT: |
| 675 | 673 | return ERR_PTR(-EOPNOTSUPP); |
| 676 | 674 | case NL80211_IFTYPE_AP: |
| 677 | − wdev = brcmf_ap_add_vif(wiphy, name, flags, params); | |
| 675 | + wdev = brcmf_ap_add_vif(wiphy, name, params); | |
| 678 | 676 | break; |
| 679 | 677 | case NL80211_IFTYPE_P2P_CLIENT: |
| 680 | 678 | case NL80211_IFTYPE_P2P_GO: |
| 681 | 679 | case NL80211_IFTYPE_P2P_DEVICE: |
| 682 | − wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params); | |
| 680 | + wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, params); | |
| 683 | 681 | break; |
| 684 | 682 | case NL80211_IFTYPE_UNSPECIFIED: |
| 685 | 683 | default: |
| @@ -858,7 +856,7 @@ int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) · 172 unmodified lines | ||
| 858 | 856 | |
| 859 | 857 | static s32 |
| 860 | 858 | brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, |
| 861 | − enum nl80211_iftype type, u32 *flags, | |
| 859 | + enum nl80211_iftype type, | |
| 862 | 860 | struct vif_params *params) |
| 863 | 861 | { |
| 864 | 862 | struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); |
| @@ -6553,7 +6551,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg) · 5688 unmodified lines | ||
| 6553 | 6551 | if (err) |
| 6554 | 6552 | goto default_conf_out; |
| 6555 | 6553 | err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype, |
| 6556 | − NULL, NULL); | |
| 6554 | + NULL); | |
| 6557 | 6555 | if (err) |
| 6558 | 6556 | goto default_conf_out; |
| 6559 | 6557 | |
| @@ -2141,12 +2141,11 @@ fail: · 2140 unmodified lines | ||
| 2141 | 2141 | * @name: name of the new interface. |
| 2142 | 2142 | * @name_assign_type: origin of the interface name |
| 2143 | 2143 | * @type: nl80211 interface type. |
| 2144 | − * @flags: not used. | |
| 2145 | 2144 | * @params: contains mac address for P2P device. |
| 2146 | 2145 | */ |
| 2147 | 2146 | struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, |
| 2148 | 2147 | unsigned char name_assign_type, |
| 2149 | − enum nl80211_iftype type, u32 *flags, | |
| 2148 | + enum nl80211_iftype type, | |
| 2150 | 2149 | struct vif_params *params) |
| 2151 | 2150 | { |
| 2152 | 2151 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); |
| @@ -150,7 +150,7 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg, bool p2pdev_forced); · 149 unmodified lines | ||
| 150 | 150 | void brcmf_p2p_detach(struct brcmf_p2p_info *p2p); |
| 151 | 151 | struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, |
| 152 | 152 | unsigned char name_assign_type, |
| 153 | − enum nl80211_iftype type, u32 *flags, | |
| 153 | + enum nl80211_iftype type, | |
| 154 | 154 | struct vif_params *params); |
| 155 | 155 | int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev); |
| 156 | 156 | int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg, |
| @@ -1082,6 +1082,8 @@ static int ieee_hw_init(struct ieee80211_hw *hw) · 1081 unmodified lines | ||
| 1082 | 1082 | * hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; |
| 1083 | 1083 | */ |
| 1084 | 1084 | |
| 1085 | + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 1086 | + | |
| 1085 | 1087 | hw->rate_control_algorithm = "minstrel_ht"; |
| 1086 | 1088 | |
| 1087 | 1089 | hw->sta_data_size = 0; |
| @@ -3592,6 +3592,8 @@ il3945_setup_mac(struct il_priv *il) · 3591 unmodified lines | ||
| 3592 | 3592 | |
| 3593 | 3593 | il_leds_init(il); |
| 3594 | 3594 | |
| 3595 | + wiphy_ext_feature_set(il->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 3596 | + | |
| 3595 | 3597 | ret = ieee80211_register_hw(il->hw); |
| 3596 | 3598 | if (ret) { |
| 3597 | 3599 | IL_ERR("Failed to register hw (error %d)\n", ret); |
| @@ -656,7 +656,7 @@ il3945_rs_get_rate(void *il_r, struct ieee80211_sta *sta, void *il_sta, · 655 unmodified lines | ||
| 656 | 656 | rate_mask = sta->supp_rates[sband->band]; |
| 657 | 657 | |
| 658 | 658 | /* get user max rate if set */ |
| 659 | − max_rate_idx = txrc->max_rate_idx; | |
| 659 | + max_rate_idx = fls(txrc->rate_idx_mask) - 1; | |
| 660 | 660 | if (sband->band == NL80211_BAND_5GHZ && max_rate_idx != -1) |
| 661 | 661 | max_rate_idx += IL_FIRST_OFDM_RATE; |
| 662 | 662 | if (max_rate_idx < 0 || max_rate_idx >= RATE_COUNT) |
| @@ -5799,6 +5799,8 @@ il4965_mac_setup_register(struct il_priv *il, u32 max_probe_length) · 5798 unmodified lines | ||
| 5799 | 5799 | |
| 5800 | 5800 | il_leds_init(il); |
| 5801 | 5801 | |
| 5802 | + wiphy_ext_feature_set(il->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 5803 | + | |
| 5802 | 5804 | ret = ieee80211_register_hw(il->hw); |
| 5803 | 5805 | if (ret) { |
| 5804 | 5806 | IL_ERR("Failed to register hw (error %d)\n", ret); |
| @@ -2211,7 +2211,7 @@ il4965_rs_get_rate(void *il_r, struct ieee80211_sta *sta, void *il_sta, · 2210 unmodified lines | ||
| 2211 | 2211 | |
| 2212 | 2212 | /* Get max rate if user set max rate */ |
| 2213 | 2213 | if (lq_sta) { |
| 2214 | − lq_sta->max_rate_idx = txrc->max_rate_idx; | |
| 2214 | + lq_sta->max_rate_idx = fls(txrc->rate_idx_mask) - 1; | |
| 2215 | 2215 | if (sband->band == NL80211_BAND_5GHZ && |
| 2216 | 2216 | lq_sta->max_rate_idx != -1) |
| 2217 | 2217 | lq_sta->max_rate_idx += IL_FIRST_OFDM_RATE; |
| @@ -213,6 +213,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, · 212 unmodified lines | ||
| 213 | 213 | |
| 214 | 214 | iwl_leds_init(priv); |
| 215 | 215 | |
| 216 | + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 217 | + | |
| 216 | 218 | ret = ieee80211_register_hw(priv->hw); |
| 217 | 219 | if (ret) { |
| 218 | 220 | IWL_ERR(priv, "Failed to register hw (error %d)\n", ret); |
| @@ -2720,7 +2720,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, · 2719 unmodified lines | ||
| 2720 | 2720 | |
| 2721 | 2721 | /* Get max rate if user set max rate */ |
| 2722 | 2722 | if (lq_sta) { |
| 2723 | − lq_sta->max_rate_idx = txrc->max_rate_idx; | |
| 2723 | + lq_sta->max_rate_idx = fls(txrc->rate_idx_mask) - 1; | |
| 2724 | 2724 | if ((sband->band == NL80211_BAND_5GHZ) && |
| 2725 | 2725 | (lq_sta->max_rate_idx != -1)) |
| 2726 | 2726 | lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE; |
| @@ -97,7 +97,7 @@ int orinoco_wiphy_register(struct wiphy *wiphy) · 96 unmodified lines | ||
| 97 | 97 | } |
| 98 | 98 | |
| 99 | 99 | static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, |
| 100 | − enum nl80211_iftype type, u32 *flags, | |
| 100 | + enum nl80211_iftype type, | |
| 101 | 101 | struct vif_params *params) |
| 102 | 102 | { |
| 103 | 103 | struct orinoco_private *priv = wiphy_priv(wiphy); |
| @@ -350,6 +350,7 @@ static const struct ieee80211_channel hwsim_channels_5ghz[] = { · 349 unmodified lines | ||
| 350 | 350 | CHAN5G(5785), /* Channel 157 */ |
| 351 | 351 | CHAN5G(5805), /* Channel 161 */ |
| 352 | 352 | CHAN5G(5825), /* Channel 165 */ |
| 353 | + CHAN5G(5845), /* Channel 169 */ | |
| 353 | 354 | }; |
| 354 | 355 | |
| 355 | 356 | static const struct ieee80211_rate hwsim_rates[] = { |
| @@ -525,6 +526,11 @@ struct mac80211_hwsim_data { · 169 unmodified lines | ||
| 525 | 526 | struct ieee80211_vif *hw_scan_vif; |
| 526 | 527 | int scan_chan_idx; |
| 527 | 528 | u8 scan_addr[ETH_ALEN]; |
| 529 | + struct { | |
| 530 | + struct ieee80211_channel *channel; | |
| 531 | + unsigned long next_start, start, end; | |
| 532 | + } survey_data[ARRAY_SIZE(hwsim_channels_2ghz) + | |
| 533 | + ARRAY_SIZE(hwsim_channels_5ghz)]; | |
| 528 | 534 | |
| 529 | 535 | struct ieee80211_channel *channel; |
| 530 | 536 | u64 beacon_int /* beacon interval in us */; |
| @@ -552,8 +558,6 @@ struct mac80211_hwsim_data { · 21 unmodified lines | ||
| 552 | 558 | /* wmediumd portid responsible for netgroup of this radio */ |
| 553 | 559 | u32 wmediumd; |
| 554 | 560 | |
| 555 | − int power_level; | |
| 556 | − | |
| 557 | 561 | /* difference between this hw's clock and the real clock, in usecs */ |
| 558 | 562 | s64 tsf_offset; |
| 559 | 563 | s64 bcn_delta; |
| @@ -1201,7 +1205,9 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, · 641 unmodified lines | ||
| 1201 | 1205 | if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) |
| 1202 | 1206 | rx_status.flag |= RX_FLAG_SHORT_GI; |
| 1203 | 1207 | /* TODO: simulate real signal strength (and optional packet loss) */ |
| 1204 | − rx_status.signal = data->power_level - 50; | |
| 1208 | + rx_status.signal = -50; | |
| 1209 | + if (info->control.vif) | |
| 1210 | + rx_status.signal += info->control.vif->bss_conf.txpower; | |
| 1205 | 1211 | |
| 1206 | 1212 | if (data->ps != PS_DISABLED) |
| 1207 | 1213 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); |
| @@ -1576,6 +1582,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) · 368 unmodified lines | ||
| 1576 | 1582 | [IEEE80211_SMPS_STATIC] = "static", |
| 1577 | 1583 | [IEEE80211_SMPS_DYNAMIC] = "dynamic", |
| 1578 | 1584 | }; |
| 1585 | + int idx; | |
| 1579 | 1586 | |
| 1580 | 1587 | if (conf->chandef.chan) |
| 1581 | 1588 | wiphy_debug(hw->wiphy, |
| @@ -1598,11 +1605,34 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) · 16 unmodified lines | ||
| 1598 | 1605 | |
| 1599 | 1606 | data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); |
| 1600 | 1607 | |
| 1601 | − data->channel = conf->chandef.chan; | |
| 1608 | + WARN_ON(conf->chandef.chan && data->use_chanctx); | |
| 1609 | + | |
| 1610 | + mutex_lock(&data->mutex); | |
| 1611 | + if (data->scanning && conf->chandef.chan) { | |
| 1612 | + for (idx = 0; idx < ARRAY_SIZE(data->survey_data); idx++) { | |
| 1613 | + if (data->survey_data[idx].channel == data->channel) { | |
| 1614 | + data->survey_data[idx].start = | |
| 1615 | + data->survey_data[idx].next_start; | |
| 1616 | + data->survey_data[idx].end = jiffies; | |
| 1617 | + break; | |
| 1618 | + } | |
| 1619 | + } | |
| 1602 | 1620 | |
| 1603 | − WARN_ON(data->channel && data->use_chanctx); | |
| 1621 | + data->channel = conf->chandef.chan; | |
| 1622 | + | |
| 1623 | + for (idx = 0; idx < ARRAY_SIZE(data->survey_data); idx++) { | |
| 1624 | + if (data->survey_data[idx].channel && | |
| 1625 | + data->survey_data[idx].channel != data->channel) | |
| 1626 | + continue; | |
| 1627 | + data->survey_data[idx].channel = data->channel; | |
| 1628 | + data->survey_data[idx].next_start = jiffies; | |
| 1629 | + break; | |
| 1630 | + } | |
| 1631 | + } else { | |
| 1632 | + data->channel = conf->chandef.chan; | |
| 1633 | + } | |
| 1634 | + mutex_unlock(&data->mutex); | |
| 1604 | 1635 | |
| 1605 | − data->power_level = conf->power_level; | |
| 1606 | 1636 | if (!data->started || !data->beacon_int) |
| 1607 | 1637 | tasklet_hrtimer_cancel(&data->beacon_timer); |
| 1608 | 1638 | else if (!hrtimer_is_queued(&data->beacon_timer.timer)) { |
| @@ -1787,28 +1817,37 @@ static int mac80211_hwsim_conf_tx( · 178 unmodified lines | ||
| 1787 | 1817 | return 0; |
| 1788 | 1818 | } |
| 1789 | 1819 | |
| 1790 | −static int mac80211_hwsim_get_survey( | |
| 1791 | − struct ieee80211_hw *hw, int idx, | |
| 1792 | − struct survey_info *survey) | |
| 1820 | +static int mac80211_hwsim_get_survey(struct ieee80211_hw *hw, int idx, | |
| 1821 | + struct survey_info *survey) | |
| 1793 | 1822 | { |
| 1794 | − struct ieee80211_conf *conf = &hw->conf; | |
| 1795 | − | |
| 1796 | − wiphy_debug(hw->wiphy, "%s (idx=%d)\n", __func__, idx); | |
| 1823 | + struct mac80211_hwsim_data *hwsim = hw->priv; | |
| 1797 | 1824 | |
| 1798 | − if (idx != 0) | |
| 1825 | + if (idx < 0 || idx >= ARRAY_SIZE(hwsim->survey_data)) | |
| 1799 | 1826 | return -ENOENT; |
| 1800 | 1827 | |
| 1801 | − /* Current channel */ | |
| 1802 | − survey->channel = conf->chandef.chan; | |
| 1828 | + mutex_lock(&hwsim->mutex); | |
| 1829 | + survey->channel = hwsim->survey_data[idx].channel; | |
| 1830 | + if (!survey->channel) { | |
| 1831 | + mutex_unlock(&hwsim->mutex); | |
| 1832 | + return -ENOENT; | |
| 1833 | + } | |
| 1803 | 1834 | |
| 1804 | 1835 | /* |
| 1805 | − * Magically conjured noise level --- this is only ok for simulated hardware. | |
| 1836 | + * Magically conjured dummy values --- this is only ok for simulated hardware. | |
| 1806 | 1837 | * |
| 1807 | − * A real driver which cannot determine the real channel noise MUST NOT | |
| 1808 | − * report any noise, especially not a magically conjured one :-) | |
| 1838 | + * A real driver which cannot determine real values noise MUST NOT | |
| 1839 | + * report any, especially not a magically conjured ones :-) | |
| 1809 | 1840 | */ |
| 1810 | − survey->filled = SURVEY_INFO_NOISE_DBM; | |
| 1841 | + survey->filled = SURVEY_INFO_NOISE_DBM | | |
| 1842 | + SURVEY_INFO_TIME | | |
| 1843 | + SURVEY_INFO_TIME_BUSY; | |
| 1811 | 1844 | survey->noise = -92; |
| 1845 | + survey->time = | |
| 1846 | + jiffies_to_msecs(hwsim->survey_data[idx].end - | |
| 1847 | + hwsim->survey_data[idx].start); | |
| 1848 | + /* report 12.5% of channel time is used */ | |
| 1849 | + survey->time_busy = survey->time/8; | |
| 1850 | + mutex_unlock(&hwsim->mutex); | |
| 1812 | 1851 | |
| 1813 | 1852 | return 0; |
| 1814 | 1853 | } |
| @@ -1986,6 +2025,10 @@ static void hw_scan_work(struct work_struct *work) · 171 unmodified lines | ||
| 1986 | 2025 | } |
| 1987 | 2026 | ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, |
| 1988 | 2027 | msecs_to_jiffies(dwell)); |
| 2028 | + hwsim->survey_data[hwsim->scan_chan_idx].channel = hwsim->tmp_chan; | |
| 2029 | + hwsim->survey_data[hwsim->scan_chan_idx].start = jiffies; | |
| 2030 | + hwsim->survey_data[hwsim->scan_chan_idx].end = | |
| 2031 | + jiffies + msecs_to_jiffies(dwell); | |
| 1989 | 2032 | hwsim->scan_chan_idx++; |
| 1990 | 2033 | mutex_unlock(&hwsim->mutex); |
| 1991 | 2034 | } |
| @@ -2011,6 +2054,7 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw, · 19 unmodified lines | ||
| 2011 | 2054 | hw_req->req.mac_addr_mask); |
| 2012 | 2055 | else |
| 2013 | 2056 | memcpy(hwsim->scan_addr, vif->addr, ETH_ALEN); |
| 2057 | + memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data)); | |
| 2014 | 2058 | mutex_unlock(&hwsim->mutex); |
| 2015 | 2059 | |
| 2016 | 2060 | wiphy_debug(hw->wiphy, "hwsim hw_scan request\n"); |
| @@ -2057,6 +2101,7 @@ static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw, · 40 unmodified lines | ||
| 2057 | 2101 | |
| 2058 | 2102 | memcpy(hwsim->scan_addr, mac_addr, ETH_ALEN); |
| 2059 | 2103 | hwsim->scanning = true; |
| 2104 | + memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data)); | |
| 2060 | 2105 | |
| 2061 | 2106 | out: |
| 2062 | 2107 | mutex_unlock(&hwsim->mutex); |
| @@ -2207,7 +2252,6 @@ static const char mac80211_hwsim_gstrings_stats[][ETH_GSTRING_LEN] = { · 144 unmodified lines | ||
| 2207 | 2252 | "d_tx_failed", |
| 2208 | 2253 | "d_ps_mode", |
| 2209 | 2254 | "d_group", |
| 2210 | − "d_tx_power", | |
| 2211 | 2255 | }; |
| 2212 | 2256 | |
| 2213 | 2257 | #define MAC80211_HWSIM_SSTATS_LEN ARRAY_SIZE(mac80211_hwsim_gstrings_stats) |
| @@ -2244,7 +2288,6 @@ static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw, · 30 unmodified lines | ||
| 2244 | 2288 | data[i++] = ar->tx_failed; |
| 2245 | 2289 | data[i++] = ar->ps; |
| 2246 | 2290 | data[i++] = ar->group; |
| 2247 | − data[i++] = ar->power_level; | |
| 2248 | 2291 | |
| 2249 | 2292 | WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN); |
| 2250 | 2293 | } |
| @@ -2438,6 +2481,9 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, · 187 unmodified lines | ||
| 2438 | 2481 | goto failed; |
| 2439 | 2482 | } |
| 2440 | 2483 | |
| 2484 | + /* ieee80211_alloc_hw_nm may have used a default name */ | |
| 2485 | + param->hwname = wiphy_name(hw->wiphy); | |
| 2486 | + | |
| 2441 | 2487 | if (info) |
| 2442 | 2488 | net = genl_info_net(info); |
| 2443 | 2489 | else |
| @@ -2645,6 +2691,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, · 201 unmodified lines | ||
| 2645 | 2691 | if (param->no_vif) |
| 2646 | 2692 | ieee80211_hw_set(hw, NO_AUTO_VIF); |
| 2647 | 2693 | |
| 2694 | + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 2695 | + | |
| 2648 | 2696 | err = ieee80211_register_hw(hw); |
| 2649 | 2697 | if (err < 0) { |
| 2650 | 2698 | printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n", |
| @@ -57,12 +57,12 @@ enum hwsim_tx_control_flags { · 56 unmodified lines | ||
| 57 | 57 | * @HWSIM_CMD_REGISTER: request to register and received all broadcasted |
| 58 | 58 | * frames by any mac80211_hwsim radio device. |
| 59 | 59 | * @HWSIM_CMD_FRAME: send/receive a broadcasted frame from/to kernel/user |
| 60 | − * space, uses: | |
| 60 | + * space, uses: | |
| 61 | 61 | * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_ADDR_RECEIVER, |
| 62 | 62 | * %HWSIM_ATTR_FRAME, %HWSIM_ATTR_FLAGS, %HWSIM_ATTR_RX_RATE, |
| 63 | 63 | * %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE, %HWSIM_ATTR_FREQ (optional) |
| 64 | 64 | * @HWSIM_CMD_TX_INFO_FRAME: Transmission info report from user space to |
| 65 | − * kernel, uses: | |
| 65 | + * kernel, uses: | |
| 66 | 66 | * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS, |
| 67 | 67 | * %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE |
| 68 | 68 | * @HWSIM_CMD_NEW_RADIO: create a new radio with the given parameters, |
| @@ -1657,7 +1657,7 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev, · 1656 unmodified lines | ||
| 1657 | 1657 | */ |
| 1658 | 1658 | |
| 1659 | 1659 | static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev, |
| 1660 | − enum nl80211_iftype type, u32 *flags, | |
| 1660 | + enum nl80211_iftype type, | |
| 1661 | 1661 | struct vif_params *params) |
| 1662 | 1662 | { |
| 1663 | 1663 | struct lbs_private *priv = wiphy_priv(wiphy); |
| @@ -641,6 +641,8 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev) · 640 unmodified lines | ||
| 641 | 641 | BIT(NL80211_IFTYPE_ADHOC); |
| 642 | 642 | skb_queue_head_init(&priv->bc_ps_buf); |
| 643 | 643 | |
| 644 | + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 645 | + | |
| 644 | 646 | SET_IEEE80211_DEV(hw, dmdev); |
| 645 | 647 | |
| 646 | 648 | INIT_WORK(&priv->cmd_work, lbtf_cmd_work); |
| @@ -935,7 +935,7 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, · 934 unmodified lines | ||
| 935 | 935 | static int |
| 936 | 936 | mwifiex_change_vif_to_p2p(struct net_device *dev, |
| 937 | 937 | enum nl80211_iftype curr_iftype, |
| 938 | − enum nl80211_iftype type, u32 *flags, | |
| 938 | + enum nl80211_iftype type, | |
| 939 | 939 | struct vif_params *params) |
| 940 | 940 | { |
| 941 | 941 | struct mwifiex_private *priv; |
| @@ -1007,7 +1007,7 @@ mwifiex_change_vif_to_p2p(struct net_device *dev, · 65 unmodified lines | ||
| 1007 | 1007 | static int |
| 1008 | 1008 | mwifiex_change_vif_to_sta_adhoc(struct net_device *dev, |
| 1009 | 1009 | enum nl80211_iftype curr_iftype, |
| 1010 | − enum nl80211_iftype type, u32 *flags, | |
| 1010 | + enum nl80211_iftype type, | |
| 1011 | 1011 | struct vif_params *params) |
| 1012 | 1012 | { |
| 1013 | 1013 | struct mwifiex_private *priv; |
| @@ -1066,7 +1066,7 @@ mwifiex_change_vif_to_sta_adhoc(struct net_device *dev, · 52 unmodified lines | ||
| 1066 | 1066 | static int |
| 1067 | 1067 | mwifiex_change_vif_to_ap(struct net_device *dev, |
| 1068 | 1068 | enum nl80211_iftype curr_iftype, |
| 1069 | − enum nl80211_iftype type, u32 *flags, | |
| 1069 | + enum nl80211_iftype type, | |
| 1070 | 1070 | struct vif_params *params) |
| 1071 | 1071 | { |
| 1072 | 1072 | struct mwifiex_private *priv; |
| @@ -1122,7 +1122,7 @@ mwifiex_change_vif_to_ap(struct net_device *dev, · 49 unmodified lines | ||
| 1122 | 1122 | static int |
| 1123 | 1123 | mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, |
| 1124 | 1124 | struct net_device *dev, |
| 1125 | − enum nl80211_iftype type, u32 *flags, | |
| 1125 | + enum nl80211_iftype type, | |
| 1126 | 1126 | struct vif_params *params) |
| 1127 | 1127 | { |
| 1128 | 1128 | struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); |
| @@ -1143,10 +1143,10 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, · 14 unmodified lines | ||
| 1143 | 1143 | case NL80211_IFTYPE_P2P_CLIENT: |
| 1144 | 1144 | case NL80211_IFTYPE_P2P_GO: |
| 1145 | 1145 | return mwifiex_change_vif_to_p2p(dev, curr_iftype, |
| 1146 | − type, flags, params); | |
| 1146 | + type, params); | |
| 1147 | 1147 | case NL80211_IFTYPE_AP: |
| 1148 | 1148 | return mwifiex_change_vif_to_ap(dev, curr_iftype, type, |
| 1149 | − flags, params); | |
| 1149 | + params); | |
| 1150 | 1150 | case NL80211_IFTYPE_UNSPECIFIED: |
| 1151 | 1151 | mwifiex_dbg(priv->adapter, INFO, |
| 1152 | 1152 | "%s: kept type as IBSS\n", dev->name); |
| @@ -1173,10 +1173,10 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, · 20 unmodified lines | ||
| 1173 | 1173 | case NL80211_IFTYPE_P2P_CLIENT: |
| 1174 | 1174 | case NL80211_IFTYPE_P2P_GO: |
| 1175 | 1175 | return mwifiex_change_vif_to_p2p(dev, curr_iftype, |
| 1176 | − type, flags, params); | |
| 1176 | + type, params); | |
| 1177 | 1177 | case NL80211_IFTYPE_AP: |
| 1178 | 1178 | return mwifiex_change_vif_to_ap(dev, curr_iftype, type, |
| 1179 | − flags, params); | |
| 1179 | + params); | |
| 1180 | 1180 | case NL80211_IFTYPE_UNSPECIFIED: |
| 1181 | 1181 | mwifiex_dbg(priv->adapter, INFO, |
| 1182 | 1182 | "%s: kept type as STA\n", dev->name); |
| @@ -1194,13 +1194,12 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, · 11 unmodified lines | ||
| 1194 | 1194 | case NL80211_IFTYPE_ADHOC: |
| 1195 | 1195 | case NL80211_IFTYPE_STATION: |
| 1196 | 1196 | return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype, |
| 1197 | − type, flags, | |
| 1198 | − params); | |
| 1197 | + type, params); | |
| 1199 | 1198 | break; |
| 1200 | 1199 | case NL80211_IFTYPE_P2P_CLIENT: |
| 1201 | 1200 | case NL80211_IFTYPE_P2P_GO: |
| 1202 | 1201 | return mwifiex_change_vif_to_p2p(dev, curr_iftype, |
| 1203 | − type, flags, params); | |
| 1202 | + type, params); | |
| 1204 | 1203 | case NL80211_IFTYPE_UNSPECIFIED: |
| 1205 | 1204 | mwifiex_dbg(priv->adapter, INFO, |
| 1206 | 1205 | "%s: kept type as AP\n", dev->name); |
| @@ -1233,14 +1232,13 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, · 26 unmodified lines | ||
| 1233 | 1232 | if (mwifiex_cfg80211_deinit_p2p(priv)) |
| 1234 | 1233 | return -EFAULT; |
| 1235 | 1234 | return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype, |
| 1236 | − type, flags, | |
| 1237 | − params); | |
| 1235 | + type, params); | |
| 1238 | 1236 | break; |
| 1239 | 1237 | case NL80211_IFTYPE_AP: |
| 1240 | 1238 | if (mwifiex_cfg80211_deinit_p2p(priv)) |
| 1241 | 1239 | return -EFAULT; |
| 1242 | 1240 | return mwifiex_change_vif_to_ap(dev, curr_iftype, type, |
| 1243 | − flags, params); | |
| 1241 | + params); | |
| 1244 | 1242 | case NL80211_IFTYPE_UNSPECIFIED: |
| 1245 | 1243 | mwifiex_dbg(priv->adapter, INFO, |
| 1246 | 1244 | "%s: kept type as P2P\n", dev->name); |
| @@ -2841,7 +2839,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, · 1594 unmodified lines | ||
| 2841 | 2839 | const char *name, |
| 2842 | 2840 | unsigned char name_assign_type, |
| 2843 | 2841 | enum nl80211_iftype type, |
| 2844 | − u32 *flags, | |
| 2845 | 2842 | struct vif_params *params) |
| 2846 | 2843 | { |
| 2847 | 2844 | struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); |
| @@ -596,7 +596,7 @@ static int _mwifiex_fw_dpc(const struct firmware *firmware, void *context) · 595 unmodified lines | ||
| 596 | 596 | rtnl_lock(); |
| 597 | 597 | /* Create station interface by default */ |
| 598 | 598 | wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", NET_NAME_ENUM, |
| 599 | − NL80211_IFTYPE_STATION, NULL, NULL); | |
| 599 | + NL80211_IFTYPE_STATION, NULL); | |
| 600 | 600 | if (IS_ERR(wdev)) { |
| 601 | 601 | mwifiex_dbg(adapter, ERROR, |
| 602 | 602 | "cannot create default STA interface\n"); |
| @@ -606,7 +606,7 @@ static int _mwifiex_fw_dpc(const struct firmware *firmware, void *context) · 3 unmodified lines | ||
| 606 | 606 | |
| 607 | 607 | if (driver_mode & MWIFIEX_DRIVER_MODE_UAP) { |
| 608 | 608 | wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", NET_NAME_ENUM, |
| 609 | − NL80211_IFTYPE_AP, NULL, NULL); | |
| 609 | + NL80211_IFTYPE_AP, NULL); | |
| 610 | 610 | if (IS_ERR(wdev)) { |
| 611 | 611 | mwifiex_dbg(adapter, ERROR, |
| 612 | 612 | "cannot create AP interface\n"); |
| @@ -617,8 +617,7 @@ static int _mwifiex_fw_dpc(const struct firmware *firmware, void *context) · 4 unmodified lines | ||
| 617 | 617 | |
| 618 | 618 | if (driver_mode & MWIFIEX_DRIVER_MODE_P2P) { |
| 619 | 619 | wdev = mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d", NET_NAME_ENUM, |
| 620 | − NL80211_IFTYPE_P2P_CLIENT, NULL, | |
| 621 | − NULL); | |
| 620 | + NL80211_IFTYPE_P2P_CLIENT, NULL); | |
| 622 | 621 | if (IS_ERR(wdev)) { |
| 623 | 622 | mwifiex_dbg(adapter, ERROR, |
| 624 | 623 | "cannot create p2p client interface\n"); |
| @@ -1529,7 +1529,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, · 1528 unmodified lines | ||
| 1529 | 1529 | const char *name, |
| 1530 | 1530 | unsigned char name_assign_type, |
| 1531 | 1531 | enum nl80211_iftype type, |
| 1532 | − u32 *flags, | |
| 1533 | 1532 | struct vif_params *params); |
| 1534 | 1533 | int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev); |
| 1535 | 1534 | |
| @@ -349,7 +349,7 @@ static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv, · 348 unmodified lines | ||
| 349 | 349 | chan_bw = IEEE80211_VHT_CHANWIDTH_USE_HT; |
| 350 | 350 | break; |
| 351 | 351 | } |
| 352 | − vht_oper->center_freq_seg1_idx = | |
| 352 | + vht_oper->center_freq_seg0_idx = | |
| 353 | 353 | mwifiex_get_center_freq_index(priv, BAND_AAC, |
| 354 | 354 | bss_desc->channel, |
| 355 | 355 | chan_bw); |
| @@ -6144,6 +6144,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) · 6143 unmodified lines | ||
| 6144 | 6144 | if (priv->sta_macids_supported || priv->device_info->fw_image_sta) |
| 6145 | 6145 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); |
| 6146 | 6146 | |
| 6147 | + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 6148 | + | |
| 6147 | 6149 | rc = ieee80211_register_hw(hw); |
| 6148 | 6150 | if (rc) { |
| 6149 | 6151 | wiphy_err(hw->wiphy, "Cannot register device\n"); |
| @@ -615,6 +615,8 @@ int mt7601u_register_device(struct mt7601u_dev *dev) · 614 unmodified lines | ||
| 615 | 615 | wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; |
| 616 | 616 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); |
| 617 | 617 | |
| 618 | + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 619 | + | |
| 618 | 620 | ret = mt76_init_sband_2g(dev); |
| 619 | 621 | if (ret) |
| 620 | 622 | return ret; |
| @@ -1456,6 +1456,9 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) · 1455 unmodified lines | ||
| 1456 | 1456 | |
| 1457 | 1457 | rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; |
| 1458 | 1458 | |
| 1459 | + wiphy_ext_feature_set(rt2x00dev->hw->wiphy, | |
| 1460 | + NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 1461 | + | |
| 1459 | 1462 | /* |
| 1460 | 1463 | * Initialize ieee80211 structure. |
| 1461 | 1464 | */ |
| @@ -1877,6 +1877,8 @@ static int rtl8180_probe(struct pci_dev *pdev, · 1876 unmodified lines | ||
| 1877 | 1877 | else |
| 1878 | 1878 | ieee80211_hw_set(dev, SIGNAL_UNSPEC); |
| 1879 | 1879 | |
| 1880 | + wiphy_ext_feature_set(dev->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 1881 | + | |
| 1880 | 1882 | rtl8180_eeprom_read(priv); |
| 1881 | 1883 | |
| 1882 | 1884 | switch (priv->rf_type) { |
| @@ -1607,6 +1607,8 @@ static int rtl8187_probe(struct usb_interface *intf, · 1606 unmodified lines | ||
| 1607 | 1607 | dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | |
| 1608 | 1608 | BIT(NL80211_IFTYPE_ADHOC) ; |
| 1609 | 1609 | |
| 1610 | + wiphy_ext_feature_set(dev->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 1611 | + | |
| 1610 | 1612 | if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) |
| 1611 | 1613 | printk(KERN_INFO "rtl8187: inconsistency between id with OEM" |
| 1612 | 1614 | " info!\n"); |
| @@ -6135,6 +6135,8 @@ static int rtl8xxxu_probe(struct usb_interface *interface, · 6134 unmodified lines | ||
| 6135 | 6135 | ieee80211_hw_set(hw, HAS_RATE_CONTROL); |
| 6136 | 6136 | ieee80211_hw_set(hw, AMPDU_AGGREGATION); |
| 6137 | 6137 | |
| 6138 | + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 6139 | + | |
| 6138 | 6140 | ret = ieee80211_register_hw(priv->hw); |
| 6139 | 6141 | if (ret) { |
| 6140 | 6142 | dev_err(&udev->dev, "%s: Failed to register: %i\n", |
| @@ -479,7 +479,7 @@ struct rndis_wlan_private { · 478 unmodified lines | ||
| 479 | 479 | */ |
| 480 | 480 | static int rndis_change_virtual_intf(struct wiphy *wiphy, |
| 481 | 481 | struct net_device *dev, |
| 482 | − enum nl80211_iftype type, u32 *flags, | |
| 482 | + enum nl80211_iftype type, | |
| 483 | 483 | struct vif_params *params); |
| 484 | 484 | |
| 485 | 485 | static int rndis_scan(struct wiphy *wiphy, |
| @@ -1857,7 +1857,7 @@ error: · 1371 unmodified lines | ||
| 1857 | 1857 | */ |
| 1858 | 1858 | static int rndis_change_virtual_intf(struct wiphy *wiphy, |
| 1859 | 1859 | struct net_device *dev, |
| 1860 | − enum nl80211_iftype type, u32 *flags, | |
| 1860 | + enum nl80211_iftype type, | |
| 1861 | 1861 | struct vif_params *params) |
| 1862 | 1862 | { |
| 1863 | 1863 | struct rndis_wlan_private *priv = wiphy_priv(wiphy); |
| @@ -1261,6 +1261,8 @@ int rsi_mac80211_attach(struct rsi_common *common) · 1260 unmodified lines | ||
| 1261 | 1261 | |
| 1262 | 1262 | wiphy->reg_notifier = rsi_reg_notify; |
| 1263 | 1263 | |
| 1264 | + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 1265 | + | |
| 1264 | 1266 | status = ieee80211_register_hw(hw); |
| 1265 | 1267 | if (status) |
| 1266 | 1268 | return status; |
| @@ -1408,6 +1408,8 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) · 1407 unmodified lines | ||
| 1408 | 1408 | BIT(NL80211_IFTYPE_ADHOC) | |
| 1409 | 1409 | BIT(NL80211_IFTYPE_AP); |
| 1410 | 1410 | |
| 1411 | + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); | |
| 1412 | + | |
| 1411 | 1413 | hw->max_signal = 100; |
| 1412 | 1414 | hw->queues = 1; |
| 1413 | 1415 | hw->extra_tx_headroom = sizeof(struct zd_ctrlset); |
| @@ -1837,7 +1837,7 @@ static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, · 1836 unmodified lines | ||
| 1837 | 1837 | } |
| 1838 | 1838 | |
| 1839 | 1839 | static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, |
| 1840 | − enum nl80211_iftype type, u32 *flags, struct vif_params *params) | |
| 1840 | + enum nl80211_iftype type, struct vif_params *params) | |
| 1841 | 1841 | { |
| 1842 | 1842 | struct wilc_priv *priv; |
| 1843 | 1843 | struct wilc_vif *vif; |
| @@ -2099,7 +2099,6 @@ static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy, · 255 unmodified lines | ||
| 2099 | 2099 | const char *name, |
| 2100 | 2100 | unsigned char name_assign_type, |
| 2101 | 2101 | enum nl80211_iftype type, |
| 2102 | − u32 *flags, | |
| 2103 | 2102 | struct vif_params *params) |
| 2104 | 2103 | { |
| 2105 | 2104 | struct wilc_vif *vif; |
| @@ -100,7 +100,7 @@ static int prism2_domibset_pstr32(struct wlandevice *wlandev, · 99 unmodified lines | ||
| 100 | 100 | /* The interface functions, called by the cfg80211 layer */ |
| 101 | 101 | static int prism2_change_virtual_intf(struct wiphy *wiphy, |
| 102 | 102 | struct net_device *dev, |
| 103 | − enum nl80211_iftype type, u32 *flags, | |
| 103 | + enum nl80211_iftype type, | |
| 104 | 104 | struct vif_params *params) |
| 105 | 105 | { |
| 106 | 106 | struct wlandevice *wlandev = dev->ml_priv; |
| @@ -1411,6 +1411,8 @@ struct ieee80211_ht_operation { · 1410 unmodified lines | ||
| 1411 | 1411 | #define IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED 3 |
| 1412 | 1412 | #define IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT 0x0004 |
| 1413 | 1413 | #define IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT 0x0010 |
| 1414 | +#define IEEE80211_HT_OP_MODE_CCFS2_SHIFT 5 | |
| 1415 | +#define IEEE80211_HT_OP_MODE_CCFS2_MASK 0x1fe0 | |
| 1414 | 1416 | |
| 1415 | 1417 | /* for stbc_param */ |
| 1416 | 1418 | #define IEEE80211_HT_STBC_PARAM_DUAL_BEACON 0x0040 |
| @@ -1525,14 +1527,14 @@ enum ieee80211_vht_chanwidth { · 108 unmodified lines | ||
| 1525 | 1527 | * This structure is the "VHT operation element" as |
| 1526 | 1528 | * described in 802.11ac D3.0 8.4.2.161 |
| 1527 | 1529 | * @chan_width: Operating channel width |
| 1530 | + * @center_freq_seg0_idx: center freq segment 0 index | |
| 1528 | 1531 | * @center_freq_seg1_idx: center freq segment 1 index |
| 1529 | − * @center_freq_seg2_idx: center freq segment 2 index | |
| 1530 | 1532 | * @basic_mcs_set: VHT Basic MCS rate set |
| 1531 | 1533 | */ |
| 1532 | 1534 | struct ieee80211_vht_operation { |
| 1533 | 1535 | u8 chan_width; |
| 1536 | + u8 center_freq_seg0_idx; | |
| 1534 | 1537 | u8 center_freq_seg1_idx; |
| 1535 | − u8 center_freq_seg2_idx; | |
| 1536 | 1538 | __le16 basic_mcs_set; |
| 1537 | 1539 | } __packed; |
| 1538 | 1540 | |
| @@ -1721,6 +1723,9 @@ enum ieee80211_statuscode { · 182 unmodified lines | ||
| 1721 | 1723 | WLAN_STATUS_REJECT_DSE_BAND = 96, |
| 1722 | 1724 | WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL = 99, |
| 1723 | 1725 | WLAN_STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT = 103, |
| 1726 | + /* 802.11ai */ | |
| 1727 | + WLAN_STATUS_FILS_AUTHENTICATION_FAILURE = 108, | |
| 1728 | + WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER = 109, | |
| 1724 | 1729 | }; |
| 1725 | 1730 | |
| 1726 | 1731 | |
| @@ -2102,6 +2107,12 @@ enum ieee80211_key_len { · 375 unmodified lines | ||
| 2102 | 2107 | #define FILS_NONCE_LEN 16 |
| 2103 | 2108 | #define FILS_MAX_KEK_LEN 64 |
| 2104 | 2109 | |
| 2110 | +#define FILS_ERP_MAX_USERNAME_LEN 16 | |
| 2111 | +#define FILS_ERP_MAX_REALM_LEN 253 | |
| 2112 | +#define FILS_ERP_MAX_RRK_LEN 64 | |
| 2113 | + | |
| 2114 | +#define PMK_MAX_LEN 48 | |
| 2115 | + | |
| 2105 | 2116 | /* Public action codes */ |
| 2106 | 2117 | enum ieee80211_pub_actioncode { |
| 2107 | 2118 | WLAN_PUB_ACTION_EXT_CHANSW_ANN = 4, |
| @@ -2347,11 +2358,16 @@ enum ieee80211_sa_query_action { · 239 unmodified lines | ||
| 2347 | 2358 | /* AKM suite selectors */ |
| 2348 | 2359 | #define WLAN_AKM_SUITE_8021X SUITE(0x000FAC, 1) |
| 2349 | 2360 | #define WLAN_AKM_SUITE_PSK SUITE(0x000FAC, 2) |
| 2361 | +#define WLAN_AKM_SUITE_FT_PSK SUITE(0x000FAC, 4) | |
| 2350 | 2362 | #define WLAN_AKM_SUITE_8021X_SHA256 SUITE(0x000FAC, 5) |
| 2351 | 2363 | #define WLAN_AKM_SUITE_PSK_SHA256 SUITE(0x000FAC, 6) |
| 2352 | 2364 | #define WLAN_AKM_SUITE_TDLS SUITE(0x000FAC, 7) |
| 2353 | 2365 | #define WLAN_AKM_SUITE_SAE SUITE(0x000FAC, 8) |
| 2354 | 2366 | #define WLAN_AKM_SUITE_FT_OVER_SAE SUITE(0x000FAC, 9) |
| 2367 | +#define WLAN_AKM_SUITE_FILS_SHA256 SUITE(0x000FAC, 14) | |
| 2368 | +#define WLAN_AKM_SUITE_FILS_SHA384 SUITE(0x000FAC, 15) | |
| 2369 | +#define WLAN_AKM_SUITE_FT_FILS_SHA256 SUITE(0x000FAC, 16) | |
| 2370 | +#define WLAN_AKM_SUITE_FT_FILS_SHA384 SUITE(0x000FAC, 17) | |
| 2355 | 2371 | |
| 2356 | 2372 | #define WLAN_MAX_KEY_LEN 32 |
| 2357 | 2373 | |
| @@ -363,6 +363,8 @@ static inline void wiphy_read_of_freq_limits(struct wiphy *wiphy) · 362 unmodified lines | ||
| 363 | 363 | |
| 364 | 364 | /** |
| 365 | 365 | * struct vif_params - describes virtual interface parameters |
| 366 | + * @flags: monitor interface flags, unchanged if 0, otherwise | |
| 367 | + * %MONITOR_FLAG_CHANGED will be set | |
| 366 | 368 | * @use_4addr: use 4-address frames |
| 367 | 369 | * @macaddr: address to use for this virtual interface. |
| 368 | 370 | * If this parameter is set to zero address the driver may |
| @@ -370,13 +372,17 @@ static inline void wiphy_read_of_freq_limits(struct wiphy *wiphy) · 1 unmodified line | ||
| 370 | 372 | * This feature is only fully supported by drivers that enable the |
| 371 | 373 | * %NL80211_FEATURE_MAC_ON_CREATE flag. Others may support creating |
| 372 | 374 | ** only p2p devices with specified MAC. |
| 373 | − * @vht_mumimo_groups: MU-MIMO groupID. used for monitoring only | |
| 374 | − * packets belonging to that MU-MIMO groupID. | |
| 375 | + * @vht_mumimo_groups: MU-MIMO groupID, used for monitoring MU-MIMO packets | |
| 376 | + * belonging to that MU-MIMO groupID; %NULL if not changed | |
| 377 | + * @vht_mumimo_follow_addr: MU-MIMO follow address, used for monitoring | |
| 378 | + * MU-MIMO packets going to the specified station; %NULL if not changed | |
| 375 | 379 | */ |
| 376 | 380 | struct vif_params { |
| 381 | + u32 flags; | |
| 377 | 382 | int use_4addr; |
| 378 | 383 | u8 macaddr[ETH_ALEN]; |
| 379 | − u8 vht_mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN]; | |
| 384 | + const u8 *vht_mumimo_groups; | |
| 385 | + const u8 *vht_mumimo_follow_addr; | |
| 380 | 386 | }; |
| 381 | 387 | |
| 382 | 388 | /** |
| @@ -1211,6 +1217,7 @@ static inline int cfg80211_get_station(struct net_device *dev, · 828 unmodified lines | ||
| 1211 | 1217 | * Monitor interface configuration flags. Note that these must be the bits |
| 1212 | 1218 | * according to the nl80211 flags. |
| 1213 | 1219 | * |
| 1220 | + * @MONITOR_FLAG_CHANGED: set if the flags were changed | |
| 1214 | 1221 | * @MONITOR_FLAG_FCSFAIL: pass frames with bad FCS |
| 1215 | 1222 | * @MONITOR_FLAG_PLCPFAIL: pass frames with bad PLCP |
| 1216 | 1223 | * @MONITOR_FLAG_CONTROL: pass control frames |
| @@ -1219,6 +1226,7 @@ static inline int cfg80211_get_station(struct net_device *dev, · 2 unmodified lines | ||
| 1219 | 1226 | * @MONITOR_FLAG_ACTIVE: active monitor, ACKs frames on its MAC address |
| 1220 | 1227 | */ |
| 1221 | 1228 | enum monitor_flags { |
| 1229 | + MONITOR_FLAG_CHANGED = 1<<__NL80211_MNTR_FLAG_INVALID, | |
| 1222 | 1230 | MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL, |
| 1223 | 1231 | MONITOR_FLAG_PLCPFAIL = 1<<NL80211_MNTR_FLAG_PLCPFAIL, |
| 1224 | 1232 | MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL, |
| @@ -1641,6 +1649,7 @@ struct cfg80211_bss_select_adjust { · 416 unmodified lines | ||
| 1641 | 1649 | /** |
| 1642 | 1650 | * struct cfg80211_sched_scan_request - scheduled scan request description |
| 1643 | 1651 | * |
| 1652 | + * @reqid: identifies this request. | |
| 1644 | 1653 | * @ssids: SSIDs to scan for (passed in the probe_reqs in active scans) |
| 1645 | 1654 | * @n_ssids: number of SSIDs |
| 1646 | 1655 | * @n_channels: total number of channels to scan |
| @@ -1685,6 +1694,7 @@ struct cfg80211_bss_select_adjust { · 38 unmodified lines | ||
| 1685 | 1694 | * comparisions. |
| 1686 | 1695 | */ |
| 1687 | 1696 | struct cfg80211_sched_scan_request { |
| 1697 | + u64 reqid; | |
| 1688 | 1698 | struct cfg80211_ssid *ssids; |
| 1689 | 1699 | int n_ssids; |
| 1690 | 1700 | u32 n_channels; |
| @@ -2073,6 +2083,19 @@ struct cfg80211_bss_selection { · 382 unmodified lines | ||
| 2073 | 2083 | * the BSSID of the current association, i.e., to the value that is |
| 2074 | 2084 | * included in the Current AP address field of the Reassociation Request |
| 2075 | 2085 | * frame. |
| 2086 | + * @fils_erp_username: EAP re-authentication protocol (ERP) username part of the | |
| 2087 | + * NAI or %NULL if not specified. This is used to construct FILS wrapped | |
| 2088 | + * data IE. | |
| 2089 | + * @fils_erp_username_len: Length of @fils_erp_username in octets. | |
| 2090 | + * @fils_erp_realm: EAP re-authentication protocol (ERP) realm part of NAI or | |
| 2091 | + * %NULL if not specified. This specifies the domain name of ER server and | |
| 2092 | + * is used to construct FILS wrapped data IE. | |
| 2093 | + * @fils_erp_realm_len: Length of @fils_erp_realm in octets. | |
| 2094 | + * @fils_erp_next_seq_num: The next sequence number to use in the FILS ERP | |
| 2095 | + * messages. This is also used to construct FILS wrapped data IE. | |
| 2096 | + * @fils_erp_rrk: ERP re-authentication Root Key (rRK) used to derive additional | |
| 2097 | + * keys in FILS or %NULL if not specified. | |
| 2098 | + * @fils_erp_rrk_len: Length of @fils_erp_rrk in octets. | |
| 2076 | 2099 | */ |
| 2077 | 2100 | struct cfg80211_connect_params { |
| 2078 | 2101 | struct ieee80211_channel *channel; |
| @@ -2098,6 +2121,13 @@ struct cfg80211_connect_params { · 19 unmodified lines | ||
| 2098 | 2121 | bool pbss; |
| 2099 | 2122 | struct cfg80211_bss_selection bss_select; |
| 2100 | 2123 | const u8 *prev_bssid; |
| 2124 | + const u8 *fils_erp_username; | |
| 2125 | + size_t fils_erp_username_len; | |
| 2126 | + const u8 *fils_erp_realm; | |
| 2127 | + size_t fils_erp_realm_len; | |
| 2128 | + u16 fils_erp_next_seq_num; | |
| 2129 | + const u8 *fils_erp_rrk; | |
| 2130 | + size_t fils_erp_rrk_len; | |
| 2101 | 2131 | }; |
| 2102 | 2132 | |
| 2103 | 2133 | /** |
| @@ -2136,12 +2166,27 @@ enum wiphy_params_flags { · 32 unmodified lines | ||
| 2136 | 2166 | * This structure is passed to the set/del_pmksa() method for PMKSA |
| 2137 | 2167 | * caching. |
| 2138 | 2168 | * |
| 2139 | − * @bssid: The AP's BSSID. | |
| 2140 | − * @pmkid: The PMK material itself. | |
| 2169 | + * @bssid: The AP's BSSID (may be %NULL). | |
| 2170 | + * @pmkid: The identifier to refer a PMKSA. | |
| 2171 | + * @pmk: The PMK for the PMKSA identified by @pmkid. This is used for key | |
| 2172 | + * derivation by a FILS STA. Otherwise, %NULL. | |
| 2173 | + * @pmk_len: Length of the @pmk. The length of @pmk can differ depending on | |
| 2174 | + * the hash algorithm used to generate this. | |
| 2175 | + * @ssid: SSID to specify the ESS within which a PMKSA is valid when using FILS | |
| 2176 | + * cache identifier (may be %NULL). | |
| 2177 | + * @ssid_len: Length of the @ssid in octets. | |
| 2178 | + * @cache_id: 2-octet cache identifier advertized by a FILS AP identifying the | |
| 2179 | + * scope of PMKSA. This is valid only if @ssid_len is non-zero (may be | |
| 2180 | + * %NULL). | |
| 2141 | 2181 | */ |
| 2142 | 2182 | struct cfg80211_pmksa { |
| 2143 | 2183 | const u8 *bssid; |
| 2144 | 2184 | const u8 *pmkid; |
| 2185 | + const u8 *pmk; | |
| 2186 | + size_t pmk_len; | |
| 2187 | + const u8 *ssid; | |
| 2188 | + size_t ssid_len; | |
| 2189 | + const u8 *cache_id; | |
| 2145 | 2190 | }; |
| 2146 | 2191 | |
| 2147 | 2192 | /** |
| @@ -2712,6 +2757,11 @@ struct cfg80211_nan_func { · 564 unmodified lines | ||
| 2712 | 2757 | * the current level is above/below the configured threshold; this may |
| 2713 | 2758 | * need some care when the configuration is changed (without first being |
| 2714 | 2759 | * disabled.) |
| 2760 | + * @set_cqm_rssi_range_config: Configure two RSSI thresholds in the | |
| 2761 | + * connection quality monitor. An event is to be sent only when the | |
| 2762 | + * signal level is found to be outside the two values. The driver should | |
| 2763 | + * set %NL80211_EXT_FEATURE_CQM_RSSI_LIST if this method is implemented. | |
| 2764 | + * If it is provided then there's no point providing @set_cqm_rssi_config. | |
| 2715 | 2765 | * @set_cqm_txe_config: Configure connection quality monitor TX error |
| 2716 | 2766 | * thresholds. |
| 2717 | 2767 | * @sched_scan_start: Tell the driver to start a scheduled scan. |
| @@ -2826,13 +2876,12 @@ struct cfg80211_ops { · 108 unmodified lines | ||
| 2826 | 2876 | const char *name, |
| 2827 | 2877 | unsigned char name_assign_type, |
| 2828 | 2878 | enum nl80211_iftype type, |
| 2829 | − u32 *flags, | |
| 2830 | 2879 | struct vif_params *params); |
| 2831 | 2880 | int (*del_virtual_intf)(struct wiphy *wiphy, |
| 2832 | 2881 | struct wireless_dev *wdev); |
| 2833 | 2882 | int (*change_virtual_intf)(struct wiphy *wiphy, |
| 2834 | 2883 | struct net_device *dev, |
| 2835 | − enum nl80211_iftype type, u32 *flags, | |
| 2884 | + enum nl80211_iftype type, | |
| 2836 | 2885 | struct vif_params *params); |
| 2837 | 2886 | |
| 2838 | 2887 | int (*add_key)(struct wiphy *wiphy, struct net_device *netdev, |
| @@ -3001,6 +3050,10 @@ struct cfg80211_ops { · 162 unmodified lines | ||
| 3001 | 3050 | struct net_device *dev, |
| 3002 | 3051 | s32 rssi_thold, u32 rssi_hyst); |
| 3003 | 3052 | |
| 3053 | + int (*set_cqm_rssi_range_config)(struct wiphy *wiphy, | |
| 3054 | + struct net_device *dev, | |
| 3055 | + s32 rssi_low, s32 rssi_high); | |
| 3056 | + | |
| 3004 | 3057 | int (*set_cqm_txe_config)(struct wiphy *wiphy, |
| 3005 | 3058 | struct net_device *dev, |
| 3006 | 3059 | u32 rate, u32 pkts, u32 intvl); |
| @@ -3871,6 +3924,7 @@ void wiphy_free(struct wiphy *wiphy); · 864 unmodified lines | ||
| 3871 | 3924 | struct cfg80211_conn; |
| 3872 | 3925 | struct cfg80211_internal_bss; |
| 3873 | 3926 | struct cfg80211_cached_keys; |
| 3927 | +struct cfg80211_cqm_config; | |
| 3874 | 3928 | |
| 3875 | 3929 | /** |
| 3876 | 3930 | * struct wireless_dev - wireless device state |
| @@ -3934,6 +3988,7 @@ struct cfg80211_cached_keys; · 57 unmodified lines | ||
| 3934 | 3988 | * @event_list: (private) list for internal event processing |
| 3935 | 3989 | * @event_lock: (private) lock for event list |
| 3936 | 3990 | * @owner_nlportid: (private) owner socket port ID |
| 3991 | + * @cqm_config: (private) nl80211 RSSI monitor state | |
| 3937 | 3992 | */ |
| 3938 | 3993 | struct wireless_dev { |
| 3939 | 3994 | struct wiphy *wiphy; |
| @@ -4002,6 +4057,8 @@ struct wireless_dev { · 62 unmodified lines | ||
| 4002 | 4057 | bool prev_bssid_valid; |
| 4003 | 4058 | } wext; |
| 4004 | 4059 | #endif |
| 4060 | + | |
| 4061 | + struct cfg80211_cqm_config *cqm_config; | |
| 4005 | 4062 | }; |
| 4006 | 4063 | |
| 4007 | 4064 | static inline u8 *wdev_address(struct wireless_dev *wdev) |
| @@ -4651,12 +4708,22 @@ cfg80211_inform_bss(struct wiphy *wiphy, · 643 unmodified lines | ||
| 4651 | 4708 | gfp); |
| 4652 | 4709 | } |
| 4653 | 4710 | |
| 4711 | +/** | |
| 4712 | + * cfg80211_get_bss - get a BSS reference | |
| 4713 | + * @wiphy: the wiphy this BSS struct belongs to | |
| 4714 | + * @channel: the channel to search on (or %NULL) | |
| 4715 | + * @bssid: the desired BSSID (or %NULL) | |
| 4716 | + * @ssid: the desired SSID (or %NULL) | |
| 4717 | + * @ssid_len: length of the SSID (or 0) | |
| 4718 | + * @bss_type: type of BSS, see &enum ieee80211_bss_type | |
| 4719 | + * @privacy: privacy filter, see &enum ieee80211_privacy | |
| 4720 | + */ | |
| 4654 | 4721 | struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, |
| 4655 | 4722 | struct ieee80211_channel *channel, |
| 4656 | 4723 | const u8 *bssid, |
| 4657 | 4724 | const u8 *ssid, size_t ssid_len, |
| 4658 | 4725 | enum ieee80211_bss_type bss_type, |
| 4659 | − enum ieee80211_privacy); | |
| 4726 | + enum ieee80211_privacy privacy); | |
| 4660 | 4727 | static inline struct cfg80211_bss * |
| 4661 | 4728 | cfg80211_get_ibss(struct wiphy *wiphy, |
| 4662 | 4729 | struct ieee80211_channel *channel, |
| @@ -5122,6 +5189,78 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) · 459 unmodified lines | ||
| 5122 | 5189 | #define CFG80211_TESTMODE_DUMP(cmd) |
| 5123 | 5190 | #endif |
| 5124 | 5191 | |
| 5192 | +/** | |
| 5193 | + * struct cfg80211_connect_resp_params - Connection response params | |
| 5194 | + * @status: Status code, %WLAN_STATUS_SUCCESS for successful connection, use | |
| 5195 | + * %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you | |
| 5196 | + * the real status code for failures. If this call is used to report a | |
| 5197 | + * failure due to a timeout (e.g., not receiving an Authentication frame | |
| 5198 | + * from the AP) instead of an explicit rejection by the AP, -1 is used to | |
| 5199 | + * indicate that this is a failure, but without a status code. | |
| 5200 | + * @timeout_reason is used to report the reason for the timeout in that | |
| 5201 | + * case. | |
| 5202 | + * @bssid: The BSSID of the AP (may be %NULL) | |
| 5203 | + * @bss: Entry of bss to which STA got connected to, can be obtained through | |
| 5204 | + * cfg80211_get_bss() (may be %NULL). Only one parameter among @bssid and | |
| 5205 | + * @bss needs to be specified. | |
| 5206 | + * @req_ie: Association request IEs (may be %NULL) | |
| 5207 | + * @req_ie_len: Association request IEs length | |
| 5208 | + * @resp_ie: Association response IEs (may be %NULL) | |
| 5209 | + * @resp_ie_len: Association response IEs length | |
| 5210 | + * @fils_kek: KEK derived from a successful FILS connection (may be %NULL) | |
| 5211 | + * @fils_kek_len: Length of @fils_kek in octets | |
| 5212 | + * @update_erp_next_seq_num: Boolean value to specify whether the value in | |
| 5213 | + * @fils_erp_next_seq_num is valid. | |
| 5214 | + * @fils_erp_next_seq_num: The next sequence number to use in ERP message in | |
| 5215 | + * FILS Authentication. This value should be specified irrespective of the | |
| 5216 | + * status for a FILS connection. | |
| 5217 | + * @pmk: A new PMK if derived from a successful FILS connection (may be %NULL). | |
| 5218 | + * @pmk_len: Length of @pmk in octets | |
| 5219 | + * @pmkid: A new PMKID if derived from a successful FILS connection or the PMKID | |
| 5220 | + * used for this FILS connection (may be %NULL). | |
| 5221 | + * @timeout_reason: Reason for connection timeout. This is used when the | |
| 5222 | + * connection fails due to a timeout instead of an explicit rejection from | |
| 5223 | + * the AP. %NL80211_TIMEOUT_UNSPECIFIED is used when the timeout reason is | |
| 5224 | + * not known. This value is used only if @status < 0 to indicate that the | |
| 5225 | + * failure is due to a timeout and not due to explicit rejection by the AP. | |
| 5226 | + * This value is ignored in other cases (@status >= 0). | |
| 5227 | + */ | |
| 5228 | +struct cfg80211_connect_resp_params { | |
| 5229 | + int status; | |
| 5230 | + const u8 *bssid; | |
| 5231 | + struct cfg80211_bss *bss; | |
| 5232 | + const u8 *req_ie; | |
| 5233 | + size_t req_ie_len; | |
| 5234 | + const u8 *resp_ie; | |
| 5235 | + size_t resp_ie_len; | |
| 5236 | + const u8 *fils_kek; | |
| 5237 | + size_t fils_kek_len; | |
| 5238 | + bool update_erp_next_seq_num; | |
| 5239 | + u16 fils_erp_next_seq_num; | |
| 5240 | + const u8 *pmk; | |
| 5241 | + size_t pmk_len; | |
| 5242 | + const u8 *pmkid; | |
| 5243 | + enum nl80211_timeout_reason timeout_reason; | |
| 5244 | +}; | |
| 5245 | + | |
| 5246 | +/** | |
| 5247 | + * cfg80211_connect_done - notify cfg80211 of connection result | |
| 5248 | + * | |
| 5249 | + * @dev: network device | |
| 5250 | + * @params: connection response parameters | |
| 5251 | + * @gfp: allocation flags | |
| 5252 | + * | |
| 5253 | + * It should be called by the underlying driver once execution of the connection | |
| 5254 | + * request from connect() has been completed. This is similar to | |
| 5255 | + * cfg80211_connect_bss(), but takes a structure pointer for connection response | |
| 5256 | + * parameters. Only one of the functions among cfg80211_connect_bss(), | |
| 5257 | + * cfg80211_connect_result(), cfg80211_connect_timeout(), | |
| 5258 | + * and cfg80211_connect_done() should be called. | |
| 5259 | + */ | |
| 5260 | +void cfg80211_connect_done(struct net_device *dev, | |
| 5261 | + struct cfg80211_connect_resp_params *params, | |
| 5262 | + gfp_t gfp); | |
| 5263 | + | |
| 5125 | 5264 | /** |
| 5126 | 5265 | * cfg80211_connect_bss - notify cfg80211 of connection result |
| 5127 | 5266 | * |
| @@ -5152,13 +5291,31 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) · 24 unmodified lines | ||
| 5152 | 5291 | * It should be called by the underlying driver once execution of the connection |
| 5153 | 5292 | * request from connect() has been completed. This is similar to |
| 5154 | 5293 | * cfg80211_connect_result(), but with the option of identifying the exact bss |
| 5155 | − * entry for the connection. Only one of these functions should be called. | |
| 5294 | + * entry for the connection. Only one of the functions among | |
| 5295 | + * cfg80211_connect_bss(), cfg80211_connect_result(), | |
| 5296 | + * cfg80211_connect_timeout(), and cfg80211_connect_done() should be called. | |
| 5156 | 5297 | */ |
| 5157 | −void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, | |
| 5158 | − struct cfg80211_bss *bss, const u8 *req_ie, | |
| 5159 | − size_t req_ie_len, const u8 *resp_ie, | |
| 5160 | − size_t resp_ie_len, int status, gfp_t gfp, | |
| 5161 | − enum nl80211_timeout_reason timeout_reason); | |
| 5298 | +static inline void | |
| 5299 | +cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, | |
| 5300 | + struct cfg80211_bss *bss, const u8 *req_ie, | |
| 5301 | + size_t req_ie_len, const u8 *resp_ie, | |
| 5302 | + size_t resp_ie_len, int status, gfp_t gfp, | |
| 5303 | + enum nl80211_timeout_reason timeout_reason) | |
| 5304 | +{ | |
| 5305 | + struct cfg80211_connect_resp_params params; | |
| 5306 | + | |
| 5307 | + memset(¶ms, 0, sizeof(params)); | |
| 5308 | + params.status = status; | |
| 5309 | + params.bssid = bssid; | |
| 5310 | + params.bss = bss; | |
| 5311 | + params.req_ie = req_ie; | |
| 5312 | + params.req_ie_len = req_ie_len; | |
| 5313 | + params.resp_ie = resp_ie; | |
| 5314 | + params.resp_ie_len = resp_ie_len; | |
| 5315 | + params.timeout_reason = timeout_reason; | |
| 5316 | + | |
| 5317 | + cfg80211_connect_done(dev, ¶ms, gfp); | |
| 5318 | +} | |
| 5162 | 5319 | |
| 5163 | 5320 | /** |
| 5164 | 5321 | * cfg80211_connect_result - notify cfg80211 of connection result |
| @@ -5177,7 +5334,8 @@ void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, · 12 unmodified lines | ||
| 5177 | 5334 | * It should be called by the underlying driver once execution of the connection |
| 5178 | 5335 | * request from connect() has been completed. This is similar to |
| 5179 | 5336 | * cfg80211_connect_bss() which allows the exact bss entry to be specified. Only |
| 5180 | − * one of these functions should be called. | |
| 5337 | + * one of the functions among cfg80211_connect_bss(), cfg80211_connect_result(), | |
| 5338 | + * cfg80211_connect_timeout(), and cfg80211_connect_done() should be called. | |
| 5181 | 5339 | */ |
| 5182 | 5340 | static inline void |
| 5183 | 5341 | cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
| @@ -5204,7 +5362,9 @@ cfg80211_connect_result(struct net_device *dev, const u8 *bssid, · 20 unmodified lines | ||
| 5204 | 5362 | * in a sequence where no explicit authentication/association rejection was |
| 5205 | 5363 | * received from the AP. This could happen, e.g., due to not being able to send |
| 5206 | 5364 | * out the Authentication or Association Request frame or timing out while |
| 5207 | − * waiting for the response. | |
| 5365 | + * waiting for the response. Only one of the functions among | |
| 5366 | + * cfg80211_connect_bss(), cfg80211_connect_result(), | |
| 5367 | + * cfg80211_connect_timeout(), and cfg80211_connect_done() should be called. | |
| 5208 | 5368 | */ |
| 5209 | 5369 | static inline void |
| 5210 | 5370 | cfg80211_connect_timeout(struct net_device *dev, const u8 *bssid, |
| @@ -501,6 +501,10 @@ struct ieee80211_mu_group_data { · 500 unmodified lines | ||
| 501 | 501 | * implies disabled. As with the cfg80211 callback, a change here should |
| 502 | 502 | * cause an event to be sent indicating where the current value is in |
| 503 | 503 | * relation to the newly configured threshold. |
| 504 | + * @cqm_rssi_low: Connection quality monitor RSSI lower threshold, a zero value | |
| 505 | + * implies disabled. This is an alternative mechanism to the single | |
| 506 | + * threshold event and can't be enabled simultaneously with it. | |
| 507 | + * @cqm_rssi_high: Connection quality monitor RSSI upper threshold. | |
| 504 | 508 | * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis |
| 505 | 509 | * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The |
| 506 | 510 | * may filter ARP queries targeted for other addresses than listed here. |
| @@ -553,6 +557,8 @@ struct ieee80211_bss_conf { · 46 unmodified lines | ||
| 553 | 557 | u16 ht_operation_mode; |
| 554 | 558 | s32 cqm_rssi_thold; |
| 555 | 559 | u32 cqm_rssi_hyst; |
| 560 | + s32 cqm_rssi_low; | |
| 561 | + s32 cqm_rssi_high; | |
| 556 | 562 | struct cfg80211_chan_def chandef; |
| 557 | 563 | struct ieee80211_mu_group_data mu_group; |
| 558 | 564 | __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; |
| @@ -5438,9 +5444,6 @@ void ieee80211_stop_rx_ba_session_offl(struct ieee80211_vif *vif, · 4879 unmodified lines | ||
| 5438 | 5444 | * RTS threshold |
| 5439 | 5445 | * @short_preamble: whether mac80211 will request short-preamble transmission |
| 5440 | 5446 | * if the selected rate supports it |
| 5441 | − * @max_rate_idx: user-requested maximum (legacy) rate | |
| 5442 | − * (deprecated; this will be removed once drivers get updated to use | |
| 5443 | − * rate_idx_mask) | |
| 5444 | 5447 | * @rate_idx_mask: user-requested (legacy) rate mask |
| 5445 | 5448 | * @rate_idx_mcs_mask: user-requested MCS rate mask (NULL if not in use) |
| 5446 | 5449 | * @bss: whether this frame is sent out in AP or IBSS mode |
| @@ -5452,7 +5455,6 @@ struct ieee80211_tx_rate_control { · 5 unmodified lines | ||
| 5452 | 5455 | struct sk_buff *skb; |
| 5453 | 5456 | struct ieee80211_tx_rate reported_rate; |
| 5454 | 5457 | bool rts, short_preamble; |
| 5455 | − u8 max_rate_idx; | |
| 5456 | 5458 | u32 rate_idx_mask; |
| 5457 | 5459 | u8 *rate_idx_mcs_mask; |
| 5458 | 5460 | bool bss; |
| @@ -172,6 +172,42 @@ · 171 unmodified lines | ||
| 172 | 172 | * Multiple such rules can be created. |
| 173 | 173 | */ |
| 174 | 174 | |
| 175 | +/** | |
| 176 | + * DOC: FILS shared key authentication offload | |
| 177 | + * | |
| 178 | + * FILS shared key authentication offload can be advertized by drivers by | |
| 179 | + * setting @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD flag. The drivers that support | |
| 180 | + * FILS shared key authentication offload should be able to construct the | |
| 181 | + * authentication and association frames for FILS shared key authentication and | |
| 182 | + * eventually do a key derivation as per IEEE 802.11ai. The below additional | |
| 183 | + * parameters should be given to driver in %NL80211_CMD_CONNECT. | |
| 184 | + * %NL80211_ATTR_FILS_ERP_USERNAME - used to construct keyname_nai | |
| 185 | + * %NL80211_ATTR_FILS_ERP_REALM - used to construct keyname_nai | |
| 186 | + * %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used to construct erp message | |
| 187 | + * %NL80211_ATTR_FILS_ERP_RRK - used to generate the rIK and rMSK | |
| 188 | + * rIK should be used to generate an authentication tag on the ERP message and | |
| 189 | + * rMSK should be used to derive a PMKSA. | |
| 190 | + * rIK, rMSK should be generated and keyname_nai, sequence number should be used | |
| 191 | + * as specified in IETF RFC 6696. | |
| 192 | + * | |
| 193 | + * When FILS shared key authentication is completed, driver needs to provide the | |
| 194 | + * below additional parameters to userspace. | |
| 195 | + * %NL80211_ATTR_FILS_KEK - used for key renewal | |
| 196 | + * %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used in further EAP-RP exchanges | |
| 197 | + * %NL80211_ATTR_PMKID - used to identify the PMKSA used/generated | |
| 198 | + * %Nl80211_ATTR_PMK - used to update PMKSA cache in userspace | |
| 199 | + * The PMKSA can be maintained in userspace persistently so that it can be used | |
| 200 | + * later after reboots or wifi turn off/on also. | |
| 201 | + * | |
| 202 | + * %NL80211_ATTR_FILS_CACHE_ID is the cache identifier advertized by a FILS | |
| 203 | + * capable AP supporting PMK caching. It specifies the scope within which the | |
| 204 | + * PMKSAs are cached in an ESS. %NL80211_CMD_SET_PMKSA and | |
| 205 | + * %NL80211_CMD_DEL_PMKSA are enhanced to allow support for PMKSA caching based | |
| 206 | + * on FILS cache identifier. Additionally %NL80211_ATTR_PMK is used with | |
| 207 | + * %NL80211_SET_PMKSA to specify the PMK corresponding to a PMKSA for driver to | |
| 208 | + * use in a FILS shared key connection with PMKSA caching. | |
| 209 | + */ | |
| 210 | + | |
| 175 | 211 | /** |
| 176 | 212 | * enum nl80211_commands - supported nl80211 commands |
| 177 | 213 | * |
| @@ -370,10 +406,18 @@ · 192 unmodified lines | ||
| 370 | 406 | * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to |
| 371 | 407 | * NL80211_CMD_GET_SURVEY and on the "scan" multicast group) |
| 372 | 408 | * |
| 373 | − * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry, using %NL80211_ATTR_MAC | |
| 374 | − * (for the BSSID) and %NL80211_ATTR_PMKID. | |
| 409 | + * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry using %NL80211_ATTR_MAC | |
| 410 | + * (for the BSSID), %NL80211_ATTR_PMKID, and optionally %NL80211_ATTR_PMK | |
| 411 | + * (PMK is used for PTKSA derivation in case of FILS shared key offload) or | |
| 412 | + * using %NL80211_ATTR_SSID, %NL80211_ATTR_FILS_CACHE_ID, | |
| 413 | + * %NL80211_ATTR_PMKID, and %NL80211_ATTR_PMK in case of FILS | |
| 414 | + * authentication where %NL80211_ATTR_FILS_CACHE_ID is the identifier | |
| 415 | + * advertized by a FILS capable AP identifying the scope of PMKSA in an | |
| 416 | + * ESS. | |
| 375 | 417 | * @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC |
| 376 | − * (for the BSSID) and %NL80211_ATTR_PMKID. | |
| 418 | + * (for the BSSID) and %NL80211_ATTR_PMKID or using %NL80211_ATTR_SSID, | |
| 419 | + * %NL80211_ATTR_FILS_CACHE_ID, and %NL80211_ATTR_PMKID in case of FILS | |
| 420 | + * authentication. | |
| 377 | 421 | * @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries. |
| 378 | 422 | * |
| 379 | 423 | * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain |
| @@ -2012,6 +2056,31 @@ enum nl80211_commands { · 1632 unmodified lines | ||
| 2012 | 2056 | * u32 attribute with an &enum nl80211_timeout_reason value. This is used, |
| 2013 | 2057 | * e.g., with %NL80211_CMD_CONNECT event. |
| 2014 | 2058 | * |
| 2059 | + * @NL80211_ATTR_FILS_ERP_USERNAME: EAP Re-authentication Protocol (ERP) | |
| 2060 | + * username part of NAI used to refer keys rRK and rIK. This is used with | |
| 2061 | + * %NL80211_CMD_CONNECT. | |
| 2062 | + * | |
| 2063 | + * @NL80211_ATTR_FILS_ERP_REALM: EAP Re-authentication Protocol (ERP) realm part | |
| 2064 | + * of NAI specifying the domain name of the ER server. This is used with | |
| 2065 | + * %NL80211_CMD_CONNECT. | |
| 2066 | + * | |
| 2067 | + * @NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM: Unsigned 16-bit ERP next sequence number | |
| 2068 | + * to use in ERP messages. This is used in generating the FILS wrapped data | |
| 2069 | + * for FILS authentication and is used with %NL80211_CMD_CONNECT. | |
| 2070 | + * | |
| 2071 | + * @NL80211_ATTR_FILS_ERP_RRK: ERP re-authentication Root Key (rRK) for the | |
| 2072 | + * NAI specified by %NL80211_ATTR_FILS_ERP_USERNAME and | |
| 2073 | + * %NL80211_ATTR_FILS_ERP_REALM. This is used for generating rIK and rMSK | |
| 2074 | + * from successful FILS authentication and is used with | |
| 2075 | + * %NL80211_CMD_CONNECT. | |
| 2076 | + * | |
| 2077 | + * @NL80211_ATTR_FILS_CACHE_ID: A 2-octet identifier advertized by a FILS AP | |
| 2078 | + * identifying the scope of PMKSAs. This is used with | |
| 2079 | + * @NL80211_CMD_SET_PMKSA and @NL80211_CMD_DEL_PMKSA. | |
| 2080 | + * | |
| 2081 | + * @NL80211_ATTR_PMK: PMK for the PMKSA identified by %NL80211_ATTR_PMKID. | |
| 2082 | + * This is used with @NL80211_CMD_SET_PMKSA. | |
| 2083 | + * | |
| 2015 | 2084 | * @NUM_NL80211_ATTR: total number of nl80211_attrs available |
| 2016 | 2085 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
| 2017 | 2086 | * @__NL80211_ATTR_AFTER_LAST: internal use |
| @@ -2423,6 +2492,14 @@ enum nl80211_attrs { · 405 unmodified lines | ||
| 2423 | 2492 | |
| 2424 | 2493 | NL80211_ATTR_TIMEOUT_REASON, |
| 2425 | 2494 | |
| 2495 | + NL80211_ATTR_FILS_ERP_USERNAME, | |
| 2496 | + NL80211_ATTR_FILS_ERP_REALM, | |
| 2497 | + NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM, | |
| 2498 | + NL80211_ATTR_FILS_ERP_RRK, | |
| 2499 | + NL80211_ATTR_FILS_CACHE_ID, | |
| 2500 | + | |
| 2501 | + NL80211_ATTR_PMK, | |
| 2502 | + | |
| 2426 | 2503 | /* add attributes here, update the policy in nl80211.c */ |
| 2427 | 2504 | |
| 2428 | 2505 | __NL80211_ATTR_AFTER_LAST, |
| @@ -3942,7 +4019,10 @@ enum nl80211_ps_state { · 1513 unmodified lines | ||
| 3942 | 4019 | * @__NL80211_ATTR_CQM_INVALID: invalid |
| 3943 | 4020 | * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies |
| 3944 | 4021 | * the threshold for the RSSI level at which an event will be sent. Zero |
| 3945 | − * to disable. | |
| 4022 | + * to disable. Alternatively, if %NL80211_EXT_FEATURE_CQM_RSSI_LIST is | |
| 4023 | + * set, multiple values can be supplied as a low-to-high sorted array of | |
| 4024 | + * threshold values in dBm. Events will be sent when the RSSI value | |
| 4025 | + * crosses any of the thresholds. | |
| 3946 | 4026 | * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies |
| 3947 | 4027 | * the minimum amount the RSSI level must change after an event before a |
| 3948 | 4028 | * new event may be issued (to reduce effects of RSSI oscillation). |
| @@ -4753,6 +4833,11 @@ enum nl80211_feature_flags { · 804 unmodified lines | ||
| 4753 | 4833 | * @NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI: The driver supports sched_scan |
| 4754 | 4834 | * for reporting BSSs with better RSSI than the current connected BSS |
| 4755 | 4835 | * (%NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI). |
| 4836 | + * @NL80211_EXT_FEATURE_CQM_RSSI_LIST: With this driver the | |
| 4837 | + * %NL80211_ATTR_CQM_RSSI_THOLD attribute accepts a list of zero or more | |
| 4838 | + * RSSI threshold values to monitor rather than exactly one threshold. | |
| 4839 | + * @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD: Driver SME supports FILS shared key | |
| 4840 | + * authentication with %NL80211_CMD_CONNECT. | |
| 4756 | 4841 | * |
| 4757 | 4842 | * @NUM_NL80211_EXT_FEATURES: number of extended features. |
| 4758 | 4843 | * @MAX_NL80211_EXT_FEATURES: highest extended feature index. |
| @@ -4771,6 +4856,8 @@ enum nl80211_ext_feature_index { · 12 unmodified lines | ||
| 4771 | 4856 | NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA, |
| 4772 | 4857 | NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED, |
| 4773 | 4858 | NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI, |
| 4859 | + NL80211_EXT_FEATURE_CQM_RSSI_LIST, | |
| 4860 | + NL80211_EXT_FEATURE_FILS_SK_OFFLOAD, | |
| 4774 | 4861 | |
| 4775 | 4862 | /* add new features before the definition below */ |
| 4776 | 4863 | NUM_NL80211_EXT_FEATURES, |
| @@ -4906,12 +4993,17 @@ enum nl80211_smps_mode { · 129 unmodified lines | ||
| 4906 | 4993 | * change to the channel status. |
| 4907 | 4994 | * @NL80211_RADAR_NOP_FINISHED: The Non-Occupancy Period for this channel is |
| 4908 | 4995 | * over, channel becomes usable. |
| 4996 | + * @NL80211_RADAR_PRE_CAC_EXPIRED: Channel Availability Check done on this | |
| 4997 | + * non-operating channel is expired and no longer valid. New CAC must | |
| 4998 | + * be done on this channel before starting the operation. This is not | |
| 4999 | + * applicable for ETSI dfs domain where pre-CAC is valid for ever. | |
| 4909 | 5000 | */ |
| 4910 | 5001 | enum nl80211_radar_event { |
| 4911 | 5002 | NL80211_RADAR_DETECTED, |
| 4912 | 5003 | NL80211_RADAR_CAC_FINISHED, |
| 4913 | 5004 | NL80211_RADAR_CAC_ABORTED, |
| 4914 | 5005 | NL80211_RADAR_NOP_FINISHED, |
| 5006 | + NL80211_RADAR_PRE_CAC_EXPIRED, | |
| 4915 | 5007 | }; |
| 4916 | 5008 | |
| 4917 | 5009 | /** |
| @@ -357,14 +357,14 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, · 356 unmodified lines | ||
| 357 | 357 | spin_lock_init(&tid_agg_rx->reorder_lock); |
| 358 | 358 | |
| 359 | 359 | /* rx timer */ |
| 360 | − tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired; | |
| 361 | − tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid]; | |
| 362 | − init_timer_deferrable(&tid_agg_rx->session_timer); | |
| 360 | + setup_deferrable_timer(&tid_agg_rx->session_timer, | |
| 361 | + sta_rx_agg_session_timer_expired, | |
| 362 | + (unsigned long)&sta->timer_to_tid[tid]); | |
| 363 | 363 | |
| 364 | 364 | /* rx reorder timer */ |
| 365 | − tid_agg_rx->reorder_timer.function = sta_rx_agg_reorder_timer_expired; | |
| 366 | − tid_agg_rx->reorder_timer.data = (unsigned long)&sta->timer_to_tid[tid]; | |
| 367 | − init_timer(&tid_agg_rx->reorder_timer); | |
| 365 | + setup_timer(&tid_agg_rx->reorder_timer, | |
| 366 | + sta_rx_agg_reorder_timer_expired, | |
| 367 | + (unsigned long)&sta->timer_to_tid[tid]); | |
| 368 | 368 | |
| 369 | 369 | /* prepare reordering buffer */ |
| 370 | 370 | tid_agg_rx->reorder_buf = |
| @@ -670,14 +670,14 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, · 669 unmodified lines | ||
| 670 | 670 | tid_tx->timeout = timeout; |
| 671 | 671 | |
| 672 | 672 | /* response timer */ |
| 673 | − tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired; | |
| 674 | − tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid]; | |
| 675 | − init_timer(&tid_tx->addba_resp_timer); | |
| 673 | + setup_timer(&tid_tx->addba_resp_timer, | |
| 674 | + sta_addba_resp_timer_expired, | |
| 675 | + (unsigned long)&sta->timer_to_tid[tid]); | |
| 676 | 676 | |
| 677 | 677 | /* tx timer */ |
| 678 | − tid_tx->session_timer.function = sta_tx_agg_session_timer_expired; | |
| 679 | − tid_tx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid]; | |
| 680 | − init_timer_deferrable(&tid_tx->session_timer); | |
| 678 | + setup_deferrable_timer(&tid_tx->session_timer, | |
| 679 | + sta_tx_agg_session_timer_expired, | |
| 680 | + (unsigned long)&sta->timer_to_tid[tid]); | |
| 681 | 681 | |
| 682 | 682 | /* assign a dialog token */ |
| 683 | 683 | sta->ampdu_mlme.dialog_token_allocator++; |
| @@ -3,7 +3,7 @@ · 2 unmodified lines | ||
| 3 | 3 | * |
| 4 | 4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
| 5 | 5 | * Copyright 2013-2015 Intel Mobile Communications GmbH |
| 6 | − * Copyright (C) 2015-2016 Intel Deutschland GmbH | |
| 6 | + * Copyright (C) 2015-2017 Intel Deutschland GmbH | |
| 7 | 7 | * |
| 8 | 8 | * This file is GPLv2 as found in COPYING. |
| 9 | 9 | */ |
| @@ -22,11 +22,98 @@ · 12 unmodified lines | ||
| 22 | 22 | #include "mesh.h" |
| 23 | 23 | #include "wme.h" |
| 24 | 24 | |
| 25 | +static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata, | |
| 26 | + struct vif_params *params) | |
| 27 | +{ | |
| 28 | + bool mu_mimo_groups = false; | |
| 29 | + bool mu_mimo_follow = false; | |
| 30 | + | |
| 31 | + if (params->vht_mumimo_groups) { | |
| 32 | + u64 membership; | |
| 33 | + | |
| 34 | + BUILD_BUG_ON(sizeof(membership) != WLAN_MEMBERSHIP_LEN); | |
| 35 | + | |
| 36 | + memcpy(sdata->vif.bss_conf.mu_group.membership, | |
| 37 | + params->vht_mumimo_groups, WLAN_MEMBERSHIP_LEN); | |
| 38 | + memcpy(sdata->vif.bss_conf.mu_group.position, | |
| 39 | + params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN, | |
| 40 | + WLAN_USER_POSITION_LEN); | |
| 41 | + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MU_GROUPS); | |
| 42 | + /* don't care about endianness - just check for 0 */ | |
| 43 | + memcpy(&membership, params->vht_mumimo_groups, | |
| 44 | + WLAN_MEMBERSHIP_LEN); | |
| 45 | + mu_mimo_groups = membership != 0; | |
| 46 | + } | |
| 47 | + | |
| 48 | + if (params->vht_mumimo_follow_addr) { | |
| 49 | + mu_mimo_follow = | |
| 50 | + is_valid_ether_addr(params->vht_mumimo_follow_addr); | |
| 51 | + ether_addr_copy(sdata->u.mntr.mu_follow_addr, | |
| 52 | + params->vht_mumimo_follow_addr); | |
| 53 | + } | |
| 54 | + | |
| 55 | + sdata->vif.mu_mimo_owner = mu_mimo_groups || mu_mimo_follow; | |
| 56 | +} | |
| 57 | + | |
| 58 | +static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata, | |
| 59 | + struct vif_params *params) | |
| 60 | +{ | |
| 61 | + struct ieee80211_local *local = sdata->local; | |
| 62 | + struct ieee80211_sub_if_data *monitor_sdata; | |
| 63 | + | |
| 64 | + /* check flags first */ | |
| 65 | + if (params->flags && ieee80211_sdata_running(sdata)) { | |
| 66 | + u32 mask = MONITOR_FLAG_COOK_FRAMES | MONITOR_FLAG_ACTIVE; | |
| 67 | + | |
| 68 | + /* | |
| 69 | + * Prohibit MONITOR_FLAG_COOK_FRAMES and | |
| 70 | + * MONITOR_FLAG_ACTIVE to be changed while the | |
| 71 | + * interface is up. | |
| 72 | + * Else we would need to add a lot of cruft | |
| 73 | + * to update everything: | |
| 74 | + * cooked_mntrs, monitor and all fif_* counters | |
| 75 | + * reconfigure hardware | |
| 76 | + */ | |
| 77 | + if ((params->flags & mask) != (sdata->u.mntr.flags & mask)) | |
| 78 | + return -EBUSY; | |
| 79 | + } | |
| 80 | + | |
| 81 | + /* also validate MU-MIMO change */ | |
| 82 | + monitor_sdata = rtnl_dereference(local->monitor_sdata); | |
| 83 | + | |
| 84 | + if (!monitor_sdata && | |
| 85 | + (params->vht_mumimo_groups || params->vht_mumimo_follow_addr)) | |
| 86 | + return -EOPNOTSUPP; | |
| 87 | + | |
| 88 | + /* apply all changes now - no failures allowed */ | |
| 89 | + | |
| 90 | + if (monitor_sdata) | |
| 91 | + ieee80211_set_mu_mimo_follow(monitor_sdata, params); | |
| 92 | + | |
| 93 | + if (params->flags) { | |
| 94 | + if (ieee80211_sdata_running(sdata)) { | |
| 95 | + ieee80211_adjust_monitor_flags(sdata, -1); | |
| 96 | + sdata->u.mntr.flags = params->flags; | |
| 97 | + ieee80211_adjust_monitor_flags(sdata, 1); | |
| 98 | + | |
| 99 | + ieee80211_configure_filter(local); | |
| 100 | + } else { | |
| 101 | + /* | |
| 102 | + * Because the interface is down, ieee80211_do_stop | |
| 103 | + * and ieee80211_do_open take care of "everything" | |
| 104 | + * mentioned in the comment above. | |
| 105 | + */ | |
| 106 | + sdata->u.mntr.flags = params->flags; | |
| 107 | + } | |
| 108 | + } | |
| 109 | + | |
| 110 | + return 0; | |
| 111 | +} | |
| 112 | + | |
| 25 | 113 | static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, |
| 26 | 114 | const char *name, |
| 27 | 115 | unsigned char name_assign_type, |
| 28 | 116 | enum nl80211_iftype type, |
| 29 | − u32 *flags, | |
| 30 | 117 | struct vif_params *params) |
| 31 | 118 | { |
| 32 | 119 | struct ieee80211_local *local = wiphy_priv(wiphy); |
| @@ -38,9 +125,14 @@ static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, · 5 unmodified lines | ||
| 38 | 125 | if (err) |
| 39 | 126 | return ERR_PTR(err); |
| 40 | 127 | |
| 41 | − if (type == NL80211_IFTYPE_MONITOR && flags) { | |
| 42 | − sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | |
| 43 | − sdata->u.mntr.flags = *flags; | |
| 128 | + sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | |
| 129 | + | |
| 130 | + if (type == NL80211_IFTYPE_MONITOR) { | |
| 131 | + err = ieee80211_set_mon_options(sdata, params); | |
| 132 | + if (err) { | |
| 133 | + ieee80211_if_remove(sdata); | |
| 134 | + return NULL; | |
| 135 | + } | |
| 44 | 136 | } |
| 45 | 137 | |
| 46 | 138 | return wdev; |
| @@ -55,7 +147,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) · 8 unmodified lines | ||
| 55 | 147 | |
| 56 | 148 | static int ieee80211_change_iface(struct wiphy *wiphy, |
| 57 | 149 | struct net_device *dev, |
| 58 | − enum nl80211_iftype type, u32 *flags, | |
| 150 | + enum nl80211_iftype type, | |
| 59 | 151 | struct vif_params *params) |
| 60 | 152 | { |
| 61 | 153 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| @@ -75,58 +167,9 @@ static int ieee80211_change_iface(struct wiphy *wiphy, · 13 unmodified lines | ||
| 75 | 167 | } |
| 76 | 168 | |
| 77 | 169 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { |
| 78 | − struct ieee80211_local *local = sdata->local; | |
| 79 | − struct ieee80211_sub_if_data *monitor_sdata; | |
| 80 | − u32 mu_mntr_cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER; | |
| 81 | − | |
| 82 | − monitor_sdata = rtnl_dereference(local->monitor_sdata); | |
| 83 | − if (monitor_sdata && | |
| 84 | − wiphy_ext_feature_isset(wiphy, mu_mntr_cap_flag)) { | |
| 85 | − memcpy(monitor_sdata->vif.bss_conf.mu_group.membership, | |
| 86 | − params->vht_mumimo_groups, WLAN_MEMBERSHIP_LEN); | |
| 87 | − memcpy(monitor_sdata->vif.bss_conf.mu_group.position, | |
| 88 | − params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN, | |
| 89 | − WLAN_USER_POSITION_LEN); | |
| 90 | − monitor_sdata->vif.mu_mimo_owner = true; | |
| 91 | − ieee80211_bss_info_change_notify(monitor_sdata, | |
| 92 | − BSS_CHANGED_MU_GROUPS); | |
| 93 | − | |
| 94 | − ether_addr_copy(monitor_sdata->u.mntr.mu_follow_addr, | |
| 95 | − params->macaddr); | |
| 96 | − } | |
| 97 | − | |
| 98 | − if (!flags) | |
| 99 | − return 0; | |
| 100 | − | |
| 101 | − if (ieee80211_sdata_running(sdata)) { | |
| 102 | − u32 mask = MONITOR_FLAG_COOK_FRAMES | | |
| 103 | − MONITOR_FLAG_ACTIVE; | |
| 104 | − | |
| 105 | − /* | |
| 106 | − * Prohibit MONITOR_FLAG_COOK_FRAMES and | |
| 107 | − * MONITOR_FLAG_ACTIVE to be changed while the | |
| 108 | − * interface is up. | |
| 109 | − * Else we would need to add a lot of cruft | |
| 110 | − * to update everything: | |
| 111 | − * cooked_mntrs, monitor and all fif_* counters | |
| 112 | − * reconfigure hardware | |
| 113 | − */ | |
| 114 | − if ((*flags & mask) != (sdata->u.mntr.flags & mask)) | |
| 115 | − return -EBUSY; | |
| 116 | − | |
| 117 | − ieee80211_adjust_monitor_flags(sdata, -1); | |
| 118 | − sdata->u.mntr.flags = *flags; | |
| 119 | − ieee80211_adjust_monitor_flags(sdata, 1); | |
| 120 | − | |
| 121 | − ieee80211_configure_filter(local); | |
| 122 | − } else { | |
| 123 | − /* | |
| 124 | − * Because the interface is down, ieee80211_do_stop | |
| 125 | − * and ieee80211_do_open take care of "everything" | |
| 126 | − * mentioned in the comment above. | |
| 127 | − */ | |
| 128 | − sdata->u.mntr.flags = *flags; | |
| 129 | − } | |
| 170 | + ret = ieee80211_set_mon_options(sdata, params); | |
| 171 | + if (ret) | |
| 172 | + return ret; | |
| 130 | 173 | } |
| 131 | 174 | |
| 132 | 175 | return 0; |
| @@ -2042,6 +2085,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, · 1909 unmodified lines | ||
| 2042 | 2085 | params->basic_rates_len, |
| 2043 | 2086 | &sdata->vif.bss_conf.basic_rates); |
| 2044 | 2087 | changed |= BSS_CHANGED_BASIC_RATES; |
| 2088 | + ieee80211_check_rate_mask(sdata); | |
| 2045 | 2089 | } |
| 2046 | 2090 | |
| 2047 | 2091 | if (params->ap_isolate >= 0) { |
| @@ -2630,6 +2674,33 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy, · 582 unmodified lines | ||
| 2630 | 2674 | |
| 2631 | 2675 | bss_conf->cqm_rssi_thold = rssi_thold; |
| 2632 | 2676 | bss_conf->cqm_rssi_hyst = rssi_hyst; |
| 2677 | + bss_conf->cqm_rssi_low = 0; | |
| 2678 | + bss_conf->cqm_rssi_high = 0; | |
| 2679 | + sdata->u.mgd.last_cqm_event_signal = 0; | |
| 2680 | + | |
| 2681 | + /* tell the driver upon association, unless already associated */ | |
| 2682 | + if (sdata->u.mgd.associated && | |
| 2683 | + sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI) | |
| 2684 | + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM); | |
| 2685 | + | |
| 2686 | + return 0; | |
| 2687 | +} | |
| 2688 | + | |
| 2689 | +static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy, | |
| 2690 | + struct net_device *dev, | |
| 2691 | + s32 rssi_low, s32 rssi_high) | |
| 2692 | +{ | |
| 2693 | + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | |
| 2694 | + struct ieee80211_vif *vif = &sdata->vif; | |
| 2695 | + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | |
| 2696 | + | |
| 2697 | + if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER) | |
| 2698 | + return -EOPNOTSUPP; | |
| 2699 | + | |
| 2700 | + bss_conf->cqm_rssi_low = rssi_low; | |
| 2701 | + bss_conf->cqm_rssi_high = rssi_high; | |
| 2702 | + bss_conf->cqm_rssi_thold = 0; | |
| 2703 | + bss_conf->cqm_rssi_hyst = 0; | |
| 2633 | 2704 | sdata->u.mgd.last_cqm_event_signal = 0; |
| 2634 | 2705 | |
| 2635 | 2706 | /* tell the driver upon association, unless already associated */ |
| @@ -2658,6 +2729,21 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, · 22 unmodified lines | ||
| 2658 | 2729 | return ret; |
| 2659 | 2730 | } |
| 2660 | 2731 | |
| 2732 | + /* | |
| 2733 | + * If active validate the setting and reject it if it doesn't leave | |
| 2734 | + * at least one basic rate usable, since we really have to be able | |
| 2735 | + * to send something, and if we're an AP we have to be able to do | |
| 2736 | + * so at a basic rate so that all clients can receive it. | |
| 2737 | + */ | |
| 2738 | + if (rcu_access_pointer(sdata->vif.chanctx_conf) && | |
| 2739 | + sdata->vif.bss_conf.chandef.chan) { | |
| 2740 | + u32 basic_rates = sdata->vif.bss_conf.basic_rates; | |
| 2741 | + enum nl80211_band band = sdata->vif.bss_conf.chandef.chan->band; | |
| 2742 | + | |
| 2743 | + if (!(mask->control[band].legacy & basic_rates)) | |
| 2744 | + return -EINVAL; | |
| 2745 | + } | |
| 2746 | + | |
| 2661 | 2747 | for (i = 0; i < NUM_NL80211_BANDS; i++) { |
| 2662 | 2748 | struct ieee80211_supported_band *sband = wiphy->bands[i]; |
| 2663 | 2749 | int j; |
| @@ -3639,6 +3725,7 @@ const struct cfg80211_ops mac80211_config_ops = { · 975 unmodified lines | ||
| 3639 | 3725 | .mgmt_tx = ieee80211_mgmt_tx, |
| 3640 | 3726 | .mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait, |
| 3641 | 3727 | .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, |
| 3728 | + .set_cqm_rssi_range_config = ieee80211_set_cqm_rssi_range_config, | |
| 3642 | 3729 | .mgmt_frame_register = ieee80211_mgmt_frame_register, |
| 3643 | 3730 | .set_antenna = ieee80211_set_antenna, |
| 3644 | 3731 | .get_antenna = ieee80211_get_antenna, |
| @@ -425,7 +425,7 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, · 424 unmodified lines | ||
| 425 | 425 | case NL80211_CHAN_WIDTH_5: |
| 426 | 426 | case NL80211_CHAN_WIDTH_10: |
| 427 | 427 | cfg80211_chandef_create(&chandef, cbss->channel, |
| 428 | − NL80211_CHAN_WIDTH_20_NOHT); | |
| 428 | + NL80211_CHAN_NO_HT); | |
| 429 | 429 | chandef.width = sdata->u.ibss.chandef.width; |
| 430 | 430 | break; |
| 431 | 431 | case NL80211_CHAN_WIDTH_80: |
| @@ -437,7 +437,7 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, · 5 unmodified lines | ||
| 437 | 437 | default: |
| 438 | 438 | /* fall back to 20 MHz for unsupported modes */ |
| 439 | 439 | cfg80211_chandef_create(&chandef, cbss->channel, |
| 440 | − NL80211_CHAN_WIDTH_20_NOHT); | |
| 440 | + NL80211_CHAN_NO_HT); | |
| 441 | 441 | break; |
| 442 | 442 | } |
| 443 | 443 | |
| @@ -839,6 +839,8 @@ struct txq_info { · 838 unmodified lines | ||
| 839 | 839 | struct ieee80211_if_mntr { |
| 840 | 840 | u32 flags; |
| 841 | 841 | u8 mu_follow_addr[ETH_ALEN] __aligned(2); |
| 842 | + | |
| 843 | + struct list_head list; | |
| 842 | 844 | }; |
| 843 | 845 | |
| 844 | 846 | /** |
| @@ -1259,6 +1261,7 @@ struct ieee80211_local { · 414 unmodified lines | ||
| 1259 | 1261 | |
| 1260 | 1262 | /* see iface.c */ |
| 1261 | 1263 | struct list_head interfaces; |
| 1264 | + struct list_head mon_list; /* only that are IFF_UP && !cooked */ | |
| 1262 | 1265 | struct mutex iflist_mtx; |
| 1263 | 1266 | |
| 1264 | 1267 | /* |
| @@ -676,7 +676,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) · 675 unmodified lines | ||
| 676 | 676 | |
| 677 | 677 | set_bit(SDATA_STATE_RUNNING, &sdata->state); |
| 678 | 678 | |
| 679 | − if (sdata->vif.type == NL80211_IFTYPE_WDS) { | |
| 679 | + switch (sdata->vif.type) { | |
| 680 | + case NL80211_IFTYPE_WDS: | |
| 680 | 681 | /* Create STA entry for the WDS peer */ |
| 681 | 682 | sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, |
| 682 | 683 | GFP_KERNEL); |
| @@ -697,8 +698,17 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) · 14 unmodified lines | ||
| 697 | 698 | |
| 698 | 699 | rate_control_rate_init(sta); |
| 699 | 700 | netif_carrier_on(dev); |
| 700 | − } else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) { | |
| 701 | + break; | |
| 702 | + case NL80211_IFTYPE_P2P_DEVICE: | |
| 701 | 703 | rcu_assign_pointer(local->p2p_sdata, sdata); |
| 704 | + break; | |
| 705 | + case NL80211_IFTYPE_MONITOR: | |
| 706 | + if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) | |
| 707 | + break; | |
| 708 | + list_add_tail_rcu(&sdata->u.mntr.list, &local->mon_list); | |
| 709 | + break; | |
| 710 | + default: | |
| 711 | + break; | |
| 702 | 712 | } |
| 703 | 713 | |
| 704 | 714 | /* |
| @@ -817,6 +827,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, · 112 unmodified lines | ||
| 817 | 827 | case NL80211_IFTYPE_AP: |
| 818 | 828 | cancel_work_sync(&sdata->u.ap.request_smps_work); |
| 819 | 829 | break; |
| 830 | + case NL80211_IFTYPE_MONITOR: | |
| 831 | + if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) | |
| 832 | + break; | |
| 833 | + list_del_rcu(&sdata->u.mntr.list); | |
| 834 | + break; | |
| 820 | 835 | default: |
| 821 | 836 | break; |
| 822 | 837 | } |
| @@ -603,6 +603,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, · 602 unmodified lines | ||
| 603 | 603 | ARRAY_SIZE(local->ext_capa); |
| 604 | 604 | |
| 605 | 605 | INIT_LIST_HEAD(&local->interfaces); |
| 606 | + INIT_LIST_HEAD(&local->mon_list); | |
| 606 | 607 | |
| 607 | 608 | __hw_addr_init(&local->mc_list); |
| 608 | 609 | |
| @@ -1100,8 +1100,14 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, · 1099 unmodified lines | ||
| 1100 | 1100 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) |
| 1101 | 1101 | return; |
| 1102 | 1102 | |
| 1103 | − if (mesh_matches_local(sdata, &elems)) | |
| 1104 | − mesh_neighbour_update(sdata, mgmt->sa, &elems); | |
| 1103 | + if (mesh_matches_local(sdata, &elems)) { | |
| 1104 | + mpl_dbg(sdata, "rssi_threshold=%d,rx_status->signal=%d\n", | |
| 1105 | + sdata->u.mesh.mshcfg.rssi_threshold, rx_status->signal); | |
| 1106 | + if (!sdata->u.mesh.user_mpm || | |
| 1107 | + sdata->u.mesh.mshcfg.rssi_threshold == 0 || | |
| 1108 | + sdata->u.mesh.mshcfg.rssi_threshold < rx_status->signal) | |
| 1109 | + mesh_neighbour_update(sdata, mgmt->sa, &elems); | |
| 1110 | + } | |
| 1105 | 1111 | |
| 1106 | 1112 | if (ifmsh->sync_ops) |
| 1107 | 1113 | ifmsh->sync_ops->rx_bcn_presp(sdata, |
| @@ -16,6 +16,7 @@ · 15 unmodified lines | ||
| 16 | 16 | #define TEST_FRAME_LEN 8192 |
| 17 | 17 | #define MAX_METRIC 0xffffffff |
| 18 | 18 | #define ARITH_SHIFT 8 |
| 19 | +#define LINK_FAIL_THRESH 95 | |
| 19 | 20 | |
| 20 | 21 | #define MAX_PREQ_QUEUE_LEN 64 |
| 21 | 22 | |
| @@ -307,10 +308,12 @@ void ieee80211s_update_metric(struct ieee80211_local *local, · 285 unmodified lines | ||
| 307 | 308 | |
| 308 | 309 | failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK); |
| 309 | 310 | |
| 310 | − /* moving average, scaled to 100 */ | |
| 311 | − sta->mesh->fail_avg = | |
| 312 | − ((80 * sta->mesh->fail_avg + 5) / 100 + 20 * failed); | |
| 313 | − if (sta->mesh->fail_avg > 95) | |
| 311 | + /* moving average, scaled to 100. | |
| 312 | + * feed failure as 100 and success as 0 | |
| 313 | + */ | |
| 314 | + ewma_mesh_fail_avg_add(&sta->mesh->fail_avg, failed * 100); | |
| 315 | + if (ewma_mesh_fail_avg_read(&sta->mesh->fail_avg) > | |
| 316 | + LINK_FAIL_THRESH) | |
| 314 | 317 | mesh_plink_broken(sta); |
| 315 | 318 | } |
| 316 | 319 | |
| @@ -325,6 +328,8 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, · 8 unmodified lines | ||
| 325 | 328 | int rate, err; |
| 326 | 329 | u32 tx_time, estimated_retx; |
| 327 | 330 | u64 result; |
| 331 | + unsigned long fail_avg = | |
| 332 | + ewma_mesh_fail_avg_read(&sta->mesh->fail_avg); | |
| 328 | 333 | |
| 329 | 334 | /* Try to get rate based on HW/SW RC algorithm. |
| 330 | 335 | * Rate is returned in units of Kbps, correct this |
| @@ -336,7 +341,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, · 5 unmodified lines | ||
| 336 | 341 | if (rate) { |
| 337 | 342 | err = 0; |
| 338 | 343 | } else { |
| 339 | − if (sta->mesh->fail_avg >= 100) | |
| 344 | + if (fail_avg > LINK_FAIL_THRESH) | |
| 340 | 345 | return MAX_METRIC; |
| 341 | 346 | |
| 342 | 347 | sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate, &rinfo); |
| @@ -344,7 +349,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, · 1 unmodified line | ||
| 344 | 349 | if (WARN_ON(!rate)) |
| 345 | 350 | return MAX_METRIC; |
| 346 | 351 | |
| 347 | − err = (sta->mesh->fail_avg << ARITH_SHIFT) / 100; | |
| 352 | + err = (fail_avg << ARITH_SHIFT) / 100; | |
| 348 | 353 | } |
| 349 | 354 | |
| 350 | 355 | /* bitrate is in units of 100 Kbps, while we need rate in units of |
| @@ -484,6 +489,9 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, · 133 unmodified lines | ||
| 484 | 489 | ? mpath->exp_time : exp_time; |
| 485 | 490 | mesh_path_activate(mpath); |
| 486 | 491 | spin_unlock_bh(&mpath->state_lock); |
| 492 | + ewma_mesh_fail_avg_init(&sta->mesh->fail_avg); | |
| 493 | + /* init it at a low value - 0 start is tricky */ | |
| 494 | + ewma_mesh_fail_avg_add(&sta->mesh->fail_avg, 1); | |
| 487 | 495 | mesh_path_tx_pending(mpath); |
| 488 | 496 | /* draft says preq_id should be saved to, but there does |
| 489 | 497 | * not seem to be any use for it, skipping by now |
| @@ -522,6 +530,9 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, · 32 unmodified lines | ||
| 522 | 530 | ? mpath->exp_time : exp_time; |
| 523 | 531 | mesh_path_activate(mpath); |
| 524 | 532 | spin_unlock_bh(&mpath->state_lock); |
| 533 | + ewma_mesh_fail_avg_init(&sta->mesh->fail_avg); | |
| 534 | + /* init it at a low value - 0 start is tricky */ | |
| 535 | + ewma_mesh_fail_avg_add(&sta->mesh->fail_avg, 1); | |
| 525 | 536 | mesh_path_tx_pending(mpath); |
| 526 | 537 | } else |
| 527 | 538 | spin_unlock_bh(&mpath->state_lock); |
| @@ -397,11 +397,10 @@ struct mesh_path *mesh_path_new(struct ieee80211_sub_if_data *sdata, · 396 unmodified lines | ||
| 397 | 397 | new_mpath->sdata = sdata; |
| 398 | 398 | new_mpath->flags = 0; |
| 399 | 399 | skb_queue_head_init(&new_mpath->frame_queue); |
| 400 | − new_mpath->timer.data = (unsigned long) new_mpath; | |
| 401 | − new_mpath->timer.function = mesh_path_timer; | |
| 402 | 400 | new_mpath->exp_time = jiffies; |
| 403 | 401 | spin_lock_init(&new_mpath->state_lock); |
| 404 | − init_timer(&new_mpath->timer); | |
| 402 | + setup_timer(&new_mpath->timer, mesh_path_timer, | |
| 403 | + (unsigned long) new_mpath); | |
| 405 | 404 | |
| 406 | 405 | return new_mpath; |
| 407 | 406 | } |
| @@ -829,6 +828,9 @@ void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop) · 421 unmodified lines | ||
| 829 | 828 | mpath->flags = MESH_PATH_FIXED | MESH_PATH_SN_VALID; |
| 830 | 829 | mesh_path_activate(mpath); |
| 831 | 830 | spin_unlock_bh(&mpath->state_lock); |
| 831 | + ewma_mesh_fail_avg_init(&next_hop->mesh->fail_avg); | |
| 832 | + /* init it at a low value - 0 start is tricky */ | |
| 833 | + ewma_mesh_fail_avg_add(&next_hop->mesh->fail_avg, 1); | |
| 832 | 834 | mesh_path_tx_pending(mpath); |
| 833 | 835 | } |
| 834 | 836 | |
| @@ -1908,6 +1908,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, · 1907 unmodified lines | ||
| 1908 | 1908 | sdata->u.mgd.associated = cbss; |
| 1909 | 1909 | memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN); |
| 1910 | 1910 | |
| 1911 | + ieee80211_check_rate_mask(sdata); | |
| 1912 | + | |
| 1911 | 1913 | sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE; |
| 1912 | 1914 | |
| 1913 | 1915 | if (sdata->vif.p2p || |
| @@ -2797,8 +2799,9 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, · 883 unmodified lines | ||
| 2797 | 2799 | |
| 2798 | 2800 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
| 2799 | 2801 | |
| 2800 | − sdata_info(sdata, "disassociated from %pM (Reason: %u)\n", | |
| 2801 | − mgmt->sa, reason_code); | |
| 2802 | + sdata_info(sdata, "disassociated from %pM (Reason: %u=%s)\n", | |
| 2803 | + mgmt->sa, reason_code, | |
| 2804 | + ieee80211_get_reason_code_string(reason_code)); | |
| 2802 | 2805 | |
| 2803 | 2806 | ieee80211_set_disassoc(sdata, 0, 0, false, NULL); |
| 2804 | 2807 | |
| @@ -2822,15 +2825,15 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband, · 17 unmodified lines | ||
| 2822 | 2825 | *have_higher_than_11mbit = true; |
| 2823 | 2826 | |
| 2824 | 2827 | /* |
| 2825 | − * BSS_MEMBERSHIP_SELECTOR_HT_PHY is defined in 802.11n-2009 | |
| 2826 | − * 7.3.2.2 as a magic value instead of a rate. Hence, skip it. | |
| 2828 | + * Skip HT and VHT BSS membership selectors since they're not | |
| 2829 | + * rates. | |
| 2827 | 2830 | * |
| 2828 | − * Note: Even through the membership selector and the basic | |
| 2831 | + * Note: Even though the membership selector and the basic | |
| 2829 | 2832 | * rate flag share the same bit, they are not exactly |
| 2830 | 2833 | * the same. |
| 2831 | 2834 | */ |
| 2832 | − if (!!(supp_rates[i] & 0x80) && | |
| 2833 | − (supp_rates[i] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY) | |
| 2835 | + if (supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY) || | |
| 2836 | + supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY)) | |
| 2834 | 2837 | continue; |
| 2835 | 2838 | |
| 2836 | 2839 | for (j = 0; j < sband->n_bitrates; j++) { |
| @@ -3430,6 +3433,30 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, · 593 unmodified lines | ||
| 3430 | 3433 | } |
| 3431 | 3434 | } |
| 3432 | 3435 | |
| 3436 | + if (bss_conf->cqm_rssi_low && | |
| 3437 | + ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) { | |
| 3438 | + int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal); | |
| 3439 | + int last_event = ifmgd->last_cqm_event_signal; | |
| 3440 | + int low = bss_conf->cqm_rssi_low; | |
| 3441 | + int high = bss_conf->cqm_rssi_high; | |
| 3442 | + | |
| 3443 | + if (sig < low && | |
| 3444 | + (last_event == 0 || last_event >= low)) { | |
| 3445 | + ifmgd->last_cqm_event_signal = sig; | |
| 3446 | + ieee80211_cqm_rssi_notify( | |
| 3447 | + &sdata->vif, | |
| 3448 | + NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, | |
| 3449 | + sig, GFP_KERNEL); | |
| 3450 | + } else if (sig > high && | |
| 3451 | + (last_event == 0 || last_event <= high)) { | |
| 3452 | + ifmgd->last_cqm_event_signal = sig; | |
| 3453 | + ieee80211_cqm_rssi_notify( | |
| 3454 | + &sdata->vif, | |
| 3455 | + NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, | |
| 3456 | + sig, GFP_KERNEL); | |
| 3457 | + } | |
| 3458 | + } | |
| 3459 | + | |
| 3433 | 3460 | if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) { |
| 3434 | 3461 | mlme_dbg_ratelimited(sdata, |
| 3435 | 3462 | "cancelling AP probe due to a received beacon\n"); |
| @@ -2,6 +2,7 @@ · 1 unmodified line | ||
| 2 | 2 | * Copyright 2002-2005, Instant802 Networks, Inc. |
| 3 | 3 | * Copyright 2005-2006, Devicescape Software, Inc. |
| 4 | 4 | * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> |
| 5 | + * Copyright 2017 Intel Deutschland GmbH | |
| 5 | 6 | * |
| 6 | 7 | * This program is free software; you can redistribute it and/or modify |
| 7 | 8 | * it under the terms of the GNU General Public License version 2 as |
| @@ -173,9 +174,11 @@ ieee80211_rate_control_ops_get(const char *name) · 165 unmodified lines | ||
| 173 | 174 | /* try default if specific alg requested but not found */ |
| 174 | 175 | ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo); |
| 175 | 176 | |
| 176 | − /* try built-in one if specific alg requested but not found */ | |
| 177 | − if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT)) | |
| 177 | + /* Note: check for > 0 is intentional to avoid clang warning */ | |
| 178 | + if (!ops && (strlen(CONFIG_MAC80211_RC_DEFAULT) > 0)) | |
| 179 | + /* try built-in one if specific alg requested but not found */ | |
| 178 | 180 | ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT); |
| 181 | + | |
| 179 | 182 | kernel_param_unlock(THIS_MODULE); |
| 180 | 183 | |
| 181 | 184 | return ops; |
| @@ -208,7 +211,6 @@ static struct rate_control_ref *rate_control_alloc(const char *name, · 26 unmodified lines | ||
| 208 | 211 | ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL); |
| 209 | 212 | if (!ref) |
| 210 | 213 | return NULL; |
| 211 | − ref->local = local; | |
| 212 | 214 | ref->ops = ieee80211_rate_control_ops_get(name); |
| 213 | 215 | if (!ref->ops) |
| 214 | 216 | goto free; |
| @@ -229,18 +231,45 @@ free: · 14 unmodified lines | ||
| 229 | 231 | return NULL; |
| 230 | 232 | } |
| 231 | 233 | |
| 232 | −static void rate_control_free(struct rate_control_ref *ctrl_ref) | |
| 234 | +static void rate_control_free(struct ieee80211_local *local, | |
| 235 | + struct rate_control_ref *ctrl_ref) | |
| 233 | 236 | { |
| 234 | 237 | ctrl_ref->ops->free(ctrl_ref->priv); |
| 235 | 238 | |
| 236 | 239 | #ifdef CONFIG_MAC80211_DEBUGFS |
| 237 | − debugfs_remove_recursive(ctrl_ref->local->debugfs.rcdir); | |
| 238 | − ctrl_ref->local->debugfs.rcdir = NULL; | |
| 240 | + debugfs_remove_recursive(local->debugfs.rcdir); | |
| 241 | + local->debugfs.rcdir = NULL; | |
| 239 | 242 | #endif |
| 240 | 243 | |
| 241 | 244 | kfree(ctrl_ref); |
| 242 | 245 | } |
| 243 | 246 | |
| 247 | +void ieee80211_check_rate_mask(struct ieee80211_sub_if_data *sdata) | |
| 248 | +{ | |
| 249 | + struct ieee80211_local *local = sdata->local; | |
| 250 | + struct ieee80211_supported_band *sband; | |
| 251 | + u32 user_mask, basic_rates = sdata->vif.bss_conf.basic_rates; | |
| 252 | + enum nl80211_band band; | |
| 253 | + | |
| 254 | + if (WARN_ON(!sdata->vif.bss_conf.chandef.chan)) | |
| 255 | + return; | |
| 256 | + | |
| 257 | + if (WARN_ON_ONCE(!basic_rates)) | |
| 258 | + return; | |
| 259 | + | |
| 260 | + band = sdata->vif.bss_conf.chandef.chan->band; | |
| 261 | + user_mask = sdata->rc_rateidx_mask[band]; | |
| 262 | + sband = local->hw.wiphy->bands[band]; | |
| 263 | + | |
| 264 | + if (user_mask & basic_rates) | |
| 265 | + return; | |
| 266 | + | |
| 267 | + sdata_dbg(sdata, | |
| 268 | + "no overlap between basic rates (0x%x) and user mask (0x%x on band %d) - clearing the latter", | |
| 269 | + basic_rates, user_mask, band); | |
| 270 | + sdata->rc_rateidx_mask[band] = (1 << sband->n_bitrates) - 1; | |
| 271 | +} | |
| 272 | + | |
| 244 | 273 | static bool rc_no_data_or_no_ack_use_min(struct ieee80211_tx_rate_control *txrc) |
| 245 | 274 | { |
| 246 | 275 | struct sk_buff *skb = txrc->skb; |
| @@ -936,6 +965,6 @@ void rate_control_deinitialize(struct ieee80211_local *local) · 689 unmodified lines | ||
| 936 | 965 | return; |
| 937 | 966 | |
| 938 | 967 | local->rate_ctrl = NULL; |
| 939 | − rate_control_free(ref); | |
| 968 | + rate_control_free(local, ref); | |
| 940 | 969 | } |
| 941 | 970 | |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | ||
| 20 | 20 | #include "driver-ops.h" |
| 21 | 21 | |
| 22 | 22 | struct rate_control_ref { |
| 23 | − struct ieee80211_local *local; | |
| 24 | 23 | const struct rate_control_ops *ops; |
| 25 | 24 | void *priv; |
| 26 | 25 | }; |
| @@ -111,6 +110,8 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) · 84 unmodified lines | ||
| 111 | 110 | #endif |
| 112 | 111 | } |
| 113 | 112 | |
| 113 | +void ieee80211_check_rate_mask(struct ieee80211_sub_if_data *sdata); | |
| 114 | + | |
| 114 | 115 | /* Get a reference to the rate control algorithm. If `name' is NULL, get the |
| 115 | 116 | * first available algorithm. */ |
| 116 | 117 | int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, |
| @@ -95,24 +95,13 @@ static u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, · 94 unmodified lines | ||
| 95 | 95 | * This function cleans up the SKB, i.e. it removes all the stuff |
| 96 | 96 | * only useful for monitoring. |
| 97 | 97 | */ |
| 98 | −static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, | |
| 99 | − struct sk_buff *skb, | |
| 100 | − unsigned int rtap_vendor_space) | |
| 98 | +static void remove_monitor_info(struct sk_buff *skb, | |
| 99 | + unsigned int present_fcs_len, | |
| 100 | + unsigned int rtap_vendor_space) | |
| 101 | 101 | { |
| 102 | − if (ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)) { | |
| 103 | − if (likely(skb->len > FCS_LEN)) | |
| 104 | − __pskb_trim(skb, skb->len - FCS_LEN); | |
| 105 | − else { | |
| 106 | − /* driver bug */ | |
| 107 | − WARN_ON(1); | |
| 108 | − dev_kfree_skb(skb); | |
| 109 | − return NULL; | |
| 110 | − } | |
| 111 | − } | |
| 112 | − | |
| 102 | + if (present_fcs_len) | |
| 103 | + __pskb_trim(skb, skb->len - present_fcs_len); | |
| 113 | 104 | __pskb_pull(skb, rtap_vendor_space); |
| 114 | − | |
| 115 | − return skb; | |
| 116 | 105 | } |
| 117 | 106 | |
| 118 | 107 | static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len, |
| @@ -534,8 +523,15 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, · 415 unmodified lines | ||
| 534 | 523 | * the SKB because it has a bad FCS/PLCP checksum. |
| 535 | 524 | */ |
| 536 | 525 | |
| 537 | − if (ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)) | |
| 526 | + if (ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)) { | |
| 527 | + if (unlikely(origskb->len <= FCS_LEN)) { | |
| 528 | + /* driver bug */ | |
| 529 | + WARN_ON(1); | |
| 530 | + dev_kfree_skb(origskb); | |
| 531 | + return NULL; | |
| 532 | + } | |
| 538 | 533 | present_fcs_len = FCS_LEN; |
| 534 | + } | |
| 539 | 535 | |
| 540 | 536 | /* ensure hdr->frame_control and vendor radiotap data are in skb head */ |
| 541 | 537 | if (!pskb_may_pull(origskb, 2 + rtap_vendor_space)) { |
| @@ -550,7 +546,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, · 8 unmodified lines | ||
| 550 | 546 | return NULL; |
| 551 | 547 | } |
| 552 | 548 | |
| 553 | − return remove_monitor_info(local, origskb, rtap_vendor_space); | |
| 549 | + remove_monitor_info(origskb, present_fcs_len, | |
| 550 | + rtap_vendor_space); | |
| 551 | + return origskb; | |
| 554 | 552 | } |
| 555 | 553 | |
| 556 | 554 | /* room for the radiotap header based on driver features */ |
| @@ -580,9 +578,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, · 23 unmodified lines | ||
| 580 | 578 | * and FCS from the original. |
| 581 | 579 | */ |
| 582 | 580 | skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC); |
| 583 | − | |
| 584 | − origskb = remove_monitor_info(local, origskb, | |
| 585 | − rtap_vendor_space); | |
| 581 | + remove_monitor_info(origskb, present_fcs_len, | |
| 582 | + rtap_vendor_space); | |
| 586 | 583 | |
| 587 | 584 | if (!skb) |
| 588 | 585 | return origskb; |
| @@ -596,16 +593,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, · 7 unmodified lines | ||
| 596 | 593 | skb->pkt_type = PACKET_OTHERHOST; |
| 597 | 594 | skb->protocol = htons(ETH_P_802_2); |
| 598 | 595 | |
| 599 | − list_for_each_entry_rcu(sdata, &local->interfaces, list) { | |
| 600 | − if (sdata->vif.type != NL80211_IFTYPE_MONITOR) | |
| 601 | − continue; | |
| 602 | − | |
| 603 | − if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) | |
| 604 | − continue; | |
| 605 | − | |
| 606 | − if (!ieee80211_sdata_running(sdata)) | |
| 607 | − continue; | |
| 608 | − | |
| 596 | + list_for_each_entry_rcu(sdata, &local->mon_list, u.mntr.list) { | |
| 609 | 597 | if (prev_dev) { |
| 610 | 598 | skb2 = skb_clone(skb, GFP_ATOMIC); |
| 611 | 599 | if (skb2) { |
| @@ -132,9 +132,9 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata, · 131 unmodified lines | ||
| 132 | 132 | struct ieee80211_vht_operation vht_oper = { |
| 133 | 133 | .chan_width = |
| 134 | 134 | wide_bw_chansw_ie->new_channel_width, |
| 135 | − .center_freq_seg1_idx = | |
| 135 | + .center_freq_seg0_idx = | |
| 136 | 136 | wide_bw_chansw_ie->new_center_freq_seg0, |
| 137 | − .center_freq_seg2_idx = | |
| 137 | + .center_freq_seg1_idx = | |
| 138 | 138 | wide_bw_chansw_ie->new_center_freq_seg1, |
| 139 | 139 | /* .basic_mcs_set doesn't matter */ |
| 140 | 140 | }; |
| @@ -1960,14 +1960,17 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate, · 1959 unmodified lines | ||
| 1960 | 1960 | rinfo->bw = (rate & STA_STATS_RATE_BW_MASK) >> |
| 1961 | 1961 | STA_STATS_RATE_BW_SHIFT; |
| 1962 | 1962 | |
| 1963 | − if (rate & STA_STATS_RATE_VHT) { | |
| 1963 | + switch (rate & STA_STATS_RATE_TYPE_MASK) { | |
| 1964 | + case STA_STATS_RATE_TYPE_VHT: | |
| 1964 | 1965 | rinfo->flags = RATE_INFO_FLAGS_VHT_MCS; |
| 1965 | 1966 | rinfo->mcs = rate & 0xf; |
| 1966 | 1967 | rinfo->nss = (rate & 0xf0) >> 4; |
| 1967 | − } else if (rate & STA_STATS_RATE_HT) { | |
| 1968 | + break; | |
| 1969 | + case STA_STATS_RATE_TYPE_HT: | |
| 1968 | 1970 | rinfo->flags = RATE_INFO_FLAGS_MCS; |
| 1969 | 1971 | rinfo->mcs = rate & 0xff; |
| 1970 | − } else if (rate & STA_STATS_RATE_LEGACY) { | |
| 1972 | + break; | |
| 1973 | + case STA_STATS_RATE_TYPE_LEGACY: { | |
| 1971 | 1974 | struct ieee80211_supported_band *sband; |
| 1972 | 1975 | u16 brate; |
| 1973 | 1976 | unsigned int shift; |
| @@ -1982,6 +1985,8 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate, · 8 unmodified lines | ||
| 1982 | 1985 | else |
| 1983 | 1986 | shift = 0; |
| 1984 | 1987 | rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift); |
| 1988 | + break; | |
| 1989 | + } | |
| 1985 | 1990 | } |
| 1986 | 1991 | |
| 1987 | 1992 | if (rate & STA_STATS_RATE_SGI) |
| @@ -324,6 +324,9 @@ struct ieee80211_fast_rx { · 323 unmodified lines | ||
| 324 | 324 | struct rcu_head rcu_head; |
| 325 | 325 | }; |
| 326 | 326 | |
| 327 | +/* we use only values in the range 0-100, so pick a large precision */ | |
| 328 | +DECLARE_EWMA(mesh_fail_avg, 20, 8) | |
| 329 | + | |
| 327 | 330 | /** |
| 328 | 331 | * struct mesh_sta - mesh STA information |
| 329 | 332 | * @plink_lock: serialize access to plink fields |
| @@ -369,7 +372,7 @@ struct mesh_sta { · 39 unmodified lines | ||
| 369 | 372 | enum nl80211_mesh_power_mode nonpeer_pm; |
| 370 | 373 | |
| 371 | 374 | /* moving percentage of failed MSDUs */ |
| 372 | − unsigned int fail_avg; | |
| 375 | + struct ewma_mesh_fail_avg fail_avg; | |
| 373 | 376 | }; |
| 374 | 377 | |
| 375 | 378 | DECLARE_EWMA(signal, 10, 8) |
| @@ -725,9 +728,10 @@ void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta); · 349 unmodified lines | ||
| 725 | 728 | unsigned long ieee80211_sta_last_active(struct sta_info *sta); |
| 726 | 729 | |
| 727 | 730 | #define STA_STATS_RATE_INVALID 0 |
| 728 | −#define STA_STATS_RATE_VHT 0x8000 | |
| 729 | −#define STA_STATS_RATE_HT 0x4000 | |
| 730 | −#define STA_STATS_RATE_LEGACY 0x2000 | |
| 731 | +#define STA_STATS_RATE_TYPE_MASK 0xC000 | |
| 732 | +#define STA_STATS_RATE_TYPE_LEGACY 0x4000 | |
| 733 | +#define STA_STATS_RATE_TYPE_HT 0x8000 | |
| 734 | +#define STA_STATS_RATE_TYPE_VHT 0xC000 | |
| 731 | 735 | #define STA_STATS_RATE_SGI 0x1000 |
| 732 | 736 | #define STA_STATS_RATE_BW_SHIFT 9 |
| 733 | 737 | #define STA_STATS_RATE_BW_MASK (0x7 << STA_STATS_RATE_BW_SHIFT) |
| @@ -753,11 +757,11 @@ static inline u16 sta_stats_encode_rate(struct ieee80211_rx_status *s) · 19 unmodified lines | ||
| 753 | 757 | r |= STA_STATS_RATE_SGI; |
| 754 | 758 | |
| 755 | 759 | if (s->flag & RX_FLAG_VHT) |
| 756 | − r |= STA_STATS_RATE_VHT | (s->vht_nss << 4); | |
| 760 | + r |= STA_STATS_RATE_TYPE_VHT | (s->vht_nss << 4); | |
| 757 | 761 | else if (s->flag & RX_FLAG_HT) |
| 758 | − r |= STA_STATS_RATE_HT; | |
| 762 | + r |= STA_STATS_RATE_TYPE_HT; | |
| 759 | 763 | else |
| 760 | − r |= STA_STATS_RATE_LEGACY | (s->band << 4); | |
| 764 | + r |= STA_STATS_RATE_TYPE_LEGACY | (s->band << 4); | |
| 761 | 765 | |
| 762 | 766 | return r; |
| 763 | 767 | } |
| @@ -682,10 +682,6 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) · 681 unmodified lines | ||
| 682 | 682 | txrc.skb = tx->skb; |
| 683 | 683 | txrc.reported_rate.idx = -1; |
| 684 | 684 | txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[info->band]; |
| 685 | − if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1) | |
| 686 | − txrc.max_rate_idx = -1; | |
| 687 | − else | |
| 688 | − txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | |
| 689 | 685 | |
| 690 | 686 | if (tx->sdata->rc_has_mcs_mask[info->band]) |
| 691 | 687 | txrc.rate_idx_mcs_mask = |
| @@ -4249,10 +4245,6 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, · 3557 unmodified lines | ||
| 4249 | 4245 | txrc.skb = skb; |
| 4250 | 4246 | txrc.reported_rate.idx = -1; |
| 4251 | 4247 | txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; |
| 4252 | − if (txrc.rate_idx_mask == (1 << txrc.sband->n_bitrates) - 1) | |
| 4253 | − txrc.max_rate_idx = -1; | |
| 4254 | − else | |
| 4255 | − txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1; | |
| 4256 | 4248 | txrc.bss = true; |
| 4257 | 4249 | rate_control_get_rate(sdata, NULL, &txrc); |
| 4258 | 4250 | |
| @@ -2413,13 +2413,13 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, · 2412 unmodified lines | ||
| 2413 | 2413 | *pos++ = WLAN_EID_VHT_OPERATION; |
| 2414 | 2414 | *pos++ = sizeof(struct ieee80211_vht_operation); |
| 2415 | 2415 | vht_oper = (struct ieee80211_vht_operation *)pos; |
| 2416 | − vht_oper->center_freq_seg1_idx = ieee80211_frequency_to_channel( | |
| 2416 | + vht_oper->center_freq_seg0_idx = ieee80211_frequency_to_channel( | |
| 2417 | 2417 | chandef->center_freq1); |
| 2418 | 2418 | if (chandef->center_freq2) |
| 2419 | − vht_oper->center_freq_seg2_idx = | |
| 2419 | + vht_oper->center_freq_seg1_idx = | |
| 2420 | 2420 | ieee80211_frequency_to_channel(chandef->center_freq2); |
| 2421 | 2421 | else |
| 2422 | − vht_oper->center_freq_seg2_idx = 0x00; | |
| 2422 | + vht_oper->center_freq_seg1_idx = 0x00; | |
| 2423 | 2423 | |
| 2424 | 2424 | switch (chandef->width) { |
| 2425 | 2425 | case NL80211_CHAN_WIDTH_160: |
| @@ -2428,11 +2428,11 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, · 2 unmodified lines | ||
| 2428 | 2428 | * workaround. |
| 2429 | 2429 | */ |
| 2430 | 2430 | vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ; |
| 2431 | − vht_oper->center_freq_seg2_idx = vht_oper->center_freq_seg1_idx; | |
| 2431 | + vht_oper->center_freq_seg1_idx = vht_oper->center_freq_seg0_idx; | |
| 2432 | 2432 | if (chandef->chan->center_freq < chandef->center_freq1) |
| 2433 | − vht_oper->center_freq_seg1_idx -= 8; | |
| 2433 | + vht_oper->center_freq_seg0_idx -= 8; | |
| 2434 | 2434 | else |
| 2435 | − vht_oper->center_freq_seg1_idx += 8; | |
| 2435 | + vht_oper->center_freq_seg0_idx += 8; | |
| 2436 | 2436 | break; |
| 2437 | 2437 | case NL80211_CHAN_WIDTH_80P80: |
| 2438 | 2438 | /* |
| @@ -2491,9 +2491,9 @@ bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper, · 52 unmodified lines | ||
| 2491 | 2491 | if (!oper) |
| 2492 | 2492 | return false; |
| 2493 | 2493 | |
| 2494 | − cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx, | |
| 2494 | + cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg0_idx, | |
| 2495 | 2495 | chandef->chan->band); |
| 2496 | − cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg2_idx, | |
| 2496 | + cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx, | |
| 2497 | 2497 | chandef->chan->band); |
| 2498 | 2498 | |
| 2499 | 2499 | switch (oper->chan_width) { |
| @@ -2503,11 +2503,11 @@ bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper, · 3 unmodified lines | ||
| 2503 | 2503 | new.width = NL80211_CHAN_WIDTH_80; |
| 2504 | 2504 | new.center_freq1 = cf1; |
| 2505 | 2505 | /* If needed, adjust based on the newer interop workaround. */ |
| 2506 | − if (oper->center_freq_seg2_idx) { | |
| 2506 | + if (oper->center_freq_seg1_idx) { | |
| 2507 | 2507 | unsigned int diff; |
| 2508 | 2508 | |
| 2509 | − diff = abs(oper->center_freq_seg2_idx - | |
| 2510 | − oper->center_freq_seg1_idx); | |
| 2509 | + diff = abs(oper->center_freq_seg1_idx - | |
| 2510 | + oper->center_freq_seg0_idx); | |
| 2511 | 2511 | if (diff == 8) { |
| 2512 | 2512 | new.width = NL80211_CHAN_WIDTH_160; |
| 2513 | 2513 | new.center_freq1 = cf2; |
| @@ -32,6 +32,11 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, · 31 unmodified lines | ||
| 32 | 32 | rdev_set_qos_map(rdev, dev, NULL); |
| 33 | 33 | if (notify) |
| 34 | 34 | nl80211_send_ap_stopped(wdev); |
| 35 | + | |
| 36 | + /* Should we apply the grace period during beaconing interface | |
| 37 | + * shutdown also? | |
| 38 | + */ | |
| 39 | + cfg80211_sched_dfs_chan_update(rdev); | |
| 35 | 40 | } |
| 36 | 41 | |
| 37 | 42 | return err; |
| @@ -456,6 +456,123 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy, · 455 unmodified lines | ||
| 456 | 456 | return (r1 + r2 > 0); |
| 457 | 457 | } |
| 458 | 458 | |
| 459 | +/* | |
| 460 | + * Checks if center frequency of chan falls with in the bandwidth | |
| 461 | + * range of chandef. | |
| 462 | + */ | |
| 463 | +bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef, | |
| 464 | + struct ieee80211_channel *chan) | |
| 465 | +{ | |
| 466 | + int width; | |
| 467 | + u32 cf_offset, freq; | |
| 468 | + | |
| 469 | + if (chandef->chan->center_freq == chan->center_freq) | |
| 470 | + return true; | |
| 471 | + | |
| 472 | + width = cfg80211_chandef_get_width(chandef); | |
| 473 | + if (width <= 20) | |
| 474 | + return false; | |
| 475 | + | |
| 476 | + cf_offset = width / 2 - 10; | |
| 477 | + | |
| 478 | + for (freq = chandef->center_freq1 - width / 2 + 10; | |
| 479 | + freq <= chandef->center_freq1 + width / 2 - 10; freq += 20) { | |
| 480 | + if (chan->center_freq == freq) | |
| 481 | + return true; | |
| 482 | + } | |
| 483 | + | |
| 484 | + if (!chandef->center_freq2) | |
| 485 | + return false; | |
| 486 | + | |
| 487 | + for (freq = chandef->center_freq2 - width / 2 + 10; | |
| 488 | + freq <= chandef->center_freq2 + width / 2 - 10; freq += 20) { | |
| 489 | + if (chan->center_freq == freq) | |
| 490 | + return true; | |
| 491 | + } | |
| 492 | + | |
| 493 | + return false; | |
| 494 | +} | |
| 495 | + | |
| 496 | +bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev) | |
| 497 | +{ | |
| 498 | + bool active = false; | |
| 499 | + | |
| 500 | + ASSERT_WDEV_LOCK(wdev); | |
| 501 | + | |
| 502 | + if (!wdev->chandef.chan) | |
| 503 | + return false; | |
| 504 | + | |
| 505 | + switch (wdev->iftype) { | |
| 506 | + case NL80211_IFTYPE_AP: | |
| 507 | + case NL80211_IFTYPE_P2P_GO: | |
| 508 | + active = wdev->beacon_interval != 0; | |
| 509 | + break; | |
| 510 | + case NL80211_IFTYPE_ADHOC: | |
| 511 | + active = wdev->ssid_len != 0; | |
| 512 | + break; | |
| 513 | + case NL80211_IFTYPE_MESH_POINT: | |
| 514 | + active = wdev->mesh_id_len != 0; | |
| 515 | + break; | |
| 516 | + case NL80211_IFTYPE_STATION: | |
| 517 | + case NL80211_IFTYPE_OCB: | |
| 518 | + case NL80211_IFTYPE_P2P_CLIENT: | |
| 519 | + case NL80211_IFTYPE_MONITOR: | |
| 520 | + case NL80211_IFTYPE_AP_VLAN: | |
| 521 | + case NL80211_IFTYPE_WDS: | |
| 522 | + case NL80211_IFTYPE_P2P_DEVICE: | |
| 523 | + /* Can NAN type be considered as beaconing interface? */ | |
| 524 | + case NL80211_IFTYPE_NAN: | |
| 525 | + break; | |
| 526 | + case NL80211_IFTYPE_UNSPECIFIED: | |
| 527 | + case NUM_NL80211_IFTYPES: | |
| 528 | + WARN_ON(1); | |
| 529 | + } | |
| 530 | + | |
| 531 | + return active; | |
| 532 | +} | |
| 533 | + | |
| 534 | +static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy, | |
| 535 | + struct ieee80211_channel *chan) | |
| 536 | +{ | |
| 537 | + struct wireless_dev *wdev; | |
| 538 | + | |
| 539 | + list_for_each_entry(wdev, &wiphy->wdev_list, list) { | |
| 540 | + wdev_lock(wdev); | |
| 541 | + if (!cfg80211_beaconing_iface_active(wdev)) { | |
| 542 | + wdev_unlock(wdev); | |
| 543 | + continue; | |
| 544 | + } | |
| 545 | + | |
| 546 | + if (cfg80211_is_sub_chan(&wdev->chandef, chan)) { | |
| 547 | + wdev_unlock(wdev); | |
| 548 | + return true; | |
| 549 | + } | |
| 550 | + wdev_unlock(wdev); | |
| 551 | + } | |
| 552 | + | |
| 553 | + return false; | |
| 554 | +} | |
| 555 | + | |
| 556 | +bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, | |
| 557 | + struct ieee80211_channel *chan) | |
| 558 | +{ | |
| 559 | + struct cfg80211_registered_device *rdev; | |
| 560 | + | |
| 561 | + ASSERT_RTNL(); | |
| 562 | + | |
| 563 | + if (!(chan->flags & IEEE80211_CHAN_RADAR)) | |
| 564 | + return false; | |
| 565 | + | |
| 566 | + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | |
| 567 | + if (!reg_dfs_domain_same(wiphy, &rdev->wiphy)) | |
| 568 | + continue; | |
| 569 | + | |
| 570 | + if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan)) | |
| 571 | + return true; | |
| 572 | + } | |
| 573 | + | |
| 574 | + return false; | |
| 575 | +} | |
| 459 | 576 | |
| 460 | 577 | static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy, |
| 461 | 578 | u32 center_freq, |
| @@ -357,6 +357,38 @@ static void cfg80211_sched_scan_stop_wk(struct work_struct *work) · 356 unmodified lines | ||
| 357 | 357 | rtnl_unlock(); |
| 358 | 358 | } |
| 359 | 359 | |
| 360 | +static void cfg80211_propagate_radar_detect_wk(struct work_struct *work) | |
| 361 | +{ | |
| 362 | + struct cfg80211_registered_device *rdev; | |
| 363 | + | |
| 364 | + rdev = container_of(work, struct cfg80211_registered_device, | |
| 365 | + propagate_radar_detect_wk); | |
| 366 | + | |
| 367 | + rtnl_lock(); | |
| 368 | + | |
| 369 | + regulatory_propagate_dfs_state(&rdev->wiphy, &rdev->radar_chandef, | |
| 370 | + NL80211_DFS_UNAVAILABLE, | |
| 371 | + NL80211_RADAR_DETECTED); | |
| 372 | + | |
| 373 | + rtnl_unlock(); | |
| 374 | +} | |
| 375 | + | |
| 376 | +static void cfg80211_propagate_cac_done_wk(struct work_struct *work) | |
| 377 | +{ | |
| 378 | + struct cfg80211_registered_device *rdev; | |
| 379 | + | |
| 380 | + rdev = container_of(work, struct cfg80211_registered_device, | |
| 381 | + propagate_cac_done_wk); | |
| 382 | + | |
| 383 | + rtnl_lock(); | |
| 384 | + | |
| 385 | + regulatory_propagate_dfs_state(&rdev->wiphy, &rdev->cac_done_chandef, | |
| 386 | + NL80211_DFS_AVAILABLE, | |
| 387 | + NL80211_RADAR_CAC_FINISHED); | |
| 388 | + | |
| 389 | + rtnl_unlock(); | |
| 390 | +} | |
| 391 | + | |
| 360 | 392 | /* exported functions */ |
| 361 | 393 | |
| 362 | 394 | struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, |
| @@ -456,6 +488,9 @@ use_default_name: · 93 unmodified lines | ||
| 456 | 488 | spin_lock_init(&rdev->destroy_list_lock); |
| 457 | 489 | INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk); |
| 458 | 490 | INIT_WORK(&rdev->sched_scan_stop_wk, cfg80211_sched_scan_stop_wk); |
| 491 | + INIT_WORK(&rdev->propagate_radar_detect_wk, | |
| 492 | + cfg80211_propagate_radar_detect_wk); | |
| 493 | + INIT_WORK(&rdev->propagate_cac_done_wk, cfg80211_propagate_cac_done_wk); | |
| 459 | 494 | |
| 460 | 495 | #ifdef CONFIG_CFG80211_DEFAULT_PS |
| 461 | 496 | rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; |
| @@ -915,6 +950,8 @@ void wiphy_unregister(struct wiphy *wiphy) · 453 unmodified lines | ||
| 915 | 950 | flush_work(&rdev->destroy_work); |
| 916 | 951 | flush_work(&rdev->sched_scan_stop_wk); |
| 917 | 952 | flush_work(&rdev->mlme_unreg_wk); |
| 953 | + flush_work(&rdev->propagate_radar_detect_wk); | |
| 954 | + flush_work(&rdev->propagate_cac_done_wk); | |
| 918 | 955 | |
| 919 | 956 | #ifdef CONFIG_PM |
| 920 | 957 | if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) |
| @@ -954,6 +991,12 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked) · 33 unmodified lines | ||
| 954 | 991 | } |
| 955 | 992 | EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); |
| 956 | 993 | |
| 994 | +void cfg80211_cqm_config_free(struct wireless_dev *wdev) | |
| 995 | +{ | |
| 996 | + kfree(wdev->cqm_config); | |
| 997 | + wdev->cqm_config = NULL; | |
| 998 | +} | |
| 999 | + | |
| 957 | 1000 | void cfg80211_unregister_wdev(struct wireless_dev *wdev) |
| 958 | 1001 | { |
| 959 | 1002 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); |
| @@ -980,6 +1023,8 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) · 20 unmodified lines | ||
| 980 | 1023 | WARN_ON_ONCE(1); |
| 981 | 1024 | break; |
| 982 | 1025 | } |
| 1026 | + | |
| 1027 | + cfg80211_cqm_config_free(wdev); | |
| 983 | 1028 | } |
| 984 | 1029 | EXPORT_SYMBOL(cfg80211_unregister_wdev); |
| 985 | 1030 | |
| @@ -1114,7 +1159,15 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, · 128 unmodified lines | ||
| 1114 | 1159 | INIT_LIST_HEAD(&wdev->mgmt_registrations); |
| 1115 | 1160 | spin_lock_init(&wdev->mgmt_registrations_lock); |
| 1116 | 1161 | |
| 1117 | − wdev->identifier = ++rdev->wdev_id; | |
| 1162 | + /* | |
| 1163 | + * We get here also when the interface changes network namespaces, | |
| 1164 | + * as it's registered into the new one, but we don't want it to | |
| 1165 | + * change ID in that case. Checking if the ID is already assigned | |
| 1166 | + * works, because 0 isn't considered a valid ID and the memory is | |
| 1167 | + * 0-initialized. | |
| 1168 | + */ | |
| 1169 | + if (!wdev->identifier) | |
| 1170 | + wdev->identifier = ++rdev->wdev_id; | |
| 1118 | 1171 | list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list); |
| 1119 | 1172 | rdev->devlist_generation++; |
| 1120 | 1173 | /* can only change netns with wiphy */ |
| @@ -1208,12 +1261,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, · 87 unmodified lines | ||
| 1208 | 1261 | */ |
| 1209 | 1262 | if ((wdev->iftype == NL80211_IFTYPE_STATION || |
| 1210 | 1263 | wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) && |
| 1211 | − rdev->ops->set_power_mgmt) | |
| 1212 | − if (rdev_set_power_mgmt(rdev, dev, wdev->ps, | |
| 1213 | − wdev->ps_timeout)) { | |
| 1214 | − /* assume this means it's off */ | |
| 1215 | − wdev->ps = false; | |
| 1216 | − } | |
| 1264 | + rdev->ops->set_power_mgmt && | |
| 1265 | + rdev_set_power_mgmt(rdev, dev, wdev->ps, | |
| 1266 | + wdev->ps_timeout)) { | |
| 1267 | + /* assume this means it's off */ | |
| 1268 | + wdev->ps = false; | |
| 1269 | + } | |
| 1217 | 1270 | break; |
| 1218 | 1271 | case NETDEV_UNREGISTER: |
| 1219 | 1272 | /* |
| @@ -1234,6 +1287,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, · 14 unmodified lines | ||
| 1234 | 1287 | kzfree(wdev->wext.keys); |
| 1235 | 1288 | #endif |
| 1236 | 1289 | flush_work(&wdev->disconnect_wk); |
| 1290 | + cfg80211_cqm_config_free(wdev); | |
| 1237 | 1291 | } |
| 1238 | 1292 | /* |
| 1239 | 1293 | * synchronise (so that we won't find this netdev |
| @@ -97,6 +97,12 @@ struct cfg80211_registered_device { · 96 unmodified lines | ||
| 97 | 97 | |
| 98 | 98 | struct work_struct sched_scan_stop_wk; |
| 99 | 99 | |
| 100 | + struct cfg80211_chan_def radar_chandef; | |
| 101 | + struct work_struct propagate_radar_detect_wk; | |
| 102 | + | |
| 103 | + struct cfg80211_chan_def cac_done_chandef; | |
| 104 | + struct work_struct propagate_cac_done_wk; | |
| 105 | + | |
| 100 | 106 | /* must be last because of the way we do wiphy_priv(), |
| 101 | 107 | * and it should at least be aligned to NETDEV_ALIGN */ |
| 102 | 108 | struct wiphy wiphy __aligned(NETDEV_ALIGN); |
| @@ -220,16 +226,7 @@ struct cfg80211_event { · 117 unmodified lines | ||
| 220 | 226 | enum cfg80211_event_type type; |
| 221 | 227 | |
| 222 | 228 | union { |
| 223 | − struct { | |
| 224 | − u8 bssid[ETH_ALEN]; | |
| 225 | − const u8 *req_ie; | |
| 226 | − const u8 *resp_ie; | |
| 227 | − size_t req_ie_len; | |
| 228 | − size_t resp_ie_len; | |
| 229 | − struct cfg80211_bss *bss; | |
| 230 | − int status; /* -1 = failed; 0..65535 = status code */ | |
| 231 | − enum nl80211_timeout_reason timeout_reason; | |
| 232 | − } cr; | |
| 229 | + struct cfg80211_connect_resp_params cr; | |
| 233 | 230 | struct { |
| 234 | 231 | const u8 *req_ie; |
| 235 | 232 | const u8 *resp_ie; |
| @@ -272,6 +269,13 @@ struct cfg80211_iface_destroy { · 36 unmodified lines | ||
| 272 | 269 | u32 nlportid; |
| 273 | 270 | }; |
| 274 | 271 | |
| 272 | +struct cfg80211_cqm_config { | |
| 273 | + u32 rssi_hyst; | |
| 274 | + s32 last_rssi_event_value; | |
| 275 | + int n_rssi_thresholds; | |
| 276 | + s32 rssi_thresholds[0]; | |
| 277 | +}; | |
| 278 | + | |
| 275 | 279 | void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev); |
| 276 | 280 | |
| 277 | 281 | /* free object */ |
| @@ -385,12 +389,9 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, · 107 unmodified lines | ||
| 385 | 389 | struct cfg80211_connect_params *connect, |
| 386 | 390 | struct cfg80211_cached_keys *connkeys, |
| 387 | 391 | const u8 *prev_bssid); |
| 388 | −void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |
| 389 | − const u8 *req_ie, size_t req_ie_len, | |
| 390 | − const u8 *resp_ie, size_t resp_ie_len, | |
| 391 | − int status, bool wextev, | |
| 392 | − struct cfg80211_bss *bss, | |
| 393 | − enum nl80211_timeout_reason timeout_reason); | |
| 392 | +void __cfg80211_connect_result(struct net_device *dev, | |
| 393 | + struct cfg80211_connect_resp_params *params, | |
| 394 | + bool wextev); | |
| 394 | 395 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, |
| 395 | 396 | size_t ie_len, u16 reason, bool from_ap); |
| 396 | 397 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, |
| @@ -429,7 +430,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, · 32 unmodified lines | ||
| 429 | 430 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); |
| 430 | 431 | int cfg80211_change_iface(struct cfg80211_registered_device *rdev, |
| 431 | 432 | struct net_device *dev, enum nl80211_iftype ntype, |
| 432 | − u32 *flags, struct vif_params *params); | |
| 433 | + struct vif_params *params); | |
| 433 | 434 | void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); |
| 434 | 435 | void cfg80211_process_wdev_events(struct wireless_dev *wdev); |
| 435 | 436 | |
| @@ -459,6 +460,16 @@ unsigned int · 23 unmodified lines | ||
| 459 | 460 | cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy, |
| 460 | 461 | const struct cfg80211_chan_def *chandef); |
| 461 | 462 | |
| 463 | +void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev); | |
| 464 | + | |
| 465 | +bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, | |
| 466 | + struct ieee80211_channel *chan); | |
| 467 | + | |
| 468 | +bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev); | |
| 469 | + | |
| 470 | +bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef, | |
| 471 | + struct ieee80211_channel *chan); | |
| 472 | + | |
| 462 | 473 | static inline unsigned int elapsed_jiffies_msecs(unsigned long start) |
| 463 | 474 | { |
| 464 | 475 | unsigned long end = jiffies; |
| @@ -512,4 +523,6 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, · 47 unmodified lines | ||
| 512 | 523 | #define CFG80211_DEV_WARN_ON(cond) ({bool __r = (cond); __r; }) |
| 513 | 524 | #endif |
| 514 | 525 | |
| 526 | +void cfg80211_cqm_config_free(struct wireless_dev *wdev); | |
| 527 | + | |
| 515 | 528 | #endif /* __NET_WIRELESS_CORE_H */ |
| @@ -190,6 +190,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) · 189 unmodified lines | ||
| 190 | 190 | if (!nowext) |
| 191 | 191 | wdev->wext.ibss.ssid_len = 0; |
| 192 | 192 | #endif |
| 193 | + cfg80211_sched_dfs_chan_update(rdev); | |
| 193 | 194 | } |
| 194 | 195 | |
| 195 | 196 | void cfg80211_clear_ibss(struct net_device *dev, bool nowext) |
| @@ -262,6 +262,7 @@ int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, · 261 unmodified lines | ||
| 262 | 262 | wdev->beacon_interval = 0; |
| 263 | 263 | memset(&wdev->chandef, 0, sizeof(wdev->chandef)); |
| 264 | 264 | rdev_set_qos_map(rdev, dev, NULL); |
| 265 | + cfg80211_sched_dfs_chan_update(rdev); | |
| 265 | 266 | } |
| 266 | 267 | |
| 267 | 268 | return err; |
| @@ -26,9 +26,16 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, · 25 unmodified lines | ||
| 26 | 26 | struct wiphy *wiphy = wdev->wiphy; |
| 27 | 27 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
| 28 | 28 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
| 29 | − u8 *ie = mgmt->u.assoc_resp.variable; | |
| 30 | − int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); | |
| 31 | − u16 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | |
| 29 | + struct cfg80211_connect_resp_params cr; | |
| 30 | + | |
| 31 | + memset(&cr, 0, sizeof(cr)); | |
| 32 | + cr.status = (int)le16_to_cpu(mgmt->u.assoc_resp.status_code); | |
| 33 | + cr.bssid = mgmt->bssid; | |
| 34 | + cr.bss = bss; | |
| 35 | + cr.resp_ie = mgmt->u.assoc_resp.variable; | |
| 36 | + cr.resp_ie_len = | |
| 37 | + len - offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); | |
| 38 | + cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED; | |
| 32 | 39 | |
| 33 | 40 | trace_cfg80211_send_rx_assoc(dev, bss); |
| 34 | 41 | |
| @@ -38,7 +45,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, · 3 unmodified lines | ||
| 38 | 45 | * and got a reject -- we only try again with an assoc |
| 39 | 46 | * frame instead of reassoc. |
| 40 | 47 | */ |
| 41 | − if (cfg80211_sme_rx_assoc_resp(wdev, status_code)) { | |
| 48 | + if (cfg80211_sme_rx_assoc_resp(wdev, cr.status)) { | |
| 42 | 49 | cfg80211_unhold_bss(bss_from_pub(bss)); |
| 43 | 50 | cfg80211_put_bss(wiphy, bss); |
| 44 | 51 | return; |
| @@ -46,10 +53,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss, · 1 unmodified line | ||
| 46 | 53 | |
| 47 | 54 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL, uapsd_queues); |
| 48 | 55 | /* update current_bss etc., consumes the bss reference */ |
| 49 | − __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, | |
| 50 | − status_code, | |
| 51 | − status_code == WLAN_STATUS_SUCCESS, bss, | |
| 52 | − NL80211_TIMEOUT_UNSPECIFIED); | |
| 56 | + __cfg80211_connect_result(dev, &cr, cr.status == WLAN_STATUS_SUCCESS); | |
| 53 | 57 | } |
| 54 | 58 | EXPORT_SYMBOL(cfg80211_rx_assoc_resp); |
| 55 | 59 | |
| @@ -745,6 +749,12 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, · 689 unmodified lines | ||
| 745 | 749 | } |
| 746 | 750 | EXPORT_SYMBOL(cfg80211_rx_mgmt); |
| 747 | 751 | |
| 752 | +void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev) | |
| 753 | +{ | |
| 754 | + cancel_delayed_work(&rdev->dfs_update_channels_wk); | |
| 755 | + queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk, 0); | |
| 756 | +} | |
| 757 | + | |
| 748 | 758 | void cfg80211_dfs_channels_update_work(struct work_struct *work) |
| 749 | 759 | { |
| 750 | 760 | struct delayed_work *delayed_work = to_delayed_work(work); |
| @@ -755,6 +765,8 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work) · 4 unmodified lines | ||
| 755 | 765 | struct wiphy *wiphy; |
| 756 | 766 | bool check_again = false; |
| 757 | 767 | unsigned long timeout, next_time = 0; |
| 768 | + unsigned long time_dfs_update; | |
| 769 | + enum nl80211_radar_event radar_event; | |
| 758 | 770 | int bandid, i; |
| 759 | 771 | |
| 760 | 772 | rdev = container_of(delayed_work, struct cfg80211_registered_device, |
| @@ -770,11 +782,27 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work) · 9 unmodified lines | ||
| 770 | 782 | for (i = 0; i < sband->n_channels; i++) { |
| 771 | 783 | c = &sband->channels[i]; |
| 772 | 784 | |
| 773 | − if (c->dfs_state != NL80211_DFS_UNAVAILABLE) | |
| 785 | + if (!(c->flags & IEEE80211_CHAN_RADAR)) | |
| 786 | + continue; | |
| 787 | + | |
| 788 | + if (c->dfs_state != NL80211_DFS_UNAVAILABLE && | |
| 789 | + c->dfs_state != NL80211_DFS_AVAILABLE) | |
| 774 | 790 | continue; |
| 775 | 791 | |
| 776 | − timeout = c->dfs_state_entered + msecs_to_jiffies( | |
| 777 | − IEEE80211_DFS_MIN_NOP_TIME_MS); | |
| 792 | + if (c->dfs_state == NL80211_DFS_UNAVAILABLE) { | |
| 793 | + time_dfs_update = IEEE80211_DFS_MIN_NOP_TIME_MS; | |
| 794 | + radar_event = NL80211_RADAR_NOP_FINISHED; | |
| 795 | + } else { | |
| 796 | + if (regulatory_pre_cac_allowed(wiphy) || | |
| 797 | + cfg80211_any_wiphy_oper_chan(wiphy, c)) | |
| 798 | + continue; | |
| 799 | + | |
| 800 | + time_dfs_update = REG_PRE_CAC_EXPIRY_GRACE_MS; | |
| 801 | + radar_event = NL80211_RADAR_PRE_CAC_EXPIRED; | |
| 802 | + } | |
| 803 | + | |
| 804 | + timeout = c->dfs_state_entered + | |
| 805 | + msecs_to_jiffies(time_dfs_update); | |
| 778 | 806 | |
| 779 | 807 | if (time_after_eq(jiffies, timeout)) { |
| 780 | 808 | c->dfs_state = NL80211_DFS_USABLE; |
| @@ -784,8 +812,12 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work) · 3 unmodified lines | ||
| 784 | 812 | NL80211_CHAN_NO_HT); |
| 785 | 813 | |
| 786 | 814 | nl80211_radar_notify(rdev, &chandef, |
| 787 | − NL80211_RADAR_NOP_FINISHED, | |
| 788 | − NULL, GFP_ATOMIC); | |
| 815 | + radar_event, NULL, | |
| 816 | + GFP_ATOMIC); | |
| 817 | + | |
| 818 | + regulatory_propagate_dfs_state(wiphy, &chandef, | |
| 819 | + c->dfs_state, | |
| 820 | + radar_event); | |
| 789 | 821 | continue; |
| 790 | 822 | } |
| 791 | 823 | |
| @@ -810,7 +842,6 @@ void cfg80211_radar_event(struct wiphy *wiphy, · 18 unmodified lines | ||
| 810 | 842 | gfp_t gfp) |
| 811 | 843 | { |
| 812 | 844 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); |
| 813 | − unsigned long timeout; | |
| 814 | 845 | |
| 815 | 846 | trace_cfg80211_radar_event(wiphy, chandef); |
| 816 | 847 | |
| @@ -820,11 +851,12 @@ void cfg80211_radar_event(struct wiphy *wiphy, · 3 unmodified lines | ||
| 820 | 851 | */ |
| 821 | 852 | cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); |
| 822 | 853 | |
| 823 | − timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_NOP_TIME_MS); | |
| 824 | − queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk, | |
| 825 | − timeout); | |
| 854 | + cfg80211_sched_dfs_chan_update(rdev); | |
| 826 | 855 | |
| 827 | 856 | nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp); |
| 857 | + | |
| 858 | + memcpy(&rdev->radar_chandef, chandef, sizeof(struct cfg80211_chan_def)); | |
| 859 | + queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk); | |
| 828 | 860 | } |
| 829 | 861 | EXPORT_SYMBOL(cfg80211_radar_event); |
| 830 | 862 | |
| @@ -851,6 +883,10 @@ void cfg80211_cac_event(struct net_device *netdev, · 20 unmodified lines | ||
| 851 | 883 | msecs_to_jiffies(wdev->cac_time_ms); |
| 852 | 884 | WARN_ON(!time_after_eq(jiffies, timeout)); |
| 853 | 885 | cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); |
| 886 | + memcpy(&rdev->cac_done_chandef, chandef, | |
| 887 | + sizeof(struct cfg80211_chan_def)); | |
| 888 | + queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk); | |
| 889 | + cfg80211_sched_dfs_chan_update(rdev); | |
| 854 | 890 | break; |
| 855 | 891 | case NL80211_RADAR_CAC_ABORTED: |
| 856 | 892 | break; |
| @@ -410,6 +410,15 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { · 409 unmodified lines | ||
| 410 | 410 | .len = sizeof(struct nl80211_bss_select_rssi_adjust) |
| 411 | 411 | }, |
| 412 | 412 | [NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 }, |
| 413 | + [NL80211_ATTR_FILS_ERP_USERNAME] = { .type = NLA_BINARY, | |
| 414 | + .len = FILS_ERP_MAX_USERNAME_LEN }, | |
| 415 | + [NL80211_ATTR_FILS_ERP_REALM] = { .type = NLA_BINARY, | |
| 416 | + .len = FILS_ERP_MAX_REALM_LEN }, | |
| 417 | + [NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] = { .type = NLA_U16 }, | |
| 418 | + [NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY, | |
| 419 | + .len = FILS_ERP_MAX_RRK_LEN }, | |
| 420 | + [NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 }, | |
| 421 | + [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN }, | |
| 413 | 422 | }; |
| 414 | 423 | |
| 415 | 424 | /* policy for the key attributes */ |
| @@ -2705,9 +2714,74 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) · 2289 unmodified lines | ||
| 2705 | 2714 | if (flags[flag]) |
| 2706 | 2715 | *mntrflags |= (1<<flag); |
| 2707 | 2716 | |
| 2717 | + *mntrflags |= MONITOR_FLAG_CHANGED; | |
| 2718 | + | |
| 2708 | 2719 | return 0; |
| 2709 | 2720 | } |
| 2710 | 2721 | |
| 2722 | +static int nl80211_parse_mon_options(struct cfg80211_registered_device *rdev, | |
| 2723 | + enum nl80211_iftype type, | |
| 2724 | + struct genl_info *info, | |
| 2725 | + struct vif_params *params) | |
| 2726 | +{ | |
| 2727 | + bool change = false; | |
| 2728 | + int err; | |
| 2729 | + | |
| 2730 | + if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { | |
| 2731 | + if (type != NL80211_IFTYPE_MONITOR) | |
| 2732 | + return -EINVAL; | |
| 2733 | + | |
| 2734 | + err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], | |
| 2735 | + ¶ms->flags); | |
| 2736 | + if (err) | |
| 2737 | + return err; | |
| 2738 | + | |
| 2739 | + change = true; | |
| 2740 | + } | |
| 2741 | + | |
| 2742 | + if (params->flags & MONITOR_FLAG_ACTIVE && | |
| 2743 | + !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR)) | |
| 2744 | + return -EOPNOTSUPP; | |
| 2745 | + | |
| 2746 | + if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) { | |
| 2747 | + const u8 *mumimo_groups; | |
| 2748 | + u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER; | |
| 2749 | + | |
| 2750 | + if (type != NL80211_IFTYPE_MONITOR) | |
| 2751 | + return -EINVAL; | |
| 2752 | + | |
| 2753 | + if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag)) | |
| 2754 | + return -EOPNOTSUPP; | |
| 2755 | + | |
| 2756 | + mumimo_groups = | |
| 2757 | + nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]); | |
| 2758 | + | |
| 2759 | + /* bits 0 and 63 are reserved and must be zero */ | |
| 2760 | + if ((mumimo_groups[0] & BIT(7)) || | |
| 2761 | + (mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(0))) | |
| 2762 | + return -EINVAL; | |
| 2763 | + | |
| 2764 | + params->vht_mumimo_groups = mumimo_groups; | |
| 2765 | + change = true; | |
| 2766 | + } | |
| 2767 | + | |
| 2768 | + if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) { | |
| 2769 | + u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER; | |
| 2770 | + | |
| 2771 | + if (type != NL80211_IFTYPE_MONITOR) | |
| 2772 | + return -EINVAL; | |
| 2773 | + | |
| 2774 | + if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag)) | |
| 2775 | + return -EOPNOTSUPP; | |
| 2776 | + | |
| 2777 | + params->vht_mumimo_follow_addr = | |
| 2778 | + nla_data(info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]); | |
| 2779 | + change = true; | |
| 2780 | + } | |
| 2781 | + | |
| 2782 | + return change ? 1 : 0; | |
| 2783 | +} | |
| 2784 | + | |
| 2711 | 2785 | static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, |
| 2712 | 2786 | struct net_device *netdev, u8 use_4addr, |
| 2713 | 2787 | enum nl80211_iftype iftype) |
| @@ -2741,7 +2815,6 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) · 27 unmodified lines | ||
| 2741 | 2815 | int err; |
| 2742 | 2816 | enum nl80211_iftype otype, ntype; |
| 2743 | 2817 | struct net_device *dev = info->user_ptr[1]; |
| 2744 | − u32 _flags, *flags = NULL; | |
| 2745 | 2818 | bool change = false; |
| 2746 | 2819 | |
| 2747 | 2820 | memset(¶ms, 0, sizeof(params)); |
| @@ -2784,56 +2857,14 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) · 36 unmodified lines | ||
| 2784 | 2857 | params.use_4addr = -1; |
| 2785 | 2858 | } |
| 2786 | 2859 | |
| 2787 | − if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { | |
| 2788 | − if (ntype != NL80211_IFTYPE_MONITOR) | |
| 2789 | − return -EINVAL; | |
| 2790 | − err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], | |
| 2791 | − &_flags); | |
| 2792 | − if (err) | |
| 2793 | − return err; | |
| 2794 | − | |
| 2795 | − flags = &_flags; | |
| 2796 | − change = true; | |
| 2797 | − } | |
| 2798 | − | |
| 2799 | − if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) { | |
| 2800 | − const u8 *mumimo_groups; | |
| 2801 | − u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER; | |
| 2802 | − | |
| 2803 | − if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag)) | |
| 2804 | − return -EOPNOTSUPP; | |
| 2805 | − | |
| 2806 | − mumimo_groups = | |
| 2807 | − nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]); | |
| 2808 | − | |
| 2809 | − /* bits 0 and 63 are reserved and must be zero */ | |
| 2810 | − if ((mumimo_groups[0] & BIT(7)) || | |
| 2811 | − (mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(0))) | |
| 2812 | − return -EINVAL; | |
| 2813 | − | |
| 2814 | − memcpy(params.vht_mumimo_groups, mumimo_groups, | |
| 2815 | − VHT_MUMIMO_GROUPS_DATA_LEN); | |
| 2816 | − change = true; | |
| 2817 | − } | |
| 2818 | − | |
| 2819 | − if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) { | |
| 2820 | − u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER; | |
| 2821 | − | |
| 2822 | − if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag)) | |
| 2823 | − return -EOPNOTSUPP; | |
| 2824 | − | |
| 2825 | − nla_memcpy(params.macaddr, | |
| 2826 | − info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR], | |
| 2827 | − ETH_ALEN); | |
| 2860 | + err = nl80211_parse_mon_options(rdev, ntype, info, ¶ms); | |
| 2861 | + if (err < 0) | |
| 2862 | + return err; | |
| 2863 | + if (err > 0) | |
| 2828 | 2864 | change = true; |
| 2829 | − } | |
| 2830 | − | |
| 2831 | − if (flags && (*flags & MONITOR_FLAG_ACTIVE) && | |
| 2832 | − !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR)) | |
| 2833 | − return -EOPNOTSUPP; | |
| 2834 | 2865 | |
| 2835 | 2866 | if (change) |
| 2836 | − err = cfg80211_change_iface(rdev, dev, ntype, flags, ¶ms); | |
| 2867 | + err = cfg80211_change_iface(rdev, dev, ntype, ¶ms); | |
| 2837 | 2868 | else |
| 2838 | 2869 | err = 0; |
| 2839 | 2870 | |
| @@ -2851,7 +2882,6 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) · 11 unmodified lines | ||
| 2851 | 2882 | struct sk_buff *msg; |
| 2852 | 2883 | int err; |
| 2853 | 2884 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
| 2854 | − u32 flags; | |
| 2855 | 2885 | |
| 2856 | 2886 | /* to avoid failing a new interface creation due to pending removal */ |
| 2857 | 2887 | cfg80211_destroy_ifaces(rdev); |
| @@ -2887,13 +2917,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) · 29 unmodified lines | ||
| 2887 | 2917 | return err; |
| 2888 | 2918 | } |
| 2889 | 2919 | |
| 2890 | − err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | |
| 2891 | − info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | |
| 2892 | − &flags); | |
| 2893 | − | |
| 2894 | − if (!err && (flags & MONITOR_FLAG_ACTIVE) && | |
| 2895 | − !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR)) | |
| 2896 | − return -EOPNOTSUPP; | |
| 2920 | + err = nl80211_parse_mon_options(rdev, type, info, ¶ms); | |
| 2921 | + if (err < 0) | |
| 2922 | + return err; | |
| 2897 | 2923 | |
| 2898 | 2924 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
| 2899 | 2925 | if (!msg) |
| @@ -2901,8 +2927,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) · 1 unmodified line | ||
| 2901 | 2927 | |
| 2902 | 2928 | wdev = rdev_add_virtual_intf(rdev, |
| 2903 | 2929 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
| 2904 | − NET_NAME_USER, type, err ? NULL : &flags, | |
| 2905 | − ¶ms); | |
| 2930 | + NET_NAME_USER, type, ¶ms); | |
| 2906 | 2931 | if (WARN_ON(!wdev)) { |
| 2907 | 2932 | nlmsg_free(msg); |
| 2908 | 2933 | return -EPROTO; |
| @@ -3820,6 +3845,19 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev, · 911 unmodified lines | ||
| 3820 | 3845 | return false; |
| 3821 | 3846 | return true; |
| 3822 | 3847 | case NL80211_CMD_CONNECT: |
| 3848 | + /* SAE not supported yet */ | |
| 3849 | + if (auth_type == NL80211_AUTHTYPE_SAE) | |
| 3850 | + return false; | |
| 3851 | + /* FILS with SK PFS or PK not supported yet */ | |
| 3852 | + if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS || | |
| 3853 | + auth_type == NL80211_AUTHTYPE_FILS_PK) | |
| 3854 | + return false; | |
| 3855 | + if (!wiphy_ext_feature_isset( | |
| 3856 | + &rdev->wiphy, | |
| 3857 | + NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) && | |
| 3858 | + auth_type == NL80211_AUTHTYPE_FILS_SK) | |
| 3859 | + return false; | |
| 3860 | + return true; | |
| 3823 | 3861 | case NL80211_CMD_START_AP: |
| 3824 | 3862 | /* SAE not supported yet */ |
| 3825 | 3863 | if (auth_type == NL80211_AUTHTYPE_SAE) |
| @@ -4153,7 +4191,7 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, · 327 unmodified lines | ||
| 4153 | 4191 | struct nlattr *rate; |
| 4154 | 4192 | u32 bitrate; |
| 4155 | 4193 | u16 bitrate_compat; |
| 4156 | − enum nl80211_attrs rate_flg; | |
| 4194 | + enum nl80211_rate_info rate_flg; | |
| 4157 | 4195 | |
| 4158 | 4196 | rate = nla_nest_start(msg, attr); |
| 4159 | 4197 | if (!rate) |
| @@ -5705,7 +5743,7 @@ static int nl80211_get_mesh_config(struct sk_buff *skb, · 1545 unmodified lines | ||
| 5705 | 5743 | cur_params.dot11MeshGateAnnouncementProtocol) || |
| 5706 | 5744 | nla_put_u8(msg, NL80211_MESHCONF_FORWARDING, |
| 5707 | 5745 | cur_params.dot11MeshForwarding) || |
| 5708 | − nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD, | |
| 5746 | + nla_put_s32(msg, NL80211_MESHCONF_RSSI_THRESHOLD, | |
| 5709 | 5747 | cur_params.rssi_threshold) || |
| 5710 | 5748 | nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE, |
| 5711 | 5749 | cur_params.ht_opmode) || |
| @@ -6548,6 +6586,19 @@ static int nl80211_parse_random_mac(struct nlattr **attrs, · 836 unmodified lines | ||
| 6548 | 6586 | return 0; |
| 6549 | 6587 | } |
| 6550 | 6588 | |
| 6589 | +static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev) | |
| 6590 | +{ | |
| 6591 | + ASSERT_WDEV_LOCK(wdev); | |
| 6592 | + | |
| 6593 | + if (!cfg80211_beaconing_iface_active(wdev)) | |
| 6594 | + return true; | |
| 6595 | + | |
| 6596 | + if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR)) | |
| 6597 | + return true; | |
| 6598 | + | |
| 6599 | + return regulatory_pre_cac_allowed(wdev->wiphy); | |
| 6600 | +} | |
| 6601 | + | |
| 6551 | 6602 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
| 6552 | 6603 | { |
| 6553 | 6604 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| @@ -6673,6 +6724,25 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) · 119 unmodified lines | ||
| 6673 | 6724 | |
| 6674 | 6725 | request->n_channels = i; |
| 6675 | 6726 | |
| 6727 | + wdev_lock(wdev); | |
| 6728 | + if (!cfg80211_off_channel_oper_allowed(wdev)) { | |
| 6729 | + struct ieee80211_channel *chan; | |
| 6730 | + | |
| 6731 | + if (request->n_channels != 1) { | |
| 6732 | + wdev_unlock(wdev); | |
| 6733 | + err = -EBUSY; | |
| 6734 | + goto out_free; | |
| 6735 | + } | |
| 6736 | + | |
| 6737 | + chan = request->channels[0]; | |
| 6738 | + if (chan->center_freq != wdev->chandef.chan->center_freq) { | |
| 6739 | + wdev_unlock(wdev); | |
| 6740 | + err = -EBUSY; | |
| 6741 | + goto out_free; | |
| 6742 | + } | |
| 6743 | + } | |
| 6744 | + wdev_unlock(wdev); | |
| 6745 | + | |
| 6676 | 6746 | i = 0; |
| 6677 | 6747 | if (n_ssids) { |
| 6678 | 6748 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) { |
| @@ -7295,8 +7365,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, · 616 unmodified lines | ||
| 7295 | 7365 | |
| 7296 | 7366 | rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req); |
| 7297 | 7367 | |
| 7298 | − nl80211_send_sched_scan(rdev, dev, | |
| 7299 | − NL80211_CMD_START_SCHED_SCAN); | |
| 7368 | + nl80211_send_sched_scan(sched_scan_req, NL80211_CMD_START_SCHED_SCAN); | |
| 7300 | 7369 | return 0; |
| 7301 | 7370 | |
| 7302 | 7371 | out_free: |
| @@ -8873,6 +8942,35 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) · 1570 unmodified lines | ||
| 8873 | 8942 | } |
| 8874 | 8943 | } |
| 8875 | 8944 | |
| 8945 | + if (wiphy_ext_feature_isset(&rdev->wiphy, | |
| 8946 | + NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) && | |
| 8947 | + info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] && | |
| 8948 | + info->attrs[NL80211_ATTR_FILS_ERP_REALM] && | |
| 8949 | + info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] && | |
| 8950 | + info->attrs[NL80211_ATTR_FILS_ERP_RRK]) { | |
| 8951 | + connect.fils_erp_username = | |
| 8952 | + nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]); | |
| 8953 | + connect.fils_erp_username_len = | |
| 8954 | + nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]); | |
| 8955 | + connect.fils_erp_realm = | |
| 8956 | + nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]); | |
| 8957 | + connect.fils_erp_realm_len = | |
| 8958 | + nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]); | |
| 8959 | + connect.fils_erp_next_seq_num = | |
| 8960 | + nla_get_u16( | |
| 8961 | + info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]); | |
| 8962 | + connect.fils_erp_rrk = | |
| 8963 | + nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]); | |
| 8964 | + connect.fils_erp_rrk_len = | |
| 8965 | + nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]); | |
| 8966 | + } else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] || | |
| 8967 | + info->attrs[NL80211_ATTR_FILS_ERP_REALM] || | |
| 8968 | + info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] || | |
| 8969 | + info->attrs[NL80211_ATTR_FILS_ERP_RRK]) { | |
| 8970 | + kzfree(connkeys); | |
| 8971 | + return -EINVAL; | |
| 8972 | + } | |
| 8973 | + | |
| 8876 | 8974 | wdev_lock(dev->ieee80211_ptr); |
| 8877 | 8975 | |
| 8878 | 8976 | err = cfg80211_connect(rdev, dev, &connect, connkeys, |
| @@ -8992,14 +9090,28 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info) · 113 unmodified lines | ||
| 8992 | 9090 | |
| 8993 | 9091 | memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); |
| 8994 | 9092 | |
| 8995 | − if (!info->attrs[NL80211_ATTR_MAC]) | |
| 8996 | − return -EINVAL; | |
| 8997 | − | |
| 8998 | 9093 | if (!info->attrs[NL80211_ATTR_PMKID]) |
| 8999 | 9094 | return -EINVAL; |
| 9000 | 9095 | |
| 9001 | 9096 | pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]); |
| 9002 | − pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | |
| 9097 | + | |
| 9098 | + if (info->attrs[NL80211_ATTR_MAC]) { | |
| 9099 | + pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | |
| 9100 | + } else if (info->attrs[NL80211_ATTR_SSID] && | |
| 9101 | + info->attrs[NL80211_ATTR_FILS_CACHE_ID] && | |
| 9102 | + (info->genlhdr->cmd == NL80211_CMD_DEL_PMKSA || | |
| 9103 | + info->attrs[NL80211_ATTR_PMK])) { | |
| 9104 | + pmksa.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | |
| 9105 | + pmksa.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | |
| 9106 | + pmksa.cache_id = | |
| 9107 | + nla_data(info->attrs[NL80211_ATTR_FILS_CACHE_ID]); | |
| 9108 | + } else { | |
| 9109 | + return -EINVAL; | |
| 9110 | + } | |
| 9111 | + if (info->attrs[NL80211_ATTR_PMK]) { | |
| 9112 | + pmksa.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]); | |
| 9113 | + pmksa.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]); | |
| 9114 | + } | |
| 9003 | 9115 | |
| 9004 | 9116 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
| 9005 | 9117 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT) |
| @@ -9102,6 +9214,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, · 96 unmodified lines | ||
| 9102 | 9214 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| 9103 | 9215 | struct wireless_dev *wdev = info->user_ptr[1]; |
| 9104 | 9216 | struct cfg80211_chan_def chandef; |
| 9217 | + const struct cfg80211_chan_def *compat_chandef; | |
| 9105 | 9218 | struct sk_buff *msg; |
| 9106 | 9219 | void *hdr; |
| 9107 | 9220 | u64 cookie; |
| @@ -9130,6 +9243,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, · 22 unmodified lines | ||
| 9130 | 9243 | if (err) |
| 9131 | 9244 | return err; |
| 9132 | 9245 | |
| 9246 | + wdev_lock(wdev); | |
| 9247 | + if (!cfg80211_off_channel_oper_allowed(wdev) && | |
| 9248 | + !cfg80211_chandef_identical(&wdev->chandef, &chandef)) { | |
| 9249 | + compat_chandef = cfg80211_chandef_compatible(&wdev->chandef, | |
| 9250 | + &chandef); | |
| 9251 | + if (compat_chandef != &chandef) { | |
| 9252 | + wdev_unlock(wdev); | |
| 9253 | + return -EBUSY; | |
| 9254 | + } | |
| 9255 | + } | |
| 9256 | + wdev_unlock(wdev); | |
| 9257 | + | |
| 9133 | 9258 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
| 9134 | 9259 | if (!msg) |
| 9135 | 9260 | return -ENOMEM; |
| @@ -9305,6 +9430,13 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) · 169 unmodified lines | ||
| 9305 | 9430 | if (!chandef.chan && params.offchan) |
| 9306 | 9431 | return -EINVAL; |
| 9307 | 9432 | |
| 9433 | + wdev_lock(wdev); | |
| 9434 | + if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev)) { | |
| 9435 | + wdev_unlock(wdev); | |
| 9436 | + return -EBUSY; | |
| 9437 | + } | |
| 9438 | + wdev_unlock(wdev); | |
| 9439 | + | |
| 9308 | 9440 | params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); |
| 9309 | 9441 | params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]); |
| 9310 | 9442 | |
| @@ -9472,7 +9604,7 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info) · 161 unmodified lines | ||
| 9472 | 9604 | |
| 9473 | 9605 | static const struct nla_policy |
| 9474 | 9606 | nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { |
| 9475 | − [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, | |
| 9607 | + [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_BINARY }, | |
| 9476 | 9608 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, |
| 9477 | 9609 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, |
| 9478 | 9610 | [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 }, |
| @@ -9501,28 +9633,123 @@ static int nl80211_set_cqm_txe(struct genl_info *info, · 22 unmodified lines | ||
| 9501 | 9633 | return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl); |
| 9502 | 9634 | } |
| 9503 | 9635 | |
| 9636 | +static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev, | |
| 9637 | + struct net_device *dev) | |
| 9638 | +{ | |
| 9639 | + struct wireless_dev *wdev = dev->ieee80211_ptr; | |
| 9640 | + s32 last, low, high; | |
| 9641 | + u32 hyst; | |
| 9642 | + int i, n; | |
| 9643 | + int err; | |
| 9644 | + | |
| 9645 | + /* RSSI reporting disabled? */ | |
| 9646 | + if (!wdev->cqm_config) | |
| 9647 | + return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0); | |
| 9648 | + | |
| 9649 | + /* | |
| 9650 | + * Obtain current RSSI value if possible, if not and no RSSI threshold | |
| 9651 | + * event has been received yet, we should receive an event after a | |
| 9652 | + * connection is established and enough beacons received to calculate | |
| 9653 | + * the average. | |
| 9654 | + */ | |
| 9655 | + if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss && | |
| 9656 | + rdev->ops->get_station) { | |
| 9657 | + struct station_info sinfo; | |
| 9658 | + u8 *mac_addr; | |
| 9659 | + | |
| 9660 | + mac_addr = wdev->current_bss->pub.bssid; | |
| 9661 | + | |
| 9662 | + err = rdev_get_station(rdev, dev, mac_addr, &sinfo); | |
| 9663 | + if (err) | |
| 9664 | + return err; | |
| 9665 | + | |
| 9666 | + if (sinfo.filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG)) | |
| 9667 | + wdev->cqm_config->last_rssi_event_value = | |
| 9668 | + (s8) sinfo.rx_beacon_signal_avg; | |
| 9669 | + } | |
| 9670 | + | |
| 9671 | + last = wdev->cqm_config->last_rssi_event_value; | |
| 9672 | + hyst = wdev->cqm_config->rssi_hyst; | |
| 9673 | + n = wdev->cqm_config->n_rssi_thresholds; | |
| 9674 | + | |
| 9675 | + for (i = 0; i < n; i++) | |
| 9676 | + if (last < wdev->cqm_config->rssi_thresholds[i]) | |
| 9677 | + break; | |
| 9678 | + | |
| 9679 | + low = i > 0 ? | |
| 9680 | + (wdev->cqm_config->rssi_thresholds[i - 1] - hyst) : S32_MIN; | |
| 9681 | + high = i < n ? | |
| 9682 | + (wdev->cqm_config->rssi_thresholds[i] + hyst - 1) : S32_MAX; | |
| 9683 | + | |
| 9684 | + return rdev_set_cqm_rssi_range_config(rdev, dev, low, high); | |
| 9685 | +} | |
| 9686 | + | |
| 9504 | 9687 | static int nl80211_set_cqm_rssi(struct genl_info *info, |
| 9505 | − s32 threshold, u32 hysteresis) | |
| 9688 | + const s32 *thresholds, int n_thresholds, | |
| 9689 | + u32 hysteresis) | |
| 9506 | 9690 | { |
| 9507 | 9691 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
| 9508 | 9692 | struct net_device *dev = info->user_ptr[1]; |
| 9509 | 9693 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 9694 | + int i, err; | |
| 9695 | + s32 prev = S32_MIN; | |
| 9510 | 9696 | |
| 9511 | − if (threshold > 0) | |
| 9512 | − return -EINVAL; | |
| 9513 | − | |
| 9514 | − /* disabling - hysteresis should also be zero then */ | |
| 9515 | − if (threshold == 0) | |
| 9516 | − hysteresis = 0; | |
| 9697 | + /* Check all values negative and sorted */ | |
| 9698 | + for (i = 0; i < n_thresholds; i++) { | |
| 9699 | + if (thresholds[i] > 0 || thresholds[i] <= prev) | |
| 9700 | + return -EINVAL; | |
| 9517 | 9701 | |
| 9518 | − if (!rdev->ops->set_cqm_rssi_config) | |
| 9519 | − return -EOPNOTSUPP; | |
| 9702 | + prev = thresholds[i]; | |
| 9703 | + } | |
| 9520 | 9704 | |
| 9521 | 9705 | if (wdev->iftype != NL80211_IFTYPE_STATION && |
| 9522 | 9706 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) |
| 9523 | 9707 | return -EOPNOTSUPP; |
| 9524 | 9708 | |
| 9525 | − return rdev_set_cqm_rssi_config(rdev, dev, threshold, hysteresis); | |
| 9709 | + wdev_lock(wdev); | |
| 9710 | + cfg80211_cqm_config_free(wdev); | |
| 9711 | + wdev_unlock(wdev); | |
| 9712 | + | |
| 9713 | + if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) { | |
| 9714 | + if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */ | |
| 9715 | + return rdev_set_cqm_rssi_config(rdev, dev, 0, 0); | |
| 9716 | + | |
| 9717 | + return rdev_set_cqm_rssi_config(rdev, dev, | |
| 9718 | + thresholds[0], hysteresis); | |
| 9719 | + } | |
| 9720 | + | |
| 9721 | + if (!wiphy_ext_feature_isset(&rdev->wiphy, | |
| 9722 | + NL80211_EXT_FEATURE_CQM_RSSI_LIST)) | |
| 9723 | + return -EOPNOTSUPP; | |
| 9724 | + | |
| 9725 | + if (n_thresholds == 1 && thresholds[0] == 0) /* Disabling */ | |
| 9726 | + n_thresholds = 0; | |
| 9727 | + | |
| 9728 | + wdev_lock(wdev); | |
| 9729 | + if (n_thresholds) { | |
| 9730 | + struct cfg80211_cqm_config *cqm_config; | |
| 9731 | + | |
| 9732 | + cqm_config = kzalloc(sizeof(struct cfg80211_cqm_config) + | |
| 9733 | + n_thresholds * sizeof(s32), GFP_KERNEL); | |
| 9734 | + if (!cqm_config) { | |
| 9735 | + err = -ENOMEM; | |
| 9736 | + goto unlock; | |
| 9737 | + } | |
| 9738 | + | |
| 9739 | + cqm_config->rssi_hyst = hysteresis; | |
| 9740 | + cqm_config->n_rssi_thresholds = n_thresholds; | |
| 9741 | + memcpy(cqm_config->rssi_thresholds, thresholds, | |
| 9742 | + n_thresholds * sizeof(s32)); | |
| 9743 | + | |
| 9744 | + wdev->cqm_config = cqm_config; | |
| 9745 | + } | |
| 9746 | + | |
| 9747 | + err = cfg80211_cqm_rssi_update(rdev, dev); | |
| 9748 | + | |
| 9749 | +unlock: | |
| 9750 | + wdev_unlock(wdev); | |
| 9751 | + | |
| 9752 | + return err; | |
| 9526 | 9753 | } |
| 9527 | 9754 | |
| 9528 | 9755 | static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) |
| @@ -9542,10 +9769,16 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) · 13 unmodified lines | ||
| 9542 | 9769 | |
| 9543 | 9770 | if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] && |
| 9544 | 9771 | attrs[NL80211_ATTR_CQM_RSSI_HYST]) { |
| 9545 | − s32 threshold = nla_get_s32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); | |
| 9772 | + const s32 *thresholds = | |
| 9773 | + nla_data(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); | |
| 9774 | + int len = nla_len(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); | |
| 9546 | 9775 | u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); |
| 9547 | 9776 | |
| 9548 | − return nl80211_set_cqm_rssi(info, threshold, hysteresis); | |
| 9777 | + if (len % 4) | |
| 9778 | + return -EINVAL; | |
| 9779 | + | |
| 9780 | + return nl80211_set_cqm_rssi(info, thresholds, len / 4, | |
| 9781 | + hysteresis); | |
| 9549 | 9782 | } |
| 9550 | 9783 | |
| 9551 | 9784 | if (attrs[NL80211_ATTR_CQM_TXE_RATE] && |
| @@ -12977,18 +13210,19 @@ static int nl80211_prep_scan_msg(struct sk_buff *msg, · 3425 unmodified lines | ||
| 12977 | 13210 | |
| 12978 | 13211 | static int |
| 12979 | 13212 | nl80211_prep_sched_scan_msg(struct sk_buff *msg, |
| 12980 | − struct cfg80211_registered_device *rdev, | |
| 12981 | − struct net_device *netdev, | |
| 12982 | − u32 portid, u32 seq, int flags, u32 cmd) | |
| 13213 | + struct cfg80211_sched_scan_request *req, u32 cmd) | |
| 12983 | 13214 | { |
| 12984 | 13215 | void *hdr; |
| 12985 | 13216 | |
| 12986 | − hdr = nl80211hdr_put(msg, portid, seq, flags, cmd); | |
| 13217 | + hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); | |
| 12987 | 13218 | if (!hdr) |
| 12988 | 13219 | return -1; |
| 12989 | 13220 | |
| 12990 | − if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | |
| 12991 | − nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex)) | |
| 13221 | + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, | |
| 13222 | + wiphy_to_rdev(req->wiphy)->wiphy_idx) || | |
| 13223 | + nla_put_u32(msg, NL80211_ATTR_IFINDEX, req->dev->ifindex) || | |
| 13224 | + nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->reqid, | |
| 13225 | + NL80211_ATTR_PAD)) | |
| 12992 | 13226 | goto nla_put_failure; |
| 12993 | 13227 | |
| 12994 | 13228 | genlmsg_end(msg, hdr); |
| @@ -13048,8 +13282,7 @@ void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev, · 53 unmodified lines | ||
| 13048 | 13282 | NL80211_MCGRP_SCAN, GFP_KERNEL); |
| 13049 | 13283 | } |
| 13050 | 13284 | |
| 13051 | −void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, | |
| 13052 | − struct net_device *netdev, u32 cmd) | |
| 13285 | +void nl80211_send_sched_scan(struct cfg80211_sched_scan_request *req, u32 cmd) | |
| 13053 | 13286 | { |
| 13054 | 13287 | struct sk_buff *msg; |
| 13055 | 13288 | |
| @@ -13057,12 +13290,12 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, · 1 unmodified line | ||
| 13057 | 13290 | if (!msg) |
| 13058 | 13291 | return; |
| 13059 | 13292 | |
| 13060 | − if (nl80211_prep_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) { | |
| 13293 | + if (nl80211_prep_sched_scan_msg(msg, req, cmd) < 0) { | |
| 13061 | 13294 | nlmsg_free(msg); |
| 13062 | 13295 | return; |
| 13063 | 13296 | } |
| 13064 | 13297 | |
| 13065 | − genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, | |
| 13298 | + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(req->wiphy), msg, 0, | |
| 13066 | 13299 | NL80211_MCGRP_SCAN, GFP_KERNEL); |
| 13067 | 13300 | } |
| 13068 | 13301 | |
| @@ -13303,17 +13536,16 @@ void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, · 234 unmodified lines | ||
| 13303 | 13536 | } |
| 13304 | 13537 | |
| 13305 | 13538 | void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, |
| 13306 | − struct net_device *netdev, const u8 *bssid, | |
| 13307 | − const u8 *req_ie, size_t req_ie_len, | |
| 13308 | − const u8 *resp_ie, size_t resp_ie_len, | |
| 13309 | − int status, | |
| 13310 | − enum nl80211_timeout_reason timeout_reason, | |
| 13539 | + struct net_device *netdev, | |
| 13540 | + struct cfg80211_connect_resp_params *cr, | |
| 13311 | 13541 | gfp_t gfp) |
| 13312 | 13542 | { |
| 13313 | 13543 | struct sk_buff *msg; |
| 13314 | 13544 | void *hdr; |
| 13315 | 13545 | |
| 13316 | − msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp); | |
| 13546 | + msg = nlmsg_new(100 + cr->req_ie_len + cr->resp_ie_len + | |
| 13547 | + cr->fils_kek_len + cr->pmk_len + | |
| 13548 | + (cr->pmkid ? WLAN_PMKID_LEN : 0), gfp); | |
| 13317 | 13549 | if (!msg) |
| 13318 | 13550 | return; |
| 13319 | 13551 | |
| @@ -13325,17 +13557,31 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, · 5 unmodified lines | ||
| 13325 | 13557 | |
| 13326 | 13558 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
| 13327 | 13559 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || |
| 13328 | − (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) || | |
| 13560 | + (cr->bssid && | |
| 13561 | + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, cr->bssid)) || | |
| 13329 | 13562 | nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, |
| 13330 | − status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE : | |
| 13331 | − status) || | |
| 13332 | − (status < 0 && | |
| 13563 | + cr->status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE : | |
| 13564 | + cr->status) || | |
| 13565 | + (cr->status < 0 && | |
| 13333 | 13566 | (nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) || |
| 13334 | − nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON, timeout_reason))) || | |
| 13335 | − (req_ie && | |
| 13336 | − nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) || | |
| 13337 | − (resp_ie && | |
| 13338 | − nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie))) | |
| 13567 | + nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON, | |
| 13568 | + cr->timeout_reason))) || | |
| 13569 | + (cr->req_ie && | |
| 13570 | + nla_put(msg, NL80211_ATTR_REQ_IE, cr->req_ie_len, cr->req_ie)) || | |
| 13571 | + (cr->resp_ie && | |
| 13572 | + nla_put(msg, NL80211_ATTR_RESP_IE, cr->resp_ie_len, | |
| 13573 | + cr->resp_ie)) || | |
| 13574 | + (cr->update_erp_next_seq_num && | |
| 13575 | + nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM, | |
| 13576 | + cr->fils_erp_next_seq_num)) || | |
| 13577 | + (cr->status == WLAN_STATUS_SUCCESS && | |
| 13578 | + ((cr->fils_kek && | |
| 13579 | + nla_put(msg, NL80211_ATTR_FILS_KEK, cr->fils_kek_len, | |
| 13580 | + cr->fils_kek)) || | |
| 13581 | + (cr->pmk && | |
| 13582 | + nla_put(msg, NL80211_ATTR_PMK, cr->pmk_len, cr->pmk)) || | |
| 13583 | + (cr->pmkid && | |
| 13584 | + nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->pmkid))))) | |
| 13339 | 13585 | goto nla_put_failure; |
| 13340 | 13586 | |
| 13341 | 13587 | genlmsg_end(msg, hdr); |
| @@ -13975,6 +14221,8 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, · 633 unmodified lines | ||
| 13975 | 14221 | s32 rssi_level, gfp_t gfp) |
| 13976 | 14222 | { |
| 13977 | 14223 | struct sk_buff *msg; |
| 14224 | + struct wireless_dev *wdev = dev->ieee80211_ptr; | |
| 14225 | + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); | |
| 13978 | 14226 | |
| 13979 | 14227 | trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level); |
| 13980 | 14228 | |
| @@ -13982,6 +14230,15 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, · 1 unmodified line | ||
| 13982 | 14230 | rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH)) |
| 13983 | 14231 | return; |
| 13984 | 14232 | |
| 14233 | + if (wdev->cqm_config) { | |
| 14234 | + wdev->cqm_config->last_rssi_event_value = rssi_level; | |
| 14235 | + | |
| 14236 | + cfg80211_cqm_rssi_update(rdev, dev); | |
| 14237 | + | |
| 14238 | + if (rssi_level == 0) | |
| 14239 | + rssi_level = wdev->cqm_config->last_rssi_event_value; | |
| 14240 | + } | |
| 14241 | + | |
| 13985 | 14242 | msg = cfg80211_prepare_cqm(dev, NULL, gfp); |
| 13986 | 14243 | if (!msg) |
| 13987 | 14244 | return; |
| @@ -16,8 +16,7 @@ struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev, · 15 unmodified lines | ||
| 16 | 16 | struct wireless_dev *wdev, bool aborted); |
| 17 | 17 | void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev, |
| 18 | 18 | struct sk_buff *msg); |
| 19 | −void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, | |
| 20 | − struct net_device *netdev, u32 cmd); | |
| 19 | +void nl80211_send_sched_scan(struct cfg80211_sched_scan_request *req, u32 cmd); | |
| 21 | 20 | void nl80211_common_reg_change_event(enum nl80211_commands cmd_id, |
| 22 | 21 | struct regulatory_request *request); |
| 23 | 22 | |
| @@ -53,11 +52,8 @@ void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, · 29 unmodified lines | ||
| 53 | 52 | struct net_device *netdev, |
| 54 | 53 | const u8 *addr, gfp_t gfp); |
| 55 | 54 | void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, |
| 56 | − struct net_device *netdev, const u8 *bssid, | |
| 57 | − const u8 *req_ie, size_t req_ie_len, | |
| 58 | − const u8 *resp_ie, size_t resp_ie_len, | |
| 59 | − int status, | |
| 60 | − enum nl80211_timeout_reason timeout_reason, | |
| 55 | + struct net_device *netdev, | |
| 56 | + struct cfg80211_connect_resp_params *params, | |
| 61 | 57 | gfp_t gfp); |
| 62 | 58 | void nl80211_send_roamed(struct cfg80211_registered_device *rdev, |
| 63 | 59 | struct net_device *netdev, const u8 *bssid, |
| @@ -36,13 +36,13 @@ static inline void rdev_set_wakeup(struct cfg80211_registered_device *rdev, · 35 unmodified lines | ||
| 36 | 36 | static inline struct wireless_dev |
| 37 | 37 | *rdev_add_virtual_intf(struct cfg80211_registered_device *rdev, char *name, |
| 38 | 38 | unsigned char name_assign_type, |
| 39 | − enum nl80211_iftype type, u32 *flags, | |
| 39 | + enum nl80211_iftype type, | |
| 40 | 40 | struct vif_params *params) |
| 41 | 41 | { |
| 42 | 42 | struct wireless_dev *ret; |
| 43 | 43 | trace_rdev_add_virtual_intf(&rdev->wiphy, name, type); |
| 44 | 44 | ret = rdev->ops->add_virtual_intf(&rdev->wiphy, name, name_assign_type, |
| 45 | − type, flags, params); | |
| 45 | + type, params); | |
| 46 | 46 | trace_rdev_return_wdev(&rdev->wiphy, ret); |
| 47 | 47 | return ret; |
| 48 | 48 | } |
| @@ -61,12 +61,11 @@ rdev_del_virtual_intf(struct cfg80211_registered_device *rdev, · 12 unmodified lines | ||
| 61 | 61 | static inline int |
| 62 | 62 | rdev_change_virtual_intf(struct cfg80211_registered_device *rdev, |
| 63 | 63 | struct net_device *dev, enum nl80211_iftype type, |
| 64 | − u32 *flags, struct vif_params *params) | |
| 64 | + struct vif_params *params) | |
| 65 | 65 | { |
| 66 | 66 | int ret; |
| 67 | 67 | trace_rdev_change_virtual_intf(&rdev->wiphy, dev, type); |
| 68 | − ret = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, type, flags, | |
| 69 | − params); | |
| 68 | + ret = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, type, params); | |
| 70 | 69 | trace_rdev_return_int(&rdev->wiphy, ret); |
| 71 | 70 | return ret; |
| 72 | 71 | } |
| @@ -749,6 +748,18 @@ rdev_set_cqm_rssi_config(struct cfg80211_registered_device *rdev, · 676 unmodified lines | ||
| 749 | 748 | return ret; |
| 750 | 749 | } |
| 751 | 750 | |
| 751 | +static inline int | |
| 752 | +rdev_set_cqm_rssi_range_config(struct cfg80211_registered_device *rdev, | |
| 753 | + struct net_device *dev, s32 low, s32 high) | |
| 754 | +{ | |
| 755 | + int ret; | |
| 756 | + trace_rdev_set_cqm_rssi_range_config(&rdev->wiphy, dev, low, high); | |
| 757 | + ret = rdev->ops->set_cqm_rssi_range_config(&rdev->wiphy, dev, | |
| 758 | + low, high); | |
| 759 | + trace_rdev_return_int(&rdev->wiphy, ret); | |
| 760 | + return ret; | |
| 761 | +} | |
| 762 | + | |
| 752 | 763 | static inline int |
| 753 | 764 | rdev_set_cqm_txe_config(struct cfg80211_registered_device *rdev, |
| 754 | 765 | struct net_device *dev, u32 rate, u32 pkts, u32 intvl) |
| @@ -2067,6 +2067,88 @@ reg_process_hint_country_ie(struct wiphy *wiphy, · 2066 unmodified lines | ||
| 2067 | 2067 | return REG_REQ_IGNORE; |
| 2068 | 2068 | } |
| 2069 | 2069 | |
| 2070 | +bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2) | |
| 2071 | +{ | |
| 2072 | + const struct ieee80211_regdomain *wiphy1_regd = NULL; | |
| 2073 | + const struct ieee80211_regdomain *wiphy2_regd = NULL; | |
| 2074 | + const struct ieee80211_regdomain *cfg80211_regd = NULL; | |
| 2075 | + bool dfs_domain_same; | |
| 2076 | + | |
| 2077 | + rcu_read_lock(); | |
| 2078 | + | |
| 2079 | + cfg80211_regd = rcu_dereference(cfg80211_regdomain); | |
| 2080 | + wiphy1_regd = rcu_dereference(wiphy1->regd); | |
| 2081 | + if (!wiphy1_regd) | |
| 2082 | + wiphy1_regd = cfg80211_regd; | |
| 2083 | + | |
| 2084 | + wiphy2_regd = rcu_dereference(wiphy2->regd); | |
| 2085 | + if (!wiphy2_regd) | |
| 2086 | + wiphy2_regd = cfg80211_regd; | |
| 2087 | + | |
| 2088 | + dfs_domain_same = wiphy1_regd->dfs_region == wiphy2_regd->dfs_region; | |
| 2089 | + | |
| 2090 | + rcu_read_unlock(); | |
| 2091 | + | |
| 2092 | + return dfs_domain_same; | |
| 2093 | +} | |
| 2094 | + | |
| 2095 | +static void reg_copy_dfs_chan_state(struct ieee80211_channel *dst_chan, | |
| 2096 | + struct ieee80211_channel *src_chan) | |
| 2097 | +{ | |
| 2098 | + if (!(dst_chan->flags & IEEE80211_CHAN_RADAR) || | |
| 2099 | + !(src_chan->flags & IEEE80211_CHAN_RADAR)) | |
| 2100 | + return; | |
| 2101 | + | |
| 2102 | + if (dst_chan->flags & IEEE80211_CHAN_DISABLED || | |
| 2103 | + src_chan->flags & IEEE80211_CHAN_DISABLED) | |
| 2104 | + return; | |
| 2105 | + | |
| 2106 | + if (src_chan->center_freq == dst_chan->center_freq && | |
| 2107 | + dst_chan->dfs_state == NL80211_DFS_USABLE) { | |
| 2108 | + dst_chan->dfs_state = src_chan->dfs_state; | |
| 2109 | + dst_chan->dfs_state_entered = src_chan->dfs_state_entered; | |
| 2110 | + } | |
| 2111 | +} | |
| 2112 | + | |
| 2113 | +static void wiphy_share_dfs_chan_state(struct wiphy *dst_wiphy, | |
| 2114 | + struct wiphy *src_wiphy) | |
| 2115 | +{ | |
| 2116 | + struct ieee80211_supported_band *src_sband, *dst_sband; | |
| 2117 | + struct ieee80211_channel *src_chan, *dst_chan; | |
| 2118 | + int i, j, band; | |
| 2119 | + | |
| 2120 | + if (!reg_dfs_domain_same(dst_wiphy, src_wiphy)) | |
| 2121 | + return; | |
| 2122 | + | |
| 2123 | + for (band = 0; band < NUM_NL80211_BANDS; band++) { | |
| 2124 | + dst_sband = dst_wiphy->bands[band]; | |
| 2125 | + src_sband = src_wiphy->bands[band]; | |
| 2126 | + if (!dst_sband || !src_sband) | |
| 2127 | + continue; | |
| 2128 | + | |
| 2129 | + for (i = 0; i < dst_sband->n_channels; i++) { | |
| 2130 | + dst_chan = &dst_sband->channels[i]; | |
| 2131 | + for (j = 0; j < src_sband->n_channels; j++) { | |
| 2132 | + src_chan = &src_sband->channels[j]; | |
| 2133 | + reg_copy_dfs_chan_state(dst_chan, src_chan); | |
| 2134 | + } | |
| 2135 | + } | |
| 2136 | + } | |
| 2137 | +} | |
| 2138 | + | |
| 2139 | +static void wiphy_all_share_dfs_chan_state(struct wiphy *wiphy) | |
| 2140 | +{ | |
| 2141 | + struct cfg80211_registered_device *rdev; | |
| 2142 | + | |
| 2143 | + ASSERT_RTNL(); | |
| 2144 | + | |
| 2145 | + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | |
| 2146 | + if (wiphy == &rdev->wiphy) | |
| 2147 | + continue; | |
| 2148 | + wiphy_share_dfs_chan_state(wiphy, &rdev->wiphy); | |
| 2149 | + } | |
| 2150 | +} | |
| 2151 | + | |
| 2070 | 2152 | /* This processes *all* regulatory hints */ |
| 2071 | 2153 | static void reg_process_hint(struct regulatory_request *reg_request) |
| 2072 | 2154 | { |
| @@ -2110,6 +2192,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) · 37 unmodified lines | ||
| 2110 | 2192 | if (treatment == REG_REQ_ALREADY_SET && wiphy && |
| 2111 | 2193 | wiphy->regulatory_flags & REGULATORY_STRICT_REG) { |
| 2112 | 2194 | wiphy_update_regulatory(wiphy, reg_request->initiator); |
| 2195 | + wiphy_all_share_dfs_chan_state(wiphy); | |
| 2113 | 2196 | reg_check_channels(); |
| 2114 | 2197 | } |
| 2115 | 2198 | |
| @@ -3061,6 +3144,7 @@ void wiphy_regulatory_register(struct wiphy *wiphy) · 945 unmodified lines | ||
| 3061 | 3144 | |
| 3062 | 3145 | lr = get_last_request(); |
| 3063 | 3146 | wiphy_update_regulatory(wiphy, lr->initiator); |
| 3147 | + wiphy_all_share_dfs_chan_state(wiphy); | |
| 3064 | 3148 | } |
| 3065 | 3149 | |
| 3066 | 3150 | void wiphy_regulatory_deregister(struct wiphy *wiphy) |
| @@ -3120,6 +3204,70 @@ bool regulatory_indoor_allowed(void) · 53 unmodified lines | ||
| 3120 | 3204 | return reg_is_indoor; |
| 3121 | 3205 | } |
| 3122 | 3206 | |
| 3207 | +bool regulatory_pre_cac_allowed(struct wiphy *wiphy) | |
| 3208 | +{ | |
| 3209 | + const struct ieee80211_regdomain *regd = NULL; | |
| 3210 | + const struct ieee80211_regdomain *wiphy_regd = NULL; | |
| 3211 | + bool pre_cac_allowed = false; | |
| 3212 | + | |
| 3213 | + rcu_read_lock(); | |
| 3214 | + | |
| 3215 | + regd = rcu_dereference(cfg80211_regdomain); | |
| 3216 | + wiphy_regd = rcu_dereference(wiphy->regd); | |
| 3217 | + if (!wiphy_regd) { | |
| 3218 | + if (regd->dfs_region == NL80211_DFS_ETSI) | |
| 3219 | + pre_cac_allowed = true; | |
| 3220 | + | |
| 3221 | + rcu_read_unlock(); | |
| 3222 | + | |
| 3223 | + return pre_cac_allowed; | |
| 3224 | + } | |
| 3225 | + | |
| 3226 | + if (regd->dfs_region == wiphy_regd->dfs_region && | |
| 3227 | + wiphy_regd->dfs_region == NL80211_DFS_ETSI) | |
| 3228 | + pre_cac_allowed = true; | |
| 3229 | + | |
| 3230 | + rcu_read_unlock(); | |
| 3231 | + | |
| 3232 | + return pre_cac_allowed; | |
| 3233 | +} | |
| 3234 | + | |
| 3235 | +void regulatory_propagate_dfs_state(struct wiphy *wiphy, | |
| 3236 | + struct cfg80211_chan_def *chandef, | |
| 3237 | + enum nl80211_dfs_state dfs_state, | |
| 3238 | + enum nl80211_radar_event event) | |
| 3239 | +{ | |
| 3240 | + struct cfg80211_registered_device *rdev; | |
| 3241 | + | |
| 3242 | + ASSERT_RTNL(); | |
| 3243 | + | |
| 3244 | + if (WARN_ON(!cfg80211_chandef_valid(chandef))) | |
| 3245 | + return; | |
| 3246 | + | |
| 3247 | + if (WARN_ON(!(chandef->chan->flags & IEEE80211_CHAN_RADAR))) | |
| 3248 | + return; | |
| 3249 | + | |
| 3250 | + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | |
| 3251 | + if (wiphy == &rdev->wiphy) | |
| 3252 | + continue; | |
| 3253 | + | |
| 3254 | + if (!reg_dfs_domain_same(wiphy, &rdev->wiphy)) | |
| 3255 | + continue; | |
| 3256 | + | |
| 3257 | + if (!ieee80211_get_channel(&rdev->wiphy, | |
| 3258 | + chandef->chan->center_freq)) | |
| 3259 | + continue; | |
| 3260 | + | |
| 3261 | + cfg80211_set_dfs_state(&rdev->wiphy, chandef, dfs_state); | |
| 3262 | + | |
| 3263 | + if (event == NL80211_RADAR_DETECTED || | |
| 3264 | + event == NL80211_RADAR_CAC_FINISHED) | |
| 3265 | + cfg80211_sched_dfs_chan_update(rdev); | |
| 3266 | + | |
| 3267 | + nl80211_radar_notify(rdev, chandef, event, NULL, GFP_KERNEL); | |
| 3268 | + } | |
| 3269 | +} | |
| 3270 | + | |
| 3123 | 3271 | int __init regulatory_init(void) |
| 3124 | 3272 | { |
| 3125 | 3273 | int err = 0; |
| @@ -143,4 +143,40 @@ int cfg80211_get_unii(int freq); · 142 unmodified lines | ||
| 143 | 143 | */ |
| 144 | 144 | bool regulatory_indoor_allowed(void); |
| 145 | 145 | |
| 146 | +/* | |
| 147 | + * Grace period to timeout pre-CAC results on the dfs channels. This timeout | |
| 148 | + * value is used for Non-ETSI domain. | |
| 149 | + * TODO: May be make this timeout available through regdb? | |
| 150 | + */ | |
| 151 | +#define REG_PRE_CAC_EXPIRY_GRACE_MS 2000 | |
| 152 | + | |
| 153 | +/** | |
| 154 | + * regulatory_pre_cac_allowed - if pre-CAC allowed in the current dfs domain | |
| 155 | + * @wiphy: wiphy for which pre-CAC capability is checked. | |
| 156 | + | |
| 157 | + * Pre-CAC is allowed only in ETSI domain. | |
| 158 | + */ | |
| 159 | +bool regulatory_pre_cac_allowed(struct wiphy *wiphy); | |
| 160 | + | |
| 161 | +/** | |
| 162 | + * regulatory_propagate_dfs_state - Propagate DFS channel state to other wiphys | |
| 163 | + * @wiphy - wiphy on which radar is detected and the event will be propagated | |
| 164 | + * to other available wiphys having the same DFS domain | |
| 165 | + * @chandef - Channel definition of radar detected channel | |
| 166 | + * @dfs_state - DFS channel state to be set | |
| 167 | + * @event - Type of radar event which triggered this DFS state change | |
| 168 | + * | |
| 169 | + * This function should be called with rtnl lock held. | |
| 170 | + */ | |
| 171 | +void regulatory_propagate_dfs_state(struct wiphy *wiphy, | |
| 172 | + struct cfg80211_chan_def *chandef, | |
| 173 | + enum nl80211_dfs_state dfs_state, | |
| 174 | + enum nl80211_radar_event event); | |
| 175 | + | |
| 176 | +/** | |
| 177 | + * reg_dfs_domain_same - Checks if both wiphy have same DFS domain configured | |
| 178 | + * @wiphy1 - wiphy it's dfs_region to be checked against that of wiphy2 | |
| 179 | + * @wiphy2 - wiphy it's dfs_region to be checked against that of wiphy1 | |
| 180 | + */ | |
| 181 | +bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2); | |
| 146 | 182 | #endif /* __NET_WIRELESS_REG_H */ |
| @@ -321,8 +321,7 @@ void __cfg80211_sched_scan_results(struct work_struct *wk) · 320 unmodified lines | ||
| 321 | 321 | spin_unlock_bh(&rdev->bss_lock); |
| 322 | 322 | request->scan_start = jiffies; |
| 323 | 323 | } |
| 324 | − nl80211_send_sched_scan(rdev, request->dev, | |
| 325 | − NL80211_CMD_SCHED_SCAN_RESULTS); | |
| 324 | + nl80211_send_sched_scan(request, NL80211_CMD_SCHED_SCAN_RESULTS); | |
| 326 | 325 | } |
| 327 | 326 | |
| 328 | 327 | rtnl_unlock(); |
| @@ -379,7 +378,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, · 50 unmodified lines | ||
| 379 | 378 | return err; |
| 380 | 379 | } |
| 381 | 380 | |
| 382 | − nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED); | |
| 381 | + nl80211_send_sched_scan(sched_scan_req, NL80211_CMD_SCHED_SCAN_STOPPED); | |
| 383 | 382 | |
| 384 | 383 | RCU_INIT_POINTER(rdev->sched_scan_req, NULL); |
| 385 | 384 | kfree_rcu(sched_scan_req, rcu_head); |
| @@ -253,10 +253,13 @@ void cfg80211_conn_work(struct work_struct *work) · 252 unmodified lines | ||
| 253 | 253 | } |
| 254 | 254 | treason = NL80211_TIMEOUT_UNSPECIFIED; |
| 255 | 255 | if (cfg80211_conn_do_work(wdev, &treason)) { |
| 256 | − __cfg80211_connect_result( | |
| 257 | − wdev->netdev, bssid, | |
| 258 | − NULL, 0, NULL, 0, -1, false, NULL, | |
| 259 | − treason); | |
| 256 | + struct cfg80211_connect_resp_params cr; | |
| 257 | + | |
| 258 | + memset(&cr, 0, sizeof(cr)); | |
| 259 | + cr.status = -1; | |
| 260 | + cr.bssid = bssid; | |
| 261 | + cr.timeout_reason = treason; | |
| 262 | + __cfg80211_connect_result(wdev->netdev, &cr, false); | |
| 260 | 263 | } |
| 261 | 264 | wdev_unlock(wdev); |
| 262 | 265 | } |
| @@ -359,10 +362,13 @@ void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len) · 96 unmodified lines | ||
| 359 | 362 | wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; |
| 360 | 363 | schedule_work(&rdev->conn_work); |
| 361 | 364 | } else if (status_code != WLAN_STATUS_SUCCESS) { |
| 362 | − __cfg80211_connect_result(wdev->netdev, mgmt->bssid, | |
| 363 | − NULL, 0, NULL, 0, | |
| 364 | − status_code, false, NULL, | |
| 365 | − NL80211_TIMEOUT_UNSPECIFIED); | |
| 365 | + struct cfg80211_connect_resp_params cr; | |
| 366 | + | |
| 367 | + memset(&cr, 0, sizeof(cr)); | |
| 368 | + cr.status = status_code; | |
| 369 | + cr.bssid = mgmt->bssid; | |
| 370 | + cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED; | |
| 371 | + __cfg80211_connect_result(wdev->netdev, &cr, false); | |
| 366 | 372 | } else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { |
| 367 | 373 | wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; |
| 368 | 374 | schedule_work(&rdev->conn_work); |
| @@ -669,12 +675,9 @@ static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); · 300 unmodified lines | ||
| 669 | 675 | */ |
| 670 | 676 | |
| 671 | 677 | /* This method must consume bss one way or another */ |
| 672 | −void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |
| 673 | − const u8 *req_ie, size_t req_ie_len, | |
| 674 | − const u8 *resp_ie, size_t resp_ie_len, | |
| 675 | − int status, bool wextev, | |
| 676 | − struct cfg80211_bss *bss, | |
| 677 | − enum nl80211_timeout_reason timeout_reason) | |
| 678 | +void __cfg80211_connect_result(struct net_device *dev, | |
| 679 | + struct cfg80211_connect_resp_params *cr, | |
| 680 | + bool wextev) | |
| 678 | 681 | { |
| 679 | 682 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 680 | 683 | const u8 *country_ie; |
| @@ -686,48 +689,48 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, · 5 unmodified lines | ||
| 686 | 689 | |
| 687 | 690 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && |
| 688 | 691 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) { |
| 689 | − cfg80211_put_bss(wdev->wiphy, bss); | |
| 692 | + cfg80211_put_bss(wdev->wiphy, cr->bss); | |
| 690 | 693 | return; |
| 691 | 694 | } |
| 692 | 695 | |
| 693 | − nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, | |
| 694 | − bssid, req_ie, req_ie_len, | |
| 695 | − resp_ie, resp_ie_len, | |
| 696 | − status, timeout_reason, GFP_KERNEL); | |
| 696 | + nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, cr, | |
| 697 | + GFP_KERNEL); | |
| 697 | 698 | |
| 698 | 699 | #ifdef CONFIG_CFG80211_WEXT |
| 699 | 700 | if (wextev) { |
| 700 | − if (req_ie && status == WLAN_STATUS_SUCCESS) { | |
| 701 | + if (cr->req_ie && cr->status == WLAN_STATUS_SUCCESS) { | |
| 701 | 702 | memset(&wrqu, 0, sizeof(wrqu)); |
| 702 | − wrqu.data.length = req_ie_len; | |
| 703 | − wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, req_ie); | |
| 703 | + wrqu.data.length = cr->req_ie_len; | |
| 704 | + wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, | |
| 705 | + cr->req_ie); | |
| 704 | 706 | } |
| 705 | 707 | |
| 706 | − if (resp_ie && status == WLAN_STATUS_SUCCESS) { | |
| 708 | + if (cr->resp_ie && cr->status == WLAN_STATUS_SUCCESS) { | |
| 707 | 709 | memset(&wrqu, 0, sizeof(wrqu)); |
| 708 | − wrqu.data.length = resp_ie_len; | |
| 709 | − wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie); | |
| 710 | + wrqu.data.length = cr->resp_ie_len; | |
| 711 | + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, | |
| 712 | + cr->resp_ie); | |
| 710 | 713 | } |
| 711 | 714 | |
| 712 | 715 | memset(&wrqu, 0, sizeof(wrqu)); |
| 713 | 716 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
| 714 | − if (bssid && status == WLAN_STATUS_SUCCESS) { | |
| 715 | − memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | |
| 716 | − memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN); | |
| 717 | + if (cr->bssid && cr->status == WLAN_STATUS_SUCCESS) { | |
| 718 | + memcpy(wrqu.ap_addr.sa_data, cr->bssid, ETH_ALEN); | |
| 719 | + memcpy(wdev->wext.prev_bssid, cr->bssid, ETH_ALEN); | |
| 717 | 720 | wdev->wext.prev_bssid_valid = true; |
| 718 | 721 | } |
| 719 | 722 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); |
| 720 | 723 | } |
| 721 | 724 | #endif |
| 722 | 725 | |
| 723 | − if (!bss && (status == WLAN_STATUS_SUCCESS)) { | |
| 726 | + if (!cr->bss && (cr->status == WLAN_STATUS_SUCCESS)) { | |
| 724 | 727 | WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect); |
| 725 | − bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | |
| 726 | − wdev->ssid, wdev->ssid_len, | |
| 727 | − wdev->conn_bss_type, | |
| 728 | − IEEE80211_PRIVACY_ANY); | |
| 729 | − if (bss) | |
| 730 | − cfg80211_hold_bss(bss_from_pub(bss)); | |
| 728 | + cr->bss = cfg80211_get_bss(wdev->wiphy, NULL, cr->bssid, | |
| 729 | + wdev->ssid, wdev->ssid_len, | |
| 730 | + wdev->conn_bss_type, | |
| 731 | + IEEE80211_PRIVACY_ANY); | |
| 732 | + if (cr->bss) | |
| 733 | + cfg80211_hold_bss(bss_from_pub(cr->bss)); | |
| 731 | 734 | } |
| 732 | 735 | |
| 733 | 736 | if (wdev->current_bss) { |
| @@ -736,29 +739,29 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, · 2 unmodified lines | ||
| 736 | 739 | wdev->current_bss = NULL; |
| 737 | 740 | } |
| 738 | 741 | |
| 739 | − if (status != WLAN_STATUS_SUCCESS) { | |
| 742 | + if (cr->status != WLAN_STATUS_SUCCESS) { | |
| 740 | 743 | kzfree(wdev->connect_keys); |
| 741 | 744 | wdev->connect_keys = NULL; |
| 742 | 745 | wdev->ssid_len = 0; |
| 743 | 746 | wdev->conn_owner_nlportid = 0; |
| 744 | − if (bss) { | |
| 745 | − cfg80211_unhold_bss(bss_from_pub(bss)); | |
| 746 | − cfg80211_put_bss(wdev->wiphy, bss); | |
| 747 | + if (cr->bss) { | |
| 748 | + cfg80211_unhold_bss(bss_from_pub(cr->bss)); | |
| 749 | + cfg80211_put_bss(wdev->wiphy, cr->bss); | |
| 747 | 750 | } |
| 748 | 751 | cfg80211_sme_free(wdev); |
| 749 | 752 | return; |
| 750 | 753 | } |
| 751 | 754 | |
| 752 | − if (WARN_ON(!bss)) | |
| 755 | + if (WARN_ON(!cr->bss)) | |
| 753 | 756 | return; |
| 754 | 757 | |
| 755 | − wdev->current_bss = bss_from_pub(bss); | |
| 758 | + wdev->current_bss = bss_from_pub(cr->bss); | |
| 756 | 759 | |
| 757 | 760 | if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP)) |
| 758 | 761 | cfg80211_upload_connect_keys(wdev); |
| 759 | 762 | |
| 760 | 763 | rcu_read_lock(); |
| 761 | − country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); | |
| 764 | + country_ie = ieee80211_bss_get_ie(cr->bss, WLAN_EID_COUNTRY); | |
| 762 | 765 | if (!country_ie) { |
| 763 | 766 | rcu_read_unlock(); |
| 764 | 767 | return; |
| @@ -775,64 +778,95 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, · 10 unmodified lines | ||
| 775 | 778 | * - country_ie + 2, the start of the country ie data, and |
| 776 | 779 | * - and country_ie[1] which is the IE length |
| 777 | 780 | */ |
| 778 | − regulatory_hint_country_ie(wdev->wiphy, bss->channel->band, | |
| 781 | + regulatory_hint_country_ie(wdev->wiphy, cr->bss->channel->band, | |
| 779 | 782 | country_ie + 2, country_ie[1]); |
| 780 | 783 | kfree(country_ie); |
| 781 | 784 | } |
| 782 | 785 | |
| 783 | 786 | /* Consumes bss object one way or another */ |
| 784 | −void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, | |
| 785 | − struct cfg80211_bss *bss, const u8 *req_ie, | |
| 786 | − size_t req_ie_len, const u8 *resp_ie, | |
| 787 | − size_t resp_ie_len, int status, gfp_t gfp, | |
| 788 | − enum nl80211_timeout_reason timeout_reason) | |
| 787 | +void cfg80211_connect_done(struct net_device *dev, | |
| 788 | + struct cfg80211_connect_resp_params *params, | |
| 789 | + gfp_t gfp) | |
| 789 | 790 | { |
| 790 | 791 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 791 | 792 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); |
| 792 | 793 | struct cfg80211_event *ev; |
| 793 | 794 | unsigned long flags; |
| 795 | + u8 *next; | |
| 794 | 796 | |
| 795 | − if (bss) { | |
| 797 | + if (params->bss) { | |
| 796 | 798 | /* Make sure the bss entry provided by the driver is valid. */ |
| 797 | − struct cfg80211_internal_bss *ibss = bss_from_pub(bss); | |
| 799 | + struct cfg80211_internal_bss *ibss = bss_from_pub(params->bss); | |
| 798 | 800 | |
| 799 | 801 | if (WARN_ON(list_empty(&ibss->list))) { |
| 800 | − cfg80211_put_bss(wdev->wiphy, bss); | |
| 802 | + cfg80211_put_bss(wdev->wiphy, params->bss); | |
| 801 | 803 | return; |
| 802 | 804 | } |
| 803 | 805 | } |
| 804 | 806 | |
| 805 | − ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); | |
| 807 | + ev = kzalloc(sizeof(*ev) + (params->bssid ? ETH_ALEN : 0) + | |
| 808 | + params->req_ie_len + params->resp_ie_len + | |
| 809 | + params->fils_kek_len + params->pmk_len + | |
| 810 | + (params->pmkid ? WLAN_PMKID_LEN : 0), gfp); | |
| 806 | 811 | if (!ev) { |
| 807 | − cfg80211_put_bss(wdev->wiphy, bss); | |
| 812 | + cfg80211_put_bss(wdev->wiphy, params->bss); | |
| 808 | 813 | return; |
| 809 | 814 | } |
| 810 | 815 | |
| 811 | 816 | ev->type = EVENT_CONNECT_RESULT; |
| 812 | − if (bssid) | |
| 813 | − memcpy(ev->cr.bssid, bssid, ETH_ALEN); | |
| 814 | − if (req_ie_len) { | |
| 815 | − ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev); | |
| 816 | − ev->cr.req_ie_len = req_ie_len; | |
| 817 | − memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len); | |
| 817 | + next = ((u8 *)ev) + sizeof(*ev); | |
| 818 | + if (params->bssid) { | |
| 819 | + ev->cr.bssid = next; | |
| 820 | + memcpy((void *)ev->cr.bssid, params->bssid, ETH_ALEN); | |
| 821 | + next += ETH_ALEN; | |
| 818 | 822 | } |
| 819 | − if (resp_ie_len) { | |
| 820 | − ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len; | |
| 821 | − ev->cr.resp_ie_len = resp_ie_len; | |
| 822 | − memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len); | |
| 823 | + if (params->req_ie_len) { | |
| 824 | + ev->cr.req_ie = next; | |
| 825 | + ev->cr.req_ie_len = params->req_ie_len; | |
| 826 | + memcpy((void *)ev->cr.req_ie, params->req_ie, | |
| 827 | + params->req_ie_len); | |
| 828 | + next += params->req_ie_len; | |
| 823 | 829 | } |
| 824 | − if (bss) | |
| 825 | − cfg80211_hold_bss(bss_from_pub(bss)); | |
| 826 | − ev->cr.bss = bss; | |
| 827 | − ev->cr.status = status; | |
| 828 | − ev->cr.timeout_reason = timeout_reason; | |
| 830 | + if (params->resp_ie_len) { | |
| 831 | + ev->cr.resp_ie = next; | |
| 832 | + ev->cr.resp_ie_len = params->resp_ie_len; | |
| 833 | + memcpy((void *)ev->cr.resp_ie, params->resp_ie, | |
| 834 | + params->resp_ie_len); | |
| 835 | + next += params->resp_ie_len; | |
| 836 | + } | |
| 837 | + if (params->fils_kek_len) { | |
| 838 | + ev->cr.fils_kek = next; | |
| 839 | + ev->cr.fils_kek_len = params->fils_kek_len; | |
| 840 | + memcpy((void *)ev->cr.fils_kek, params->fils_kek, | |
| 841 | + params->fils_kek_len); | |
| 842 | + next += params->fils_kek_len; | |
| 843 | + } | |
| 844 | + if (params->pmk_len) { | |
| 845 | + ev->cr.pmk = next; | |
| 846 | + ev->cr.pmk_len = params->pmk_len; | |
| 847 | + memcpy((void *)ev->cr.pmk, params->pmk, params->pmk_len); | |
| 848 | + next += params->pmk_len; | |
| 849 | + } | |
| 850 | + if (params->pmkid) { | |
| 851 | + ev->cr.pmkid = next; | |
| 852 | + memcpy((void *)ev->cr.pmkid, params->pmkid, WLAN_PMKID_LEN); | |
| 853 | + next += WLAN_PMKID_LEN; | |
| 854 | + } | |
| 855 | + ev->cr.update_erp_next_seq_num = params->update_erp_next_seq_num; | |
| 856 | + if (params->update_erp_next_seq_num) | |
| 857 | + ev->cr.fils_erp_next_seq_num = params->fils_erp_next_seq_num; | |
| 858 | + if (params->bss) | |
| 859 | + cfg80211_hold_bss(bss_from_pub(params->bss)); | |
| 860 | + ev->cr.bss = params->bss; | |
| 861 | + ev->cr.status = params->status; | |
| 862 | + ev->cr.timeout_reason = params->timeout_reason; | |
| 829 | 863 | |
| 830 | 864 | spin_lock_irqsave(&wdev->event_lock, flags); |
| 831 | 865 | list_add_tail(&ev->list, &wdev->event_list); |
| 832 | 866 | spin_unlock_irqrestore(&wdev->event_lock, flags); |
| 833 | 867 | queue_work(cfg80211_wq, &rdev->event_work); |
| 834 | 868 | } |
| 835 | −EXPORT_SYMBOL(cfg80211_connect_bss); | |
| 869 | +EXPORT_SYMBOL(cfg80211_connect_done); | |
| 836 | 870 | |
| 837 | 871 | /* Consumes bss object one way or another */ |
| 838 | 872 | void __cfg80211_roamed(struct wireless_dev *wdev, |
| @@ -1322,6 +1322,28 @@ TRACE_EVENT(rdev_set_cqm_rssi_config, · 1321 unmodified lines | ||
| 1322 | 1322 | __entry->rssi_thold, __entry->rssi_hyst) |
| 1323 | 1323 | ); |
| 1324 | 1324 | |
| 1325 | +TRACE_EVENT(rdev_set_cqm_rssi_range_config, | |
| 1326 | + TP_PROTO(struct wiphy *wiphy, | |
| 1327 | + struct net_device *netdev, s32 low, s32 high), | |
| 1328 | + TP_ARGS(wiphy, netdev, low, high), | |
| 1329 | + TP_STRUCT__entry( | |
| 1330 | + WIPHY_ENTRY | |
| 1331 | + NETDEV_ENTRY | |
| 1332 | + __field(s32, rssi_low) | |
| 1333 | + __field(s32, rssi_high) | |
| 1334 | + ), | |
| 1335 | + TP_fast_assign( | |
| 1336 | + WIPHY_ASSIGN; | |
| 1337 | + NETDEV_ASSIGN; | |
| 1338 | + __entry->rssi_low = low; | |
| 1339 | + __entry->rssi_high = high; | |
| 1340 | + ), | |
| 1341 | + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT | |
| 1342 | + ", range: %d - %d ", | |
| 1343 | + WIPHY_PR_ARG, NETDEV_PR_ARG, | |
| 1344 | + __entry->rssi_low, __entry->rssi_high) | |
| 1345 | +); | |
| 1346 | + | |
| 1325 | 1347 | TRACE_EVENT(rdev_set_cqm_txe_config, |
| 1326 | 1348 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 rate, |
| 1327 | 1349 | u32 pkts, u32 intvl), |
| @@ -659,7 +659,7 @@ __ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame, · 658 unmodified lines | ||
| 659 | 659 | int offset, int len) |
| 660 | 660 | { |
| 661 | 661 | struct skb_shared_info *sh = skb_shinfo(skb); |
| 662 | − const skb_frag_t *frag = &sh->frags[-1]; | |
| 662 | + const skb_frag_t *frag = &sh->frags[0]; | |
| 663 | 663 | struct page *frag_page; |
| 664 | 664 | void *frag_ptr; |
| 665 | 665 | int frag_len, frag_size; |
| @@ -672,10 +672,10 @@ __ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame, · 6 unmodified lines | ||
| 672 | 672 | |
| 673 | 673 | while (offset >= frag_size) { |
| 674 | 674 | offset -= frag_size; |
| 675 | − frag++; | |
| 676 | 675 | frag_page = skb_frag_page(frag); |
| 677 | 676 | frag_ptr = skb_frag_address(frag); |
| 678 | 677 | frag_size = skb_frag_size(frag); |
| 678 | + frag++; | |
| 679 | 679 | } |
| 680 | 680 | |
| 681 | 681 | frag_ptr += offset; |
| @@ -687,12 +687,12 @@ __ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame, · 5 unmodified lines | ||
| 687 | 687 | len -= cur_len; |
| 688 | 688 | |
| 689 | 689 | while (len > 0) { |
| 690 | − frag++; | |
| 691 | 690 | frag_len = skb_frag_size(frag); |
| 692 | 691 | cur_len = min(len, frag_len); |
| 693 | 692 | __frame_add_frag(frame, skb_frag_page(frag), |
| 694 | 693 | skb_frag_address(frag), cur_len, frag_len); |
| 695 | 694 | len -= cur_len; |
| 695 | + frag++; | |
| 696 | 696 | } |
| 697 | 697 | } |
| 698 | 698 | |
| @@ -914,11 +914,11 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev) · 215 unmodified lines | ||
| 914 | 914 | netdev_err(dev, "failed to set key %d\n", i); |
| 915 | 915 | continue; |
| 916 | 916 | } |
| 917 | − if (wdev->connect_keys->def == i) | |
| 918 | − if (rdev_set_default_key(rdev, dev, i, true, true)) { | |
| 919 | − netdev_err(dev, "failed to set defkey %d\n", i); | |
| 920 | − continue; | |
| 921 | − } | |
| 917 | + if (wdev->connect_keys->def == i && | |
| 918 | + rdev_set_default_key(rdev, dev, i, true, true)) { | |
| 919 | + netdev_err(dev, "failed to set defkey %d\n", i); | |
| 920 | + continue; | |
| 921 | + } | |
| 922 | 922 | } |
| 923 | 923 | |
| 924 | 924 | kzfree(wdev->connect_keys); |
| @@ -929,7 +929,6 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) · 4 unmodified lines | ||
| 929 | 929 | { |
| 930 | 930 | struct cfg80211_event *ev; |
| 931 | 931 | unsigned long flags; |
| 932 | − const u8 *bssid = NULL; | |
| 933 | 932 | |
| 934 | 933 | spin_lock_irqsave(&wdev->event_lock, flags); |
| 935 | 934 | while (!list_empty(&wdev->event_list)) { |
| @@ -941,15 +940,10 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev) · 5 unmodified lines | ||
| 941 | 940 | wdev_lock(wdev); |
| 942 | 941 | switch (ev->type) { |
| 943 | 942 | case EVENT_CONNECT_RESULT: |
| 944 | − if (!is_zero_ether_addr(ev->cr.bssid)) | |
| 945 | − bssid = ev->cr.bssid; | |
| 946 | 943 | __cfg80211_connect_result( |
| 947 | − wdev->netdev, bssid, | |
| 948 | − ev->cr.req_ie, ev->cr.req_ie_len, | |
| 949 | − ev->cr.resp_ie, ev->cr.resp_ie_len, | |
| 950 | − ev->cr.status, | |
| 951 | − ev->cr.status == WLAN_STATUS_SUCCESS, | |
| 952 | − ev->cr.bss, ev->cr.timeout_reason); | |
| 944 | + wdev->netdev, | |
| 945 | + &ev->cr, | |
| 946 | + ev->cr.status == WLAN_STATUS_SUCCESS); | |
| 953 | 947 | break; |
| 954 | 948 | case EVENT_ROAMED: |
| 955 | 949 | __cfg80211_roamed(wdev, ev->rm.bss, ev->rm.req_ie, |
| @@ -991,7 +985,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) · 35 unmodified lines | ||
| 991 | 985 | |
| 992 | 986 | int cfg80211_change_iface(struct cfg80211_registered_device *rdev, |
| 993 | 987 | struct net_device *dev, enum nl80211_iftype ntype, |
| 994 | − u32 *flags, struct vif_params *params) | |
| 988 | + struct vif_params *params) | |
| 995 | 989 | { |
| 996 | 990 | int err; |
| 997 | 991 | enum nl80211_iftype otype = dev->ieee80211_ptr->iftype; |
| @@ -1049,7 +1043,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, · 51 unmodified lines | ||
| 1049 | 1043 | cfg80211_process_rdev_events(rdev); |
| 1050 | 1044 | } |
| 1051 | 1045 | |
| 1052 | − err = rdev_change_virtual_intf(rdev, dev, ntype, flags, params); | |
| 1046 | + err = rdev_change_virtual_intf(rdev, dev, ntype, params); | |
| 1053 | 1047 | |
| 1054 | 1048 | WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype); |
| 1055 | 1049 | |
| @@ -1097,6 +1091,35 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, · 41 unmodified lines | ||
| 1097 | 1091 | return err; |
| 1098 | 1092 | } |
| 1099 | 1093 | |
| 1094 | +static u32 cfg80211_calculate_bitrate_ht(struct rate_info *rate) | |
| 1095 | +{ | |
| 1096 | + int modulation, streams, bitrate; | |
| 1097 | + | |
| 1098 | + /* the formula below does only work for MCS values smaller than 32 */ | |
| 1099 | + if (WARN_ON_ONCE(rate->mcs >= 32)) | |
| 1100 | + return 0; | |
| 1101 | + | |
| 1102 | + modulation = rate->mcs & 7; | |
| 1103 | + streams = (rate->mcs >> 3) + 1; | |
| 1104 | + | |
| 1105 | + bitrate = (rate->bw == RATE_INFO_BW_40) ? 13500000 : 6500000; | |
| 1106 | + | |
| 1107 | + if (modulation < 4) | |
| 1108 | + bitrate *= (modulation + 1); | |
| 1109 | + else if (modulation == 4) | |
| 1110 | + bitrate *= (modulation + 2); | |
| 1111 | + else | |
| 1112 | + bitrate *= (modulation + 3); | |
| 1113 | + | |
| 1114 | + bitrate *= streams; | |
| 1115 | + | |
| 1116 | + if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) | |
| 1117 | + bitrate = (bitrate / 9) * 10; | |
| 1118 | + | |
| 1119 | + /* do NOT round down here */ | |
| 1120 | + return (bitrate + 50000) / 100000; | |
| 1121 | +} | |
| 1122 | + | |
| 1100 | 1123 | static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate) |
| 1101 | 1124 | { |
| 1102 | 1125 | static const u32 __mcs2bitrate[] = { |
| @@ -1230,39 +1253,14 @@ static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate) · 127 unmodified lines | ||
| 1230 | 1253 | |
| 1231 | 1254 | u32 cfg80211_calculate_bitrate(struct rate_info *rate) |
| 1232 | 1255 | { |
| 1233 | − int modulation, streams, bitrate; | |
| 1234 | − | |
| 1235 | − if (!(rate->flags & RATE_INFO_FLAGS_MCS) && | |
| 1236 | − !(rate->flags & RATE_INFO_FLAGS_VHT_MCS)) | |
| 1237 | − return rate->legacy; | |
| 1256 | + if (rate->flags & RATE_INFO_FLAGS_MCS) | |
| 1257 | + return cfg80211_calculate_bitrate_ht(rate); | |
| 1238 | 1258 | if (rate->flags & RATE_INFO_FLAGS_60G) |
| 1239 | 1259 | return cfg80211_calculate_bitrate_60g(rate); |
| 1240 | 1260 | if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) |
| 1241 | 1261 | return cfg80211_calculate_bitrate_vht(rate); |
| 1242 | 1262 | |
| 1243 | − /* the formula below does only work for MCS values smaller than 32 */ | |
| 1244 | − if (WARN_ON_ONCE(rate->mcs >= 32)) | |
| 1245 | − return 0; | |
| 1246 | − | |
| 1247 | − modulation = rate->mcs & 7; | |
| 1248 | − streams = (rate->mcs >> 3) + 1; | |
| 1249 | − | |
| 1250 | − bitrate = (rate->bw == RATE_INFO_BW_40) ? 13500000 : 6500000; | |
| 1251 | − | |
| 1252 | − if (modulation < 4) | |
| 1253 | − bitrate *= (modulation + 1); | |
| 1254 | − else if (modulation == 4) | |
| 1255 | − bitrate *= (modulation + 2); | |
| 1256 | − else | |
| 1257 | − bitrate *= (modulation + 3); | |
| 1258 | − | |
| 1259 | − bitrate *= streams; | |
| 1260 | − | |
| 1261 | − if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) | |
| 1262 | − bitrate = (bitrate / 9) * 10; | |
| 1263 | − | |
| 1264 | − /* do NOT round down here */ | |
| 1265 | − return (bitrate + 50000) / 100000; | |
| 1263 | + return rate->legacy; | |
| 1266 | 1264 | } |
| 1267 | 1265 | EXPORT_SYMBOL(cfg80211_calculate_bitrate); |
| 1268 | 1266 | |
| @@ -62,7 +62,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, · 61 unmodified lines | ||
| 62 | 62 | |
| 63 | 63 | memset(&vifparams, 0, sizeof(vifparams)); |
| 64 | 64 | |
| 65 | − return cfg80211_change_iface(rdev, dev, type, NULL, &vifparams); | |
| 65 | + return cfg80211_change_iface(rdev, dev, type, &vifparams); | |
| 66 | 66 | } |
| 67 | 67 | EXPORT_WEXT_HANDLER(cfg80211_wext_siwmode); |
| 68 | 68 | |