mirror of https://gitee.com/openkylin/linux.git
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 -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEExu3sM/nZ1eRSfR9Ha3t4Rpy0AB0FAlj12HMACgkQa3t4Rpy0 AB0ztBAAi0tH9xR/7iYgChyZV4S8PpYKo2QoQZofG8vzAztboqI4clAxbWEOsJHh qddjm+foiHVJtZj2LqxjDcaxk69VIh/ERSlR7ve7GCzz9WAAWBMHZop2eArHvgI1 pqP4mQEZ7QISVo88H3LeRdj8NmTwfZYH8u8e2CN3yEpSh1PPrU+slaXRLrjB4uql XWwwJYQatgDw6Dj4vTIk++DqGo7OhK6CrC1gZLnyOtitTiPzRtfj8rdRHeRKdlj4 wOkUaenjs5r9KsofNYZpzckHp2NEpgIruqCsNdRGHf14EWBC5Q1N35OUOecyQ67T 3VeSnHxU4qjomkXgwqmDKFFOdqtqIruor3YDdO1iwO2TNF+JlNfq5AqUNec/XjUv VDmj1NRZE0ftJtCkDFm1Q/ABfVDH9i2O6ZBs6a3zb65lA83q1y4xlF48LqDzG3qi fNnfRO2rOOiyosF3HEkF5u1mfD6MRUtZAc2ZiHckGUpAngs5QOWKqtVgcgWjmbFW qDTKsFYi2YpGXZAnUjqS4ZtmcgRGEXqg1STJBt4cA8cnmI9Ka5GplACVhqzGeneH EYMESEct9BOpR6BjABmbZL09NtCkiTPYjiL4V//USr4f6NFhOeHHMYuxYFYIEgC6 ldRjf4EUzZw0QJ8X6L+zxYI5m40fEJ7bGhlIdMo7fWXpRpCaF1Y= =f4VT -----END PGP SIGNATURE----- Merge tag 'mac80211-next-for-davem-2017-04-18' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next 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 ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
028f43bc64
|
@ -2,6 +2,9 @@
|
|||
cfg80211 subsystem
|
||||
==================
|
||||
|
||||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:doc: Introduction
|
||||
|
||||
Device registration
|
||||
===================
|
||||
|
||||
|
@ -179,6 +182,12 @@ Actions and configuration
|
|||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:functions: cfg80211_ibss_joined
|
||||
|
||||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:functions: cfg80211_connect_resp_params
|
||||
|
||||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:functions: cfg80211_connect_done
|
||||
|
||||
.. kernel-doc:: include/net/cfg80211.h
|
||||
:functions: cfg80211_connect_result
|
||||
|
||||
|
|
|
@ -1917,6 +1917,8 @@ static int adm8211_probe(struct pci_dev *pdev,
|
|||
|
||||
dev->wiphy->bands[NL80211_BAND_2GHZ] = &priv->band;
|
||||
|
||||
wiphy_ext_feature_set(dev->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
err = ieee80211_register_hw(dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s (adm8211): Cannot register device\n",
|
||||
|
|
|
@ -1689,6 +1689,8 @@ static int ar5523_probe(struct usb_interface *intf,
|
|||
if (error)
|
||||
goto out_cancel_rx_cmd;
|
||||
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
usb_set_intfdata(intf, hw);
|
||||
|
||||
error = ieee80211_register_hw(hw);
|
||||
|
|
|
@ -8267,6 +8267,8 @@ int ath10k_mac_register(struct ath10k *ar)
|
|||
ar->hw->wiphy->cipher_suites = cipher_suites;
|
||||
ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
|
||||
|
||||
wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
ret = ieee80211_register_hw(ar->hw);
|
||||
if (ret) {
|
||||
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)
|
|||
|
||||
hw->extra_tx_headroom = 2;
|
||||
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
/*
|
||||
* Mark the device as detached to avoid processing
|
||||
* interrupts until setup is complete.
|
||||
|
|
|
@ -1503,7 +1503,6 @@ static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
|
|||
const char *name,
|
||||
unsigned char name_assign_type,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct ath6kl *ar = wiphy_priv(wiphy);
|
||||
|
@ -1550,7 +1549,7 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
|
|||
|
||||
static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct ath6kl_vif *vif = netdev_priv(ndev);
|
||||
|
|
|
@ -780,6 +780,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
|
|||
}
|
||||
|
||||
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
|
||||
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
}
|
||||
|
||||
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)
|
|||
ath9k_cmn_reload_chainmask(ah);
|
||||
|
||||
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
|
||||
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
}
|
||||
|
||||
int ath9k_init_device(u16 devid, struct ath_softc *sc,
|
||||
|
|
|
@ -1874,6 +1874,8 @@ void *carl9170_alloc(size_t priv_size)
|
|||
for (i = 0; i < ARRAY_SIZE(ar->noise); i++)
|
||||
ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */
|
||||
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
return ar;
|
||||
|
||||
err_nomem:
|
||||
|
|
|
@ -1112,6 +1112,9 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
|
|||
wcn->hw->sta_data_size = sizeof(struct wcn36xx_sta);
|
||||
wcn->hw->vif_data_size = sizeof(struct wcn36xx_vif);
|
||||
|
||||
wiphy_ext_feature_set(wcn->hw->wiphy,
|
||||
NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -178,9 +178,8 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
|
|||
BIT(NL80211_STA_INFO_RX_DROP_MISC) |
|
||||
BIT(NL80211_STA_INFO_TX_FAILED);
|
||||
|
||||
sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
|
||||
sinfo->txrate.flags = RATE_INFO_FLAGS_60G;
|
||||
sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
|
||||
sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
|
||||
sinfo->rxrate.mcs = stats->last_mcs_rx;
|
||||
sinfo->rx_bytes = stats->rx_bytes;
|
||||
sinfo->rx_packets = stats->rx_packets;
|
||||
|
@ -256,7 +255,7 @@ static struct wireless_dev *
|
|||
wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name,
|
||||
unsigned char name_assign_type,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags, struct vif_params *params)
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
|
@ -307,7 +306,7 @@ static int wil_cfg80211_del_iface(struct wiphy *wiphy,
|
|||
|
||||
static int wil_cfg80211_change_iface(struct wiphy *wiphy,
|
||||
struct net_device *ndev,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
@ -334,11 +333,8 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
|
|||
case NL80211_IFTYPE_P2P_GO:
|
||||
break;
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
if (flags)
|
||||
wil->monitor_flags = *flags;
|
||||
else
|
||||
wil->monitor_flags = 0;
|
||||
|
||||
if (params->flags)
|
||||
wil->monitor_flags = params->flags;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
|
|
@ -2377,6 +2377,8 @@ static int at76_init_new_device(struct at76_priv *priv,
|
|||
|
||||
wiphy->hw_version = priv->board_type;
|
||||
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
ret = ieee80211_register_hw(priv->hw);
|
||||
if (ret) {
|
||||
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)
|
|||
|
||||
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
|
||||
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
wl->hw_registred = false;
|
||||
hw->max_rates = 2;
|
||||
SET_IEEE80211_DEV(hw, dev->dev);
|
||||
|
|
|
@ -3850,6 +3850,8 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
|
|||
else
|
||||
SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac);
|
||||
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
/* Get and initialize struct b43legacy_wl */
|
||||
wl = hw_to_b43legacy_wl(hw);
|
||||
memset(wl, 0, sizeof(*wl));
|
||||
|
|
|
@ -575,12 +575,11 @@ static int brcmf_cfg80211_request_ap_if(struct brcmf_if *ifp)
|
|||
*
|
||||
* @wiphy: wiphy device of new interface.
|
||||
* @name: name of the new interface.
|
||||
* @flags: not used.
|
||||
* @params: contains mac address for AP device.
|
||||
*/
|
||||
static
|
||||
struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
|
||||
u32 *flags, struct vif_params *params)
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
|
||||
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,
|
|||
const char *name,
|
||||
unsigned char name_assign_type,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct wireless_dev *wdev;
|
||||
|
@ -674,12 +672,12 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
|
|||
case NL80211_IFTYPE_MESH_POINT:
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
case NL80211_IFTYPE_AP:
|
||||
wdev = brcmf_ap_add_vif(wiphy, name, flags, params);
|
||||
wdev = brcmf_ap_add_vif(wiphy, name, params);
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params);
|
||||
wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, params);
|
||||
break;
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
default:
|
||||
|
@ -858,7 +856,7 @@ int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
|
|||
|
||||
static s32
|
||||
brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
|
||||
|
@ -6553,7 +6551,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
|
|||
if (err)
|
||||
goto default_conf_out;
|
||||
err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
|
||||
NULL, NULL);
|
||||
NULL);
|
||||
if (err)
|
||||
goto default_conf_out;
|
||||
|
||||
|
|
|
@ -2141,12 +2141,11 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,
|
|||
* @name: name of the new interface.
|
||||
* @name_assign_type: origin of the interface name
|
||||
* @type: nl80211 interface type.
|
||||
* @flags: not used.
|
||||
* @params: contains mac address for P2P device.
|
||||
*/
|
||||
struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
|
||||
unsigned char name_assign_type,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
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);
|
|||
void brcmf_p2p_detach(struct brcmf_p2p_info *p2p);
|
||||
struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
|
||||
unsigned char name_assign_type,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params);
|
||||
int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev);
|
||||
int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
|
||||
|
|
|
@ -1082,6 +1082,8 @@ static int ieee_hw_init(struct ieee80211_hw *hw)
|
|||
* hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
|
||||
*/
|
||||
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
hw->rate_control_algorithm = "minstrel_ht";
|
||||
|
||||
hw->sta_data_size = 0;
|
||||
|
|
|
@ -3592,6 +3592,8 @@ il3945_setup_mac(struct il_priv *il)
|
|||
|
||||
il_leds_init(il);
|
||||
|
||||
wiphy_ext_feature_set(il->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
ret = ieee80211_register_hw(il->hw);
|
||||
if (ret) {
|
||||
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,
|
|||
rate_mask = sta->supp_rates[sband->band];
|
||||
|
||||
/* get user max rate if set */
|
||||
max_rate_idx = txrc->max_rate_idx;
|
||||
max_rate_idx = fls(txrc->rate_idx_mask) - 1;
|
||||
if (sband->band == NL80211_BAND_5GHZ && max_rate_idx != -1)
|
||||
max_rate_idx += IL_FIRST_OFDM_RATE;
|
||||
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)
|
|||
|
||||
il_leds_init(il);
|
||||
|
||||
wiphy_ext_feature_set(il->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
ret = ieee80211_register_hw(il->hw);
|
||||
if (ret) {
|
||||
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,
|
|||
|
||||
/* Get max rate if user set max rate */
|
||||
if (lq_sta) {
|
||||
lq_sta->max_rate_idx = txrc->max_rate_idx;
|
||||
lq_sta->max_rate_idx = fls(txrc->rate_idx_mask) - 1;
|
||||
if (sband->band == NL80211_BAND_5GHZ &&
|
||||
lq_sta->max_rate_idx != -1)
|
||||
lq_sta->max_rate_idx += IL_FIRST_OFDM_RATE;
|
||||
|
|
|
@ -213,6 +213,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
|
|||
|
||||
iwl_leds_init(priv);
|
||||
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
ret = ieee80211_register_hw(priv->hw);
|
||||
if (ret) {
|
||||
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,
|
|||
|
||||
/* Get max rate if user set max rate */
|
||||
if (lq_sta) {
|
||||
lq_sta->max_rate_idx = txrc->max_rate_idx;
|
||||
lq_sta->max_rate_idx = fls(txrc->rate_idx_mask) - 1;
|
||||
if ((sband->band == NL80211_BAND_5GHZ) &&
|
||||
(lq_sta->max_rate_idx != -1))
|
||||
lq_sta->max_rate_idx += IWL_FIRST_OFDM_RATE;
|
||||
|
|
|
@ -97,7 +97,7 @@ int orinoco_wiphy_register(struct wiphy *wiphy)
|
|||
}
|
||||
|
||||
static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct orinoco_private *priv = wiphy_priv(wiphy);
|
||||
|
|
|
@ -350,6 +350,7 @@ static const struct ieee80211_channel hwsim_channels_5ghz[] = {
|
|||
CHAN5G(5785), /* Channel 157 */
|
||||
CHAN5G(5805), /* Channel 161 */
|
||||
CHAN5G(5825), /* Channel 165 */
|
||||
CHAN5G(5845), /* Channel 169 */
|
||||
};
|
||||
|
||||
static const struct ieee80211_rate hwsim_rates[] = {
|
||||
|
@ -525,6 +526,11 @@ struct mac80211_hwsim_data {
|
|||
struct ieee80211_vif *hw_scan_vif;
|
||||
int scan_chan_idx;
|
||||
u8 scan_addr[ETH_ALEN];
|
||||
struct {
|
||||
struct ieee80211_channel *channel;
|
||||
unsigned long next_start, start, end;
|
||||
} survey_data[ARRAY_SIZE(hwsim_channels_2ghz) +
|
||||
ARRAY_SIZE(hwsim_channels_5ghz)];
|
||||
|
||||
struct ieee80211_channel *channel;
|
||||
u64 beacon_int /* beacon interval in us */;
|
||||
|
@ -552,8 +558,6 @@ struct mac80211_hwsim_data {
|
|||
/* wmediumd portid responsible for netgroup of this radio */
|
||||
u32 wmediumd;
|
||||
|
||||
int power_level;
|
||||
|
||||
/* difference between this hw's clock and the real clock, in usecs */
|
||||
s64 tsf_offset;
|
||||
s64 bcn_delta;
|
||||
|
@ -1201,7 +1205,9 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
|
|||
if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
|
||||
rx_status.flag |= RX_FLAG_SHORT_GI;
|
||||
/* TODO: simulate real signal strength (and optional packet loss) */
|
||||
rx_status.signal = data->power_level - 50;
|
||||
rx_status.signal = -50;
|
||||
if (info->control.vif)
|
||||
rx_status.signal += info->control.vif->bss_conf.txpower;
|
||||
|
||||
if (data->ps != PS_DISABLED)
|
||||
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
|
||||
|
@ -1576,6 +1582,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
|
|||
[IEEE80211_SMPS_STATIC] = "static",
|
||||
[IEEE80211_SMPS_DYNAMIC] = "dynamic",
|
||||
};
|
||||
int idx;
|
||||
|
||||
if (conf->chandef.chan)
|
||||
wiphy_debug(hw->wiphy,
|
||||
|
@ -1598,11 +1605,34 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
|
|||
|
||||
data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);
|
||||
|
||||
data->channel = conf->chandef.chan;
|
||||
WARN_ON(conf->chandef.chan && data->use_chanctx);
|
||||
|
||||
WARN_ON(data->channel && data->use_chanctx);
|
||||
mutex_lock(&data->mutex);
|
||||
if (data->scanning && conf->chandef.chan) {
|
||||
for (idx = 0; idx < ARRAY_SIZE(data->survey_data); idx++) {
|
||||
if (data->survey_data[idx].channel == data->channel) {
|
||||
data->survey_data[idx].start =
|
||||
data->survey_data[idx].next_start;
|
||||
data->survey_data[idx].end = jiffies;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
data->channel = conf->chandef.chan;
|
||||
|
||||
for (idx = 0; idx < ARRAY_SIZE(data->survey_data); idx++) {
|
||||
if (data->survey_data[idx].channel &&
|
||||
data->survey_data[idx].channel != data->channel)
|
||||
continue;
|
||||
data->survey_data[idx].channel = data->channel;
|
||||
data->survey_data[idx].next_start = jiffies;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
data->channel = conf->chandef.chan;
|
||||
}
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
data->power_level = conf->power_level;
|
||||
if (!data->started || !data->beacon_int)
|
||||
tasklet_hrtimer_cancel(&data->beacon_timer);
|
||||
else if (!hrtimer_is_queued(&data->beacon_timer.timer)) {
|
||||
|
@ -1787,28 +1817,37 @@ static int mac80211_hwsim_conf_tx(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mac80211_hwsim_get_survey(
|
||||
struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey)
|
||||
static int mac80211_hwsim_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey)
|
||||
{
|
||||
struct ieee80211_conf *conf = &hw->conf;
|
||||
struct mac80211_hwsim_data *hwsim = hw->priv;
|
||||
|
||||
wiphy_debug(hw->wiphy, "%s (idx=%d)\n", __func__, idx);
|
||||
|
||||
if (idx != 0)
|
||||
if (idx < 0 || idx >= ARRAY_SIZE(hwsim->survey_data))
|
||||
return -ENOENT;
|
||||
|
||||
/* Current channel */
|
||||
survey->channel = conf->chandef.chan;
|
||||
mutex_lock(&hwsim->mutex);
|
||||
survey->channel = hwsim->survey_data[idx].channel;
|
||||
if (!survey->channel) {
|
||||
mutex_unlock(&hwsim->mutex);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Magically conjured noise level --- this is only ok for simulated hardware.
|
||||
* Magically conjured dummy values --- this is only ok for simulated hardware.
|
||||
*
|
||||
* A real driver which cannot determine the real channel noise MUST NOT
|
||||
* report any noise, especially not a magically conjured one :-)
|
||||
* A real driver which cannot determine real values noise MUST NOT
|
||||
* report any, especially not a magically conjured ones :-)
|
||||
*/
|
||||
survey->filled = SURVEY_INFO_NOISE_DBM;
|
||||
survey->filled = SURVEY_INFO_NOISE_DBM |
|
||||
SURVEY_INFO_TIME |
|
||||
SURVEY_INFO_TIME_BUSY;
|
||||
survey->noise = -92;
|
||||
survey->time =
|
||||
jiffies_to_msecs(hwsim->survey_data[idx].end -
|
||||
hwsim->survey_data[idx].start);
|
||||
/* report 12.5% of channel time is used */
|
||||
survey->time_busy = survey->time/8;
|
||||
mutex_unlock(&hwsim->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1986,6 +2025,10 @@ static void hw_scan_work(struct work_struct *work)
|
|||
}
|
||||
ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan,
|
||||
msecs_to_jiffies(dwell));
|
||||
hwsim->survey_data[hwsim->scan_chan_idx].channel = hwsim->tmp_chan;
|
||||
hwsim->survey_data[hwsim->scan_chan_idx].start = jiffies;
|
||||
hwsim->survey_data[hwsim->scan_chan_idx].end =
|
||||
jiffies + msecs_to_jiffies(dwell);
|
||||
hwsim->scan_chan_idx++;
|
||||
mutex_unlock(&hwsim->mutex);
|
||||
}
|
||||
|
@ -2011,6 +2054,7 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
|
|||
hw_req->req.mac_addr_mask);
|
||||
else
|
||||
memcpy(hwsim->scan_addr, vif->addr, ETH_ALEN);
|
||||
memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data));
|
||||
mutex_unlock(&hwsim->mutex);
|
||||
|
||||
wiphy_debug(hw->wiphy, "hwsim hw_scan request\n");
|
||||
|
@ -2057,6 +2101,7 @@ static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw,
|
|||
|
||||
memcpy(hwsim->scan_addr, mac_addr, ETH_ALEN);
|
||||
hwsim->scanning = true;
|
||||
memset(hwsim->survey_data, 0, sizeof(hwsim->survey_data));
|
||||
|
||||
out:
|
||||
mutex_unlock(&hwsim->mutex);
|
||||
|
@ -2207,7 +2252,6 @@ static const char mac80211_hwsim_gstrings_stats[][ETH_GSTRING_LEN] = {
|
|||
"d_tx_failed",
|
||||
"d_ps_mode",
|
||||
"d_group",
|
||||
"d_tx_power",
|
||||
};
|
||||
|
||||
#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,
|
|||
data[i++] = ar->tx_failed;
|
||||
data[i++] = ar->ps;
|
||||
data[i++] = ar->group;
|
||||
data[i++] = ar->power_level;
|
||||
|
||||
WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN);
|
||||
}
|
||||
|
@ -2438,6 +2481,9 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
|||
goto failed;
|
||||
}
|
||||
|
||||
/* ieee80211_alloc_hw_nm may have used a default name */
|
||||
param->hwname = wiphy_name(hw->wiphy);
|
||||
|
||||
if (info)
|
||||
net = genl_info_net(info);
|
||||
else
|
||||
|
@ -2645,6 +2691,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
|
|||
if (param->no_vif)
|
||||
ieee80211_hw_set(hw, NO_AUTO_VIF);
|
||||
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
err = ieee80211_register_hw(hw);
|
||||
if (err < 0) {
|
||||
printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n",
|
||||
|
|
|
@ -57,12 +57,12 @@ enum hwsim_tx_control_flags {
|
|||
* @HWSIM_CMD_REGISTER: request to register and received all broadcasted
|
||||
* frames by any mac80211_hwsim radio device.
|
||||
* @HWSIM_CMD_FRAME: send/receive a broadcasted frame from/to kernel/user
|
||||
* space, uses:
|
||||
* space, uses:
|
||||
* %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_ADDR_RECEIVER,
|
||||
* %HWSIM_ATTR_FRAME, %HWSIM_ATTR_FLAGS, %HWSIM_ATTR_RX_RATE,
|
||||
* %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE, %HWSIM_ATTR_FREQ (optional)
|
||||
* @HWSIM_CMD_TX_INFO_FRAME: Transmission info report from user space to
|
||||
* kernel, uses:
|
||||
* kernel, uses:
|
||||
* %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS,
|
||||
* %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE
|
||||
* @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,
|
|||
*/
|
||||
|
||||
static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct lbs_private *priv = wiphy_priv(wiphy);
|
||||
|
|
|
@ -641,6 +641,8 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev)
|
|||
BIT(NL80211_IFTYPE_ADHOC);
|
||||
skb_queue_head_init(&priv->bc_ps_buf);
|
||||
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
SET_IEEE80211_DEV(hw, dmdev);
|
||||
|
||||
INIT_WORK(&priv->cmd_work, lbtf_cmd_work);
|
||||
|
|
|
@ -935,7 +935,7 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv,
|
|||
static int
|
||||
mwifiex_change_vif_to_p2p(struct net_device *dev,
|
||||
enum nl80211_iftype curr_iftype,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct mwifiex_private *priv;
|
||||
|
@ -1007,7 +1007,7 @@ mwifiex_change_vif_to_p2p(struct net_device *dev,
|
|||
static int
|
||||
mwifiex_change_vif_to_sta_adhoc(struct net_device *dev,
|
||||
enum nl80211_iftype curr_iftype,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct mwifiex_private *priv;
|
||||
|
@ -1066,7 +1066,7 @@ mwifiex_change_vif_to_sta_adhoc(struct net_device *dev,
|
|||
static int
|
||||
mwifiex_change_vif_to_ap(struct net_device *dev,
|
||||
enum nl80211_iftype curr_iftype,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct mwifiex_private *priv;
|
||||
|
@ -1122,7 +1122,7 @@ mwifiex_change_vif_to_ap(struct net_device *dev,
|
|||
static int
|
||||
mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
|
||||
|
@ -1143,10 +1143,10 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
|
|||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
return mwifiex_change_vif_to_p2p(dev, curr_iftype,
|
||||
type, flags, params);
|
||||
type, params);
|
||||
case NL80211_IFTYPE_AP:
|
||||
return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
|
||||
flags, params);
|
||||
params);
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
mwifiex_dbg(priv->adapter, INFO,
|
||||
"%s: kept type as IBSS\n", dev->name);
|
||||
|
@ -1173,10 +1173,10 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
|
|||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
return mwifiex_change_vif_to_p2p(dev, curr_iftype,
|
||||
type, flags, params);
|
||||
type, params);
|
||||
case NL80211_IFTYPE_AP:
|
||||
return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
|
||||
flags, params);
|
||||
params);
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
mwifiex_dbg(priv->adapter, INFO,
|
||||
"%s: kept type as STA\n", dev->name);
|
||||
|
@ -1194,13 +1194,12 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
|
|||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype,
|
||||
type, flags,
|
||||
params);
|
||||
type, params);
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
return mwifiex_change_vif_to_p2p(dev, curr_iftype,
|
||||
type, flags, params);
|
||||
type, params);
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
mwifiex_dbg(priv->adapter, INFO,
|
||||
"%s: kept type as AP\n", dev->name);
|
||||
|
@ -1233,14 +1232,13 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
|
|||
if (mwifiex_cfg80211_deinit_p2p(priv))
|
||||
return -EFAULT;
|
||||
return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype,
|
||||
type, flags,
|
||||
params);
|
||||
type, params);
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
if (mwifiex_cfg80211_deinit_p2p(priv))
|
||||
return -EFAULT;
|
||||
return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
|
||||
flags, params);
|
||||
params);
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
mwifiex_dbg(priv->adapter, INFO,
|
||||
"%s: kept type as P2P\n", dev->name);
|
||||
|
@ -2841,7 +2839,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
|||
const char *name,
|
||||
unsigned char name_assign_type,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
|
||||
|
|
|
@ -596,7 +596,7 @@ static int _mwifiex_fw_dpc(const struct firmware *firmware, void *context)
|
|||
rtnl_lock();
|
||||
/* Create station interface by default */
|
||||
wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", NET_NAME_ENUM,
|
||||
NL80211_IFTYPE_STATION, NULL, NULL);
|
||||
NL80211_IFTYPE_STATION, NULL);
|
||||
if (IS_ERR(wdev)) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"cannot create default STA interface\n");
|
||||
|
@ -606,7 +606,7 @@ static int _mwifiex_fw_dpc(const struct firmware *firmware, void *context)
|
|||
|
||||
if (driver_mode & MWIFIEX_DRIVER_MODE_UAP) {
|
||||
wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", NET_NAME_ENUM,
|
||||
NL80211_IFTYPE_AP, NULL, NULL);
|
||||
NL80211_IFTYPE_AP, NULL);
|
||||
if (IS_ERR(wdev)) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"cannot create AP interface\n");
|
||||
|
@ -617,8 +617,7 @@ static int _mwifiex_fw_dpc(const struct firmware *firmware, void *context)
|
|||
|
||||
if (driver_mode & MWIFIEX_DRIVER_MODE_P2P) {
|
||||
wdev = mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d", NET_NAME_ENUM,
|
||||
NL80211_IFTYPE_P2P_CLIENT, NULL,
|
||||
NULL);
|
||||
NL80211_IFTYPE_P2P_CLIENT, NULL);
|
||||
if (IS_ERR(wdev)) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"cannot create p2p client interface\n");
|
||||
|
|
|
@ -1529,7 +1529,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
|||
const char *name,
|
||||
unsigned char name_assign_type,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params);
|
||||
int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev);
|
||||
|
||||
|
|
|
@ -349,7 +349,7 @@ static int mwifiex_tdls_add_vht_oper(struct mwifiex_private *priv,
|
|||
chan_bw = IEEE80211_VHT_CHANWIDTH_USE_HT;
|
||||
break;
|
||||
}
|
||||
vht_oper->center_freq_seg1_idx =
|
||||
vht_oper->center_freq_seg0_idx =
|
||||
mwifiex_get_center_freq_index(priv, BAND_AAC,
|
||||
bss_desc->channel,
|
||||
chan_bw);
|
||||
|
|
|
@ -6144,6 +6144,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
|
|||
if (priv->sta_macids_supported || priv->device_info->fw_image_sta)
|
||||
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION);
|
||||
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
rc = ieee80211_register_hw(hw);
|
||||
if (rc) {
|
||||
wiphy_err(hw->wiphy, "Cannot register device\n");
|
||||
|
|
|
@ -615,6 +615,8 @@ int mt7601u_register_device(struct mt7601u_dev *dev)
|
|||
wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
|
||||
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
||||
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
ret = mt76_init_sband_2g(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
@ -1456,6 +1456,9 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
|
|||
|
||||
rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
|
||||
|
||||
wiphy_ext_feature_set(rt2x00dev->hw->wiphy,
|
||||
NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
/*
|
||||
* Initialize ieee80211 structure.
|
||||
*/
|
||||
|
|
|
@ -1877,6 +1877,8 @@ static int rtl8180_probe(struct pci_dev *pdev,
|
|||
else
|
||||
ieee80211_hw_set(dev, SIGNAL_UNSPEC);
|
||||
|
||||
wiphy_ext_feature_set(dev->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
rtl8180_eeprom_read(priv);
|
||||
|
||||
switch (priv->rf_type) {
|
||||
|
|
|
@ -1607,6 +1607,8 @@ static int rtl8187_probe(struct usb_interface *intf,
|
|||
dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC) ;
|
||||
|
||||
wiphy_ext_feature_set(dev->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b)
|
||||
printk(KERN_INFO "rtl8187: inconsistency between id with OEM"
|
||||
" info!\n");
|
||||
|
|
|
@ -6135,6 +6135,8 @@ static int rtl8xxxu_probe(struct usb_interface *interface,
|
|||
ieee80211_hw_set(hw, HAS_RATE_CONTROL);
|
||||
ieee80211_hw_set(hw, AMPDU_AGGREGATION);
|
||||
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
ret = ieee80211_register_hw(priv->hw);
|
||||
if (ret) {
|
||||
dev_err(&udev->dev, "%s: Failed to register: %i\n",
|
||||
|
|
|
@ -479,7 +479,7 @@ struct rndis_wlan_private {
|
|||
*/
|
||||
static int rndis_change_virtual_intf(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params);
|
||||
|
||||
static int rndis_scan(struct wiphy *wiphy,
|
||||
|
@ -1857,7 +1857,7 @@ static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev,
|
|||
*/
|
||||
static int rndis_change_virtual_intf(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
|
||||
|
|
|
@ -1261,6 +1261,8 @@ int rsi_mac80211_attach(struct rsi_common *common)
|
|||
|
||||
wiphy->reg_notifier = rsi_reg_notify;
|
||||
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
status = ieee80211_register_hw(hw);
|
||||
if (status)
|
||||
return status;
|
||||
|
|
|
@ -1408,6 +1408,8 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
|
|||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_AP);
|
||||
|
||||
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
|
||||
|
||||
hw->max_signal = 100;
|
||||
hw->queues = 1;
|
||||
hw->extra_tx_headroom = sizeof(struct zd_ctrlset);
|
||||
|
|
|
@ -1837,7 +1837,7 @@ static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
|
|||
}
|
||||
|
||||
static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
|
||||
enum nl80211_iftype type, u32 *flags, struct vif_params *params)
|
||||
enum nl80211_iftype type, struct vif_params *params)
|
||||
{
|
||||
struct wilc_priv *priv;
|
||||
struct wilc_vif *vif;
|
||||
|
@ -2099,7 +2099,6 @@ static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy,
|
|||
const char *name,
|
||||
unsigned char name_assign_type,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct wilc_vif *vif;
|
||||
|
|
|
@ -100,7 +100,7 @@ static int prism2_domibset_pstr32(struct wlandevice *wlandev,
|
|||
/* The interface functions, called by the cfg80211 layer */
|
||||
static int prism2_change_virtual_intf(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct wlandevice *wlandev = dev->ml_priv;
|
||||
|
|
|
@ -1411,6 +1411,8 @@ struct ieee80211_ht_operation {
|
|||
#define IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED 3
|
||||
#define IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT 0x0004
|
||||
#define IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT 0x0010
|
||||
#define IEEE80211_HT_OP_MODE_CCFS2_SHIFT 5
|
||||
#define IEEE80211_HT_OP_MODE_CCFS2_MASK 0x1fe0
|
||||
|
||||
/* for stbc_param */
|
||||
#define IEEE80211_HT_STBC_PARAM_DUAL_BEACON 0x0040
|
||||
|
@ -1525,14 +1527,14 @@ enum ieee80211_vht_chanwidth {
|
|||
* This structure is the "VHT operation element" as
|
||||
* described in 802.11ac D3.0 8.4.2.161
|
||||
* @chan_width: Operating channel width
|
||||
* @center_freq_seg0_idx: center freq segment 0 index
|
||||
* @center_freq_seg1_idx: center freq segment 1 index
|
||||
* @center_freq_seg2_idx: center freq segment 2 index
|
||||
* @basic_mcs_set: VHT Basic MCS rate set
|
||||
*/
|
||||
struct ieee80211_vht_operation {
|
||||
u8 chan_width;
|
||||
u8 center_freq_seg0_idx;
|
||||
u8 center_freq_seg1_idx;
|
||||
u8 center_freq_seg2_idx;
|
||||
__le16 basic_mcs_set;
|
||||
} __packed;
|
||||
|
||||
|
@ -1721,6 +1723,9 @@ enum ieee80211_statuscode {
|
|||
WLAN_STATUS_REJECT_DSE_BAND = 96,
|
||||
WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL = 99,
|
||||
WLAN_STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT = 103,
|
||||
/* 802.11ai */
|
||||
WLAN_STATUS_FILS_AUTHENTICATION_FAILURE = 108,
|
||||
WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER = 109,
|
||||
};
|
||||
|
||||
|
||||
|
@ -2102,6 +2107,12 @@ enum ieee80211_key_len {
|
|||
#define FILS_NONCE_LEN 16
|
||||
#define FILS_MAX_KEK_LEN 64
|
||||
|
||||
#define FILS_ERP_MAX_USERNAME_LEN 16
|
||||
#define FILS_ERP_MAX_REALM_LEN 253
|
||||
#define FILS_ERP_MAX_RRK_LEN 64
|
||||
|
||||
#define PMK_MAX_LEN 48
|
||||
|
||||
/* Public action codes */
|
||||
enum ieee80211_pub_actioncode {
|
||||
WLAN_PUB_ACTION_EXT_CHANSW_ANN = 4,
|
||||
|
@ -2347,11 +2358,16 @@ enum ieee80211_sa_query_action {
|
|||
/* AKM suite selectors */
|
||||
#define WLAN_AKM_SUITE_8021X SUITE(0x000FAC, 1)
|
||||
#define WLAN_AKM_SUITE_PSK SUITE(0x000FAC, 2)
|
||||
#define WLAN_AKM_SUITE_FT_PSK SUITE(0x000FAC, 4)
|
||||
#define WLAN_AKM_SUITE_8021X_SHA256 SUITE(0x000FAC, 5)
|
||||
#define WLAN_AKM_SUITE_PSK_SHA256 SUITE(0x000FAC, 6)
|
||||
#define WLAN_AKM_SUITE_TDLS SUITE(0x000FAC, 7)
|
||||
#define WLAN_AKM_SUITE_SAE SUITE(0x000FAC, 8)
|
||||
#define WLAN_AKM_SUITE_FT_OVER_SAE SUITE(0x000FAC, 9)
|
||||
#define WLAN_AKM_SUITE_FILS_SHA256 SUITE(0x000FAC, 14)
|
||||
#define WLAN_AKM_SUITE_FILS_SHA384 SUITE(0x000FAC, 15)
|
||||
#define WLAN_AKM_SUITE_FT_FILS_SHA256 SUITE(0x000FAC, 16)
|
||||
#define WLAN_AKM_SUITE_FT_FILS_SHA384 SUITE(0x000FAC, 17)
|
||||
|
||||
#define WLAN_MAX_KEY_LEN 32
|
||||
|
||||
|
|
|
@ -363,6 +363,8 @@ static inline void wiphy_read_of_freq_limits(struct wiphy *wiphy)
|
|||
|
||||
/**
|
||||
* struct vif_params - describes virtual interface parameters
|
||||
* @flags: monitor interface flags, unchanged if 0, otherwise
|
||||
* %MONITOR_FLAG_CHANGED will be set
|
||||
* @use_4addr: use 4-address frames
|
||||
* @macaddr: address to use for this virtual interface.
|
||||
* 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)
|
|||
* This feature is only fully supported by drivers that enable the
|
||||
* %NL80211_FEATURE_MAC_ON_CREATE flag. Others may support creating
|
||||
** only p2p devices with specified MAC.
|
||||
* @vht_mumimo_groups: MU-MIMO groupID. used for monitoring only
|
||||
* packets belonging to that MU-MIMO groupID.
|
||||
* @vht_mumimo_groups: MU-MIMO groupID, used for monitoring MU-MIMO packets
|
||||
* belonging to that MU-MIMO groupID; %NULL if not changed
|
||||
* @vht_mumimo_follow_addr: MU-MIMO follow address, used for monitoring
|
||||
* MU-MIMO packets going to the specified station; %NULL if not changed
|
||||
*/
|
||||
struct vif_params {
|
||||
u32 flags;
|
||||
int use_4addr;
|
||||
u8 macaddr[ETH_ALEN];
|
||||
u8 vht_mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN];
|
||||
const u8 *vht_mumimo_groups;
|
||||
const u8 *vht_mumimo_follow_addr;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1211,6 +1217,7 @@ static inline int cfg80211_get_station(struct net_device *dev,
|
|||
* Monitor interface configuration flags. Note that these must be the bits
|
||||
* according to the nl80211 flags.
|
||||
*
|
||||
* @MONITOR_FLAG_CHANGED: set if the flags were changed
|
||||
* @MONITOR_FLAG_FCSFAIL: pass frames with bad FCS
|
||||
* @MONITOR_FLAG_PLCPFAIL: pass frames with bad PLCP
|
||||
* @MONITOR_FLAG_CONTROL: pass control frames
|
||||
|
@ -1219,6 +1226,7 @@ static inline int cfg80211_get_station(struct net_device *dev,
|
|||
* @MONITOR_FLAG_ACTIVE: active monitor, ACKs frames on its MAC address
|
||||
*/
|
||||
enum monitor_flags {
|
||||
MONITOR_FLAG_CHANGED = 1<<__NL80211_MNTR_FLAG_INVALID,
|
||||
MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL,
|
||||
MONITOR_FLAG_PLCPFAIL = 1<<NL80211_MNTR_FLAG_PLCPFAIL,
|
||||
MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL,
|
||||
|
@ -1641,6 +1649,7 @@ struct cfg80211_bss_select_adjust {
|
|||
/**
|
||||
* struct cfg80211_sched_scan_request - scheduled scan request description
|
||||
*
|
||||
* @reqid: identifies this request.
|
||||
* @ssids: SSIDs to scan for (passed in the probe_reqs in active scans)
|
||||
* @n_ssids: number of SSIDs
|
||||
* @n_channels: total number of channels to scan
|
||||
|
@ -1685,6 +1694,7 @@ struct cfg80211_bss_select_adjust {
|
|||
* comparisions.
|
||||
*/
|
||||
struct cfg80211_sched_scan_request {
|
||||
u64 reqid;
|
||||
struct cfg80211_ssid *ssids;
|
||||
int n_ssids;
|
||||
u32 n_channels;
|
||||
|
@ -2073,6 +2083,19 @@ struct cfg80211_bss_selection {
|
|||
* the BSSID of the current association, i.e., to the value that is
|
||||
* included in the Current AP address field of the Reassociation Request
|
||||
* frame.
|
||||
* @fils_erp_username: EAP re-authentication protocol (ERP) username part of the
|
||||
* NAI or %NULL if not specified. This is used to construct FILS wrapped
|
||||
* data IE.
|
||||
* @fils_erp_username_len: Length of @fils_erp_username in octets.
|
||||
* @fils_erp_realm: EAP re-authentication protocol (ERP) realm part of NAI or
|
||||
* %NULL if not specified. This specifies the domain name of ER server and
|
||||
* is used to construct FILS wrapped data IE.
|
||||
* @fils_erp_realm_len: Length of @fils_erp_realm in octets.
|
||||
* @fils_erp_next_seq_num: The next sequence number to use in the FILS ERP
|
||||
* messages. This is also used to construct FILS wrapped data IE.
|
||||
* @fils_erp_rrk: ERP re-authentication Root Key (rRK) used to derive additional
|
||||
* keys in FILS or %NULL if not specified.
|
||||
* @fils_erp_rrk_len: Length of @fils_erp_rrk in octets.
|
||||
*/
|
||||
struct cfg80211_connect_params {
|
||||
struct ieee80211_channel *channel;
|
||||
|
@ -2098,6 +2121,13 @@ struct cfg80211_connect_params {
|
|||
bool pbss;
|
||||
struct cfg80211_bss_selection bss_select;
|
||||
const u8 *prev_bssid;
|
||||
const u8 *fils_erp_username;
|
||||
size_t fils_erp_username_len;
|
||||
const u8 *fils_erp_realm;
|
||||
size_t fils_erp_realm_len;
|
||||
u16 fils_erp_next_seq_num;
|
||||
const u8 *fils_erp_rrk;
|
||||
size_t fils_erp_rrk_len;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -2136,12 +2166,27 @@ enum wiphy_params_flags {
|
|||
* This structure is passed to the set/del_pmksa() method for PMKSA
|
||||
* caching.
|
||||
*
|
||||
* @bssid: The AP's BSSID.
|
||||
* @pmkid: The PMK material itself.
|
||||
* @bssid: The AP's BSSID (may be %NULL).
|
||||
* @pmkid: The identifier to refer a PMKSA.
|
||||
* @pmk: The PMK for the PMKSA identified by @pmkid. This is used for key
|
||||
* derivation by a FILS STA. Otherwise, %NULL.
|
||||
* @pmk_len: Length of the @pmk. The length of @pmk can differ depending on
|
||||
* the hash algorithm used to generate this.
|
||||
* @ssid: SSID to specify the ESS within which a PMKSA is valid when using FILS
|
||||
* cache identifier (may be %NULL).
|
||||
* @ssid_len: Length of the @ssid in octets.
|
||||
* @cache_id: 2-octet cache identifier advertized by a FILS AP identifying the
|
||||
* scope of PMKSA. This is valid only if @ssid_len is non-zero (may be
|
||||
* %NULL).
|
||||
*/
|
||||
struct cfg80211_pmksa {
|
||||
const u8 *bssid;
|
||||
const u8 *pmkid;
|
||||
const u8 *pmk;
|
||||
size_t pmk_len;
|
||||
const u8 *ssid;
|
||||
size_t ssid_len;
|
||||
const u8 *cache_id;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -2712,6 +2757,11 @@ struct cfg80211_nan_func {
|
|||
* the current level is above/below the configured threshold; this may
|
||||
* need some care when the configuration is changed (without first being
|
||||
* disabled.)
|
||||
* @set_cqm_rssi_range_config: Configure two RSSI thresholds in the
|
||||
* connection quality monitor. An event is to be sent only when the
|
||||
* signal level is found to be outside the two values. The driver should
|
||||
* set %NL80211_EXT_FEATURE_CQM_RSSI_LIST if this method is implemented.
|
||||
* If it is provided then there's no point providing @set_cqm_rssi_config.
|
||||
* @set_cqm_txe_config: Configure connection quality monitor TX error
|
||||
* thresholds.
|
||||
* @sched_scan_start: Tell the driver to start a scheduled scan.
|
||||
|
@ -2826,13 +2876,12 @@ struct cfg80211_ops {
|
|||
const char *name,
|
||||
unsigned char name_assign_type,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params);
|
||||
int (*del_virtual_intf)(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev);
|
||||
int (*change_virtual_intf)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params);
|
||||
|
||||
int (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
|
||||
|
@ -3001,6 +3050,10 @@ struct cfg80211_ops {
|
|||
struct net_device *dev,
|
||||
s32 rssi_thold, u32 rssi_hyst);
|
||||
|
||||
int (*set_cqm_rssi_range_config)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
s32 rssi_low, s32 rssi_high);
|
||||
|
||||
int (*set_cqm_txe_config)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
u32 rate, u32 pkts, u32 intvl);
|
||||
|
@ -3871,6 +3924,7 @@ void wiphy_free(struct wiphy *wiphy);
|
|||
struct cfg80211_conn;
|
||||
struct cfg80211_internal_bss;
|
||||
struct cfg80211_cached_keys;
|
||||
struct cfg80211_cqm_config;
|
||||
|
||||
/**
|
||||
* struct wireless_dev - wireless device state
|
||||
|
@ -3934,6 +3988,7 @@ struct cfg80211_cached_keys;
|
|||
* @event_list: (private) list for internal event processing
|
||||
* @event_lock: (private) lock for event list
|
||||
* @owner_nlportid: (private) owner socket port ID
|
||||
* @cqm_config: (private) nl80211 RSSI monitor state
|
||||
*/
|
||||
struct wireless_dev {
|
||||
struct wiphy *wiphy;
|
||||
|
@ -4002,6 +4057,8 @@ struct wireless_dev {
|
|||
bool prev_bssid_valid;
|
||||
} wext;
|
||||
#endif
|
||||
|
||||
struct cfg80211_cqm_config *cqm_config;
|
||||
};
|
||||
|
||||
static inline u8 *wdev_address(struct wireless_dev *wdev)
|
||||
|
@ -4651,12 +4708,22 @@ cfg80211_inform_bss(struct wiphy *wiphy,
|
|||
gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_get_bss - get a BSS reference
|
||||
* @wiphy: the wiphy this BSS struct belongs to
|
||||
* @channel: the channel to search on (or %NULL)
|
||||
* @bssid: the desired BSSID (or %NULL)
|
||||
* @ssid: the desired SSID (or %NULL)
|
||||
* @ssid_len: length of the SSID (or 0)
|
||||
* @bss_type: type of BSS, see &enum ieee80211_bss_type
|
||||
* @privacy: privacy filter, see &enum ieee80211_privacy
|
||||
*/
|
||||
struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *channel,
|
||||
const u8 *bssid,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
enum ieee80211_bss_type bss_type,
|
||||
enum ieee80211_privacy);
|
||||
enum ieee80211_privacy privacy);
|
||||
static inline struct cfg80211_bss *
|
||||
cfg80211_get_ibss(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *channel,
|
||||
|
@ -5122,6 +5189,78 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
|
|||
#define CFG80211_TESTMODE_DUMP(cmd)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* struct cfg80211_connect_resp_params - Connection response params
|
||||
* @status: Status code, %WLAN_STATUS_SUCCESS for successful connection, use
|
||||
* %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you
|
||||
* the real status code for failures. If this call is used to report a
|
||||
* failure due to a timeout (e.g., not receiving an Authentication frame
|
||||
* from the AP) instead of an explicit rejection by the AP, -1 is used to
|
||||
* indicate that this is a failure, but without a status code.
|
||||
* @timeout_reason is used to report the reason for the timeout in that
|
||||
* case.
|
||||
* @bssid: The BSSID of the AP (may be %NULL)
|
||||
* @bss: Entry of bss to which STA got connected to, can be obtained through
|
||||
* cfg80211_get_bss() (may be %NULL). Only one parameter among @bssid and
|
||||
* @bss needs to be specified.
|
||||
* @req_ie: Association request IEs (may be %NULL)
|
||||
* @req_ie_len: Association request IEs length
|
||||
* @resp_ie: Association response IEs (may be %NULL)
|
||||
* @resp_ie_len: Association response IEs length
|
||||
* @fils_kek: KEK derived from a successful FILS connection (may be %NULL)
|
||||
* @fils_kek_len: Length of @fils_kek in octets
|
||||
* @update_erp_next_seq_num: Boolean value to specify whether the value in
|
||||
* @fils_erp_next_seq_num is valid.
|
||||
* @fils_erp_next_seq_num: The next sequence number to use in ERP message in
|
||||
* FILS Authentication. This value should be specified irrespective of the
|
||||
* status for a FILS connection.
|
||||
* @pmk: A new PMK if derived from a successful FILS connection (may be %NULL).
|
||||
* @pmk_len: Length of @pmk in octets
|
||||
* @pmkid: A new PMKID if derived from a successful FILS connection or the PMKID
|
||||
* used for this FILS connection (may be %NULL).
|
||||
* @timeout_reason: Reason for connection timeout. This is used when the
|
||||
* connection fails due to a timeout instead of an explicit rejection from
|
||||
* the AP. %NL80211_TIMEOUT_UNSPECIFIED is used when the timeout reason is
|
||||
* not known. This value is used only if @status < 0 to indicate that the
|
||||
* failure is due to a timeout and not due to explicit rejection by the AP.
|
||||
* This value is ignored in other cases (@status >= 0).
|
||||
*/
|
||||
struct cfg80211_connect_resp_params {
|
||||
int status;
|
||||
const u8 *bssid;
|
||||
struct cfg80211_bss *bss;
|
||||
const u8 *req_ie;
|
||||
size_t req_ie_len;
|
||||
const u8 *resp_ie;
|
||||
size_t resp_ie_len;
|
||||
const u8 *fils_kek;
|
||||
size_t fils_kek_len;
|
||||
bool update_erp_next_seq_num;
|
||||
u16 fils_erp_next_seq_num;
|
||||
const u8 *pmk;
|
||||
size_t pmk_len;
|
||||
const u8 *pmkid;
|
||||
enum nl80211_timeout_reason timeout_reason;
|
||||
};
|
||||
|
||||
/**
|
||||
* cfg80211_connect_done - notify cfg80211 of connection result
|
||||
*
|
||||
* @dev: network device
|
||||
* @params: connection response parameters
|
||||
* @gfp: allocation flags
|
||||
*
|
||||
* It should be called by the underlying driver once execution of the connection
|
||||
* request from connect() has been completed. This is similar to
|
||||
* cfg80211_connect_bss(), but takes a structure pointer for connection response
|
||||
* parameters. Only one of the functions among cfg80211_connect_bss(),
|
||||
* cfg80211_connect_result(), cfg80211_connect_timeout(),
|
||||
* and cfg80211_connect_done() should be called.
|
||||
*/
|
||||
void cfg80211_connect_done(struct net_device *dev,
|
||||
struct cfg80211_connect_resp_params *params,
|
||||
gfp_t gfp);
|
||||
|
||||
/**
|
||||
* cfg80211_connect_bss - notify cfg80211 of connection result
|
||||
*
|
||||
|
@ -5152,13 +5291,31 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
|
|||
* It should be called by the underlying driver once execution of the connection
|
||||
* request from connect() has been completed. This is similar to
|
||||
* cfg80211_connect_result(), but with the option of identifying the exact bss
|
||||
* entry for the connection. Only one of these functions should be called.
|
||||
* entry for the connection. Only one of the functions among
|
||||
* cfg80211_connect_bss(), cfg80211_connect_result(),
|
||||
* cfg80211_connect_timeout(), and cfg80211_connect_done() should be called.
|
||||
*/
|
||||
void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
|
||||
struct cfg80211_bss *bss, const u8 *req_ie,
|
||||
size_t req_ie_len, const u8 *resp_ie,
|
||||
size_t resp_ie_len, int status, gfp_t gfp,
|
||||
enum nl80211_timeout_reason timeout_reason);
|
||||
static inline void
|
||||
cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
|
||||
struct cfg80211_bss *bss, const u8 *req_ie,
|
||||
size_t req_ie_len, const u8 *resp_ie,
|
||||
size_t resp_ie_len, int status, gfp_t gfp,
|
||||
enum nl80211_timeout_reason timeout_reason)
|
||||
{
|
||||
struct cfg80211_connect_resp_params params;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.status = status;
|
||||
params.bssid = bssid;
|
||||
params.bss = bss;
|
||||
params.req_ie = req_ie;
|
||||
params.req_ie_len = req_ie_len;
|
||||
params.resp_ie = resp_ie;
|
||||
params.resp_ie_len = resp_ie_len;
|
||||
params.timeout_reason = timeout_reason;
|
||||
|
||||
cfg80211_connect_done(dev, ¶ms, gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_connect_result - notify cfg80211 of connection result
|
||||
|
@ -5177,7 +5334,8 @@ void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
|
|||
* It should be called by the underlying driver once execution of the connection
|
||||
* request from connect() has been completed. This is similar to
|
||||
* cfg80211_connect_bss() which allows the exact bss entry to be specified. Only
|
||||
* one of these functions should be called.
|
||||
* one of the functions among cfg80211_connect_bss(), cfg80211_connect_result(),
|
||||
* cfg80211_connect_timeout(), and cfg80211_connect_done() should be called.
|
||||
*/
|
||||
static inline void
|
||||
cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
|
@ -5204,7 +5362,9 @@ cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
* in a sequence where no explicit authentication/association rejection was
|
||||
* received from the AP. This could happen, e.g., due to not being able to send
|
||||
* out the Authentication or Association Request frame or timing out while
|
||||
* waiting for the response.
|
||||
* waiting for the response. Only one of the functions among
|
||||
* cfg80211_connect_bss(), cfg80211_connect_result(),
|
||||
* cfg80211_connect_timeout(), and cfg80211_connect_done() should be called.
|
||||
*/
|
||||
static inline void
|
||||
cfg80211_connect_timeout(struct net_device *dev, const u8 *bssid,
|
||||
|
|
|
@ -501,6 +501,10 @@ struct ieee80211_mu_group_data {
|
|||
* implies disabled. As with the cfg80211 callback, a change here should
|
||||
* cause an event to be sent indicating where the current value is in
|
||||
* relation to the newly configured threshold.
|
||||
* @cqm_rssi_low: Connection quality monitor RSSI lower threshold, a zero value
|
||||
* implies disabled. This is an alternative mechanism to the single
|
||||
* threshold event and can't be enabled simultaneously with it.
|
||||
* @cqm_rssi_high: Connection quality monitor RSSI upper threshold.
|
||||
* @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
|
||||
* @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
|
||||
* may filter ARP queries targeted for other addresses than listed here.
|
||||
|
@ -553,6 +557,8 @@ struct ieee80211_bss_conf {
|
|||
u16 ht_operation_mode;
|
||||
s32 cqm_rssi_thold;
|
||||
u32 cqm_rssi_hyst;
|
||||
s32 cqm_rssi_low;
|
||||
s32 cqm_rssi_high;
|
||||
struct cfg80211_chan_def chandef;
|
||||
struct ieee80211_mu_group_data mu_group;
|
||||
__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,
|
|||
* RTS threshold
|
||||
* @short_preamble: whether mac80211 will request short-preamble transmission
|
||||
* if the selected rate supports it
|
||||
* @max_rate_idx: user-requested maximum (legacy) rate
|
||||
* (deprecated; this will be removed once drivers get updated to use
|
||||
* rate_idx_mask)
|
||||
* @rate_idx_mask: user-requested (legacy) rate mask
|
||||
* @rate_idx_mcs_mask: user-requested MCS rate mask (NULL if not in use)
|
||||
* @bss: whether this frame is sent out in AP or IBSS mode
|
||||
|
@ -5452,7 +5455,6 @@ struct ieee80211_tx_rate_control {
|
|||
struct sk_buff *skb;
|
||||
struct ieee80211_tx_rate reported_rate;
|
||||
bool rts, short_preamble;
|
||||
u8 max_rate_idx;
|
||||
u32 rate_idx_mask;
|
||||
u8 *rate_idx_mcs_mask;
|
||||
bool bss;
|
||||
|
|
|
@ -172,6 +172,42 @@
|
|||
* Multiple such rules can be created.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: FILS shared key authentication offload
|
||||
*
|
||||
* FILS shared key authentication offload can be advertized by drivers by
|
||||
* setting @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD flag. The drivers that support
|
||||
* FILS shared key authentication offload should be able to construct the
|
||||
* authentication and association frames for FILS shared key authentication and
|
||||
* eventually do a key derivation as per IEEE 802.11ai. The below additional
|
||||
* parameters should be given to driver in %NL80211_CMD_CONNECT.
|
||||
* %NL80211_ATTR_FILS_ERP_USERNAME - used to construct keyname_nai
|
||||
* %NL80211_ATTR_FILS_ERP_REALM - used to construct keyname_nai
|
||||
* %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used to construct erp message
|
||||
* %NL80211_ATTR_FILS_ERP_RRK - used to generate the rIK and rMSK
|
||||
* rIK should be used to generate an authentication tag on the ERP message and
|
||||
* rMSK should be used to derive a PMKSA.
|
||||
* rIK, rMSK should be generated and keyname_nai, sequence number should be used
|
||||
* as specified in IETF RFC 6696.
|
||||
*
|
||||
* When FILS shared key authentication is completed, driver needs to provide the
|
||||
* below additional parameters to userspace.
|
||||
* %NL80211_ATTR_FILS_KEK - used for key renewal
|
||||
* %NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM - used in further EAP-RP exchanges
|
||||
* %NL80211_ATTR_PMKID - used to identify the PMKSA used/generated
|
||||
* %Nl80211_ATTR_PMK - used to update PMKSA cache in userspace
|
||||
* The PMKSA can be maintained in userspace persistently so that it can be used
|
||||
* later after reboots or wifi turn off/on also.
|
||||
*
|
||||
* %NL80211_ATTR_FILS_CACHE_ID is the cache identifier advertized by a FILS
|
||||
* capable AP supporting PMK caching. It specifies the scope within which the
|
||||
* PMKSAs are cached in an ESS. %NL80211_CMD_SET_PMKSA and
|
||||
* %NL80211_CMD_DEL_PMKSA are enhanced to allow support for PMKSA caching based
|
||||
* on FILS cache identifier. Additionally %NL80211_ATTR_PMK is used with
|
||||
* %NL80211_SET_PMKSA to specify the PMK corresponding to a PMKSA for driver to
|
||||
* use in a FILS shared key connection with PMKSA caching.
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum nl80211_commands - supported nl80211 commands
|
||||
*
|
||||
|
@ -370,10 +406,18 @@
|
|||
* @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
|
||||
* NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
|
||||
*
|
||||
* @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry, using %NL80211_ATTR_MAC
|
||||
* (for the BSSID) and %NL80211_ATTR_PMKID.
|
||||
* @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry using %NL80211_ATTR_MAC
|
||||
* (for the BSSID), %NL80211_ATTR_PMKID, and optionally %NL80211_ATTR_PMK
|
||||
* (PMK is used for PTKSA derivation in case of FILS shared key offload) or
|
||||
* using %NL80211_ATTR_SSID, %NL80211_ATTR_FILS_CACHE_ID,
|
||||
* %NL80211_ATTR_PMKID, and %NL80211_ATTR_PMK in case of FILS
|
||||
* authentication where %NL80211_ATTR_FILS_CACHE_ID is the identifier
|
||||
* advertized by a FILS capable AP identifying the scope of PMKSA in an
|
||||
* ESS.
|
||||
* @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC
|
||||
* (for the BSSID) and %NL80211_ATTR_PMKID.
|
||||
* (for the BSSID) and %NL80211_ATTR_PMKID or using %NL80211_ATTR_SSID,
|
||||
* %NL80211_ATTR_FILS_CACHE_ID, and %NL80211_ATTR_PMKID in case of FILS
|
||||
* authentication.
|
||||
* @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries.
|
||||
*
|
||||
* @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
|
||||
|
@ -2012,6 +2056,31 @@ enum nl80211_commands {
|
|||
* u32 attribute with an &enum nl80211_timeout_reason value. This is used,
|
||||
* e.g., with %NL80211_CMD_CONNECT event.
|
||||
*
|
||||
* @NL80211_ATTR_FILS_ERP_USERNAME: EAP Re-authentication Protocol (ERP)
|
||||
* username part of NAI used to refer keys rRK and rIK. This is used with
|
||||
* %NL80211_CMD_CONNECT.
|
||||
*
|
||||
* @NL80211_ATTR_FILS_ERP_REALM: EAP Re-authentication Protocol (ERP) realm part
|
||||
* of NAI specifying the domain name of the ER server. This is used with
|
||||
* %NL80211_CMD_CONNECT.
|
||||
*
|
||||
* @NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM: Unsigned 16-bit ERP next sequence number
|
||||
* to use in ERP messages. This is used in generating the FILS wrapped data
|
||||
* for FILS authentication and is used with %NL80211_CMD_CONNECT.
|
||||
*
|
||||
* @NL80211_ATTR_FILS_ERP_RRK: ERP re-authentication Root Key (rRK) for the
|
||||
* NAI specified by %NL80211_ATTR_FILS_ERP_USERNAME and
|
||||
* %NL80211_ATTR_FILS_ERP_REALM. This is used for generating rIK and rMSK
|
||||
* from successful FILS authentication and is used with
|
||||
* %NL80211_CMD_CONNECT.
|
||||
*
|
||||
* @NL80211_ATTR_FILS_CACHE_ID: A 2-octet identifier advertized by a FILS AP
|
||||
* identifying the scope of PMKSAs. This is used with
|
||||
* @NL80211_CMD_SET_PMKSA and @NL80211_CMD_DEL_PMKSA.
|
||||
*
|
||||
* @NL80211_ATTR_PMK: PMK for the PMKSA identified by %NL80211_ATTR_PMKID.
|
||||
* This is used with @NL80211_CMD_SET_PMKSA.
|
||||
*
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
|
@ -2423,6 +2492,14 @@ enum nl80211_attrs {
|
|||
|
||||
NL80211_ATTR_TIMEOUT_REASON,
|
||||
|
||||
NL80211_ATTR_FILS_ERP_USERNAME,
|
||||
NL80211_ATTR_FILS_ERP_REALM,
|
||||
NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
|
||||
NL80211_ATTR_FILS_ERP_RRK,
|
||||
NL80211_ATTR_FILS_CACHE_ID,
|
||||
|
||||
NL80211_ATTR_PMK,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
@ -3942,7 +4019,10 @@ enum nl80211_ps_state {
|
|||
* @__NL80211_ATTR_CQM_INVALID: invalid
|
||||
* @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies
|
||||
* the threshold for the RSSI level at which an event will be sent. Zero
|
||||
* to disable.
|
||||
* to disable. Alternatively, if %NL80211_EXT_FEATURE_CQM_RSSI_LIST is
|
||||
* set, multiple values can be supplied as a low-to-high sorted array of
|
||||
* threshold values in dBm. Events will be sent when the RSSI value
|
||||
* crosses any of the thresholds.
|
||||
* @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies
|
||||
* the minimum amount the RSSI level must change after an event before a
|
||||
* new event may be issued (to reduce effects of RSSI oscillation).
|
||||
|
@ -4753,6 +4833,11 @@ enum nl80211_feature_flags {
|
|||
* @NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI: The driver supports sched_scan
|
||||
* for reporting BSSs with better RSSI than the current connected BSS
|
||||
* (%NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI).
|
||||
* @NL80211_EXT_FEATURE_CQM_RSSI_LIST: With this driver the
|
||||
* %NL80211_ATTR_CQM_RSSI_THOLD attribute accepts a list of zero or more
|
||||
* RSSI threshold values to monitor rather than exactly one threshold.
|
||||
* @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD: Driver SME supports FILS shared key
|
||||
* authentication with %NL80211_CMD_CONNECT.
|
||||
*
|
||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||
|
@ -4771,6 +4856,8 @@ enum nl80211_ext_feature_index {
|
|||
NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA,
|
||||
NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED,
|
||||
NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI,
|
||||
NL80211_EXT_FEATURE_CQM_RSSI_LIST,
|
||||
NL80211_EXT_FEATURE_FILS_SK_OFFLOAD,
|
||||
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
|
@ -4906,12 +4993,17 @@ enum nl80211_smps_mode {
|
|||
* change to the channel status.
|
||||
* @NL80211_RADAR_NOP_FINISHED: The Non-Occupancy Period for this channel is
|
||||
* over, channel becomes usable.
|
||||
* @NL80211_RADAR_PRE_CAC_EXPIRED: Channel Availability Check done on this
|
||||
* non-operating channel is expired and no longer valid. New CAC must
|
||||
* be done on this channel before starting the operation. This is not
|
||||
* applicable for ETSI dfs domain where pre-CAC is valid for ever.
|
||||
*/
|
||||
enum nl80211_radar_event {
|
||||
NL80211_RADAR_DETECTED,
|
||||
NL80211_RADAR_CAC_FINISHED,
|
||||
NL80211_RADAR_CAC_ABORTED,
|
||||
NL80211_RADAR_NOP_FINISHED,
|
||||
NL80211_RADAR_PRE_CAC_EXPIRED,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -357,14 +357,14 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
|||
spin_lock_init(&tid_agg_rx->reorder_lock);
|
||||
|
||||
/* rx timer */
|
||||
tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired;
|
||||
tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
|
||||
init_timer_deferrable(&tid_agg_rx->session_timer);
|
||||
setup_deferrable_timer(&tid_agg_rx->session_timer,
|
||||
sta_rx_agg_session_timer_expired,
|
||||
(unsigned long)&sta->timer_to_tid[tid]);
|
||||
|
||||
/* rx reorder timer */
|
||||
tid_agg_rx->reorder_timer.function = sta_rx_agg_reorder_timer_expired;
|
||||
tid_agg_rx->reorder_timer.data = (unsigned long)&sta->timer_to_tid[tid];
|
||||
init_timer(&tid_agg_rx->reorder_timer);
|
||||
setup_timer(&tid_agg_rx->reorder_timer,
|
||||
sta_rx_agg_reorder_timer_expired,
|
||||
(unsigned long)&sta->timer_to_tid[tid]);
|
||||
|
||||
/* prepare reordering buffer */
|
||||
tid_agg_rx->reorder_buf =
|
||||
|
|
|
@ -670,14 +670,14 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
|
|||
tid_tx->timeout = timeout;
|
||||
|
||||
/* response timer */
|
||||
tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired;
|
||||
tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid];
|
||||
init_timer(&tid_tx->addba_resp_timer);
|
||||
setup_timer(&tid_tx->addba_resp_timer,
|
||||
sta_addba_resp_timer_expired,
|
||||
(unsigned long)&sta->timer_to_tid[tid]);
|
||||
|
||||
/* tx timer */
|
||||
tid_tx->session_timer.function = sta_tx_agg_session_timer_expired;
|
||||
tid_tx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
|
||||
init_timer_deferrable(&tid_tx->session_timer);
|
||||
setup_deferrable_timer(&tid_tx->session_timer,
|
||||
sta_tx_agg_session_timer_expired,
|
||||
(unsigned long)&sta->timer_to_tid[tid]);
|
||||
|
||||
/* assign a dialog token */
|
||||
sta->ampdu_mlme.dialog_token_allocator++;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015-2016 Intel Deutschland GmbH
|
||||
* Copyright (C) 2015-2017 Intel Deutschland GmbH
|
||||
*
|
||||
* This file is GPLv2 as found in COPYING.
|
||||
*/
|
||||
|
@ -22,11 +22,98 @@
|
|||
#include "mesh.h"
|
||||
#include "wme.h"
|
||||
|
||||
static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata,
|
||||
struct vif_params *params)
|
||||
{
|
||||
bool mu_mimo_groups = false;
|
||||
bool mu_mimo_follow = false;
|
||||
|
||||
if (params->vht_mumimo_groups) {
|
||||
u64 membership;
|
||||
|
||||
BUILD_BUG_ON(sizeof(membership) != WLAN_MEMBERSHIP_LEN);
|
||||
|
||||
memcpy(sdata->vif.bss_conf.mu_group.membership,
|
||||
params->vht_mumimo_groups, WLAN_MEMBERSHIP_LEN);
|
||||
memcpy(sdata->vif.bss_conf.mu_group.position,
|
||||
params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN,
|
||||
WLAN_USER_POSITION_LEN);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MU_GROUPS);
|
||||
/* don't care about endianness - just check for 0 */
|
||||
memcpy(&membership, params->vht_mumimo_groups,
|
||||
WLAN_MEMBERSHIP_LEN);
|
||||
mu_mimo_groups = membership != 0;
|
||||
}
|
||||
|
||||
if (params->vht_mumimo_follow_addr) {
|
||||
mu_mimo_follow =
|
||||
is_valid_ether_addr(params->vht_mumimo_follow_addr);
|
||||
ether_addr_copy(sdata->u.mntr.mu_follow_addr,
|
||||
params->vht_mumimo_follow_addr);
|
||||
}
|
||||
|
||||
sdata->vif.mu_mimo_owner = mu_mimo_groups || mu_mimo_follow;
|
||||
}
|
||||
|
||||
static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_sub_if_data *monitor_sdata;
|
||||
|
||||
/* check flags first */
|
||||
if (params->flags && ieee80211_sdata_running(sdata)) {
|
||||
u32 mask = MONITOR_FLAG_COOK_FRAMES | MONITOR_FLAG_ACTIVE;
|
||||
|
||||
/*
|
||||
* Prohibit MONITOR_FLAG_COOK_FRAMES and
|
||||
* MONITOR_FLAG_ACTIVE to be changed while the
|
||||
* interface is up.
|
||||
* Else we would need to add a lot of cruft
|
||||
* to update everything:
|
||||
* cooked_mntrs, monitor and all fif_* counters
|
||||
* reconfigure hardware
|
||||
*/
|
||||
if ((params->flags & mask) != (sdata->u.mntr.flags & mask))
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* also validate MU-MIMO change */
|
||||
monitor_sdata = rtnl_dereference(local->monitor_sdata);
|
||||
|
||||
if (!monitor_sdata &&
|
||||
(params->vht_mumimo_groups || params->vht_mumimo_follow_addr))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* apply all changes now - no failures allowed */
|
||||
|
||||
if (monitor_sdata)
|
||||
ieee80211_set_mu_mimo_follow(monitor_sdata, params);
|
||||
|
||||
if (params->flags) {
|
||||
if (ieee80211_sdata_running(sdata)) {
|
||||
ieee80211_adjust_monitor_flags(sdata, -1);
|
||||
sdata->u.mntr.flags = params->flags;
|
||||
ieee80211_adjust_monitor_flags(sdata, 1);
|
||||
|
||||
ieee80211_configure_filter(local);
|
||||
} else {
|
||||
/*
|
||||
* Because the interface is down, ieee80211_do_stop
|
||||
* and ieee80211_do_open take care of "everything"
|
||||
* mentioned in the comment above.
|
||||
*/
|
||||
sdata->u.mntr.flags = params->flags;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
|
||||
const char *name,
|
||||
unsigned char name_assign_type,
|
||||
enum nl80211_iftype type,
|
||||
u32 *flags,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||
|
@ -38,9 +125,14 @@ static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
|
|||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
if (type == NL80211_IFTYPE_MONITOR && flags) {
|
||||
sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
sdata->u.mntr.flags = *flags;
|
||||
sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
|
||||
if (type == NL80211_IFTYPE_MONITOR) {
|
||||
err = ieee80211_set_mon_options(sdata, params);
|
||||
if (err) {
|
||||
ieee80211_if_remove(sdata);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return wdev;
|
||||
|
@ -55,7 +147,7 @@ static int ieee80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
|
|||
|
||||
static int ieee80211_change_iface(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
@ -75,58 +167,9 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
|
|||
}
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_sub_if_data *monitor_sdata;
|
||||
u32 mu_mntr_cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
|
||||
|
||||
monitor_sdata = rtnl_dereference(local->monitor_sdata);
|
||||
if (monitor_sdata &&
|
||||
wiphy_ext_feature_isset(wiphy, mu_mntr_cap_flag)) {
|
||||
memcpy(monitor_sdata->vif.bss_conf.mu_group.membership,
|
||||
params->vht_mumimo_groups, WLAN_MEMBERSHIP_LEN);
|
||||
memcpy(monitor_sdata->vif.bss_conf.mu_group.position,
|
||||
params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN,
|
||||
WLAN_USER_POSITION_LEN);
|
||||
monitor_sdata->vif.mu_mimo_owner = true;
|
||||
ieee80211_bss_info_change_notify(monitor_sdata,
|
||||
BSS_CHANGED_MU_GROUPS);
|
||||
|
||||
ether_addr_copy(monitor_sdata->u.mntr.mu_follow_addr,
|
||||
params->macaddr);
|
||||
}
|
||||
|
||||
if (!flags)
|
||||
return 0;
|
||||
|
||||
if (ieee80211_sdata_running(sdata)) {
|
||||
u32 mask = MONITOR_FLAG_COOK_FRAMES |
|
||||
MONITOR_FLAG_ACTIVE;
|
||||
|
||||
/*
|
||||
* Prohibit MONITOR_FLAG_COOK_FRAMES and
|
||||
* MONITOR_FLAG_ACTIVE to be changed while the
|
||||
* interface is up.
|
||||
* Else we would need to add a lot of cruft
|
||||
* to update everything:
|
||||
* cooked_mntrs, monitor and all fif_* counters
|
||||
* reconfigure hardware
|
||||
*/
|
||||
if ((*flags & mask) != (sdata->u.mntr.flags & mask))
|
||||
return -EBUSY;
|
||||
|
||||
ieee80211_adjust_monitor_flags(sdata, -1);
|
||||
sdata->u.mntr.flags = *flags;
|
||||
ieee80211_adjust_monitor_flags(sdata, 1);
|
||||
|
||||
ieee80211_configure_filter(local);
|
||||
} else {
|
||||
/*
|
||||
* Because the interface is down, ieee80211_do_stop
|
||||
* and ieee80211_do_open take care of "everything"
|
||||
* mentioned in the comment above.
|
||||
*/
|
||||
sdata->u.mntr.flags = *flags;
|
||||
}
|
||||
ret = ieee80211_set_mon_options(sdata, params);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2042,6 +2085,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
|
|||
params->basic_rates_len,
|
||||
&sdata->vif.bss_conf.basic_rates);
|
||||
changed |= BSS_CHANGED_BASIC_RATES;
|
||||
ieee80211_check_rate_mask(sdata);
|
||||
}
|
||||
|
||||
if (params->ap_isolate >= 0) {
|
||||
|
@ -2630,6 +2674,33 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
|
|||
|
||||
bss_conf->cqm_rssi_thold = rssi_thold;
|
||||
bss_conf->cqm_rssi_hyst = rssi_hyst;
|
||||
bss_conf->cqm_rssi_low = 0;
|
||||
bss_conf->cqm_rssi_high = 0;
|
||||
sdata->u.mgd.last_cqm_event_signal = 0;
|
||||
|
||||
/* tell the driver upon association, unless already associated */
|
||||
if (sdata->u.mgd.associated &&
|
||||
sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
s32 rssi_low, s32 rssi_high)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_vif *vif = &sdata->vif;
|
||||
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||
|
||||
if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
bss_conf->cqm_rssi_low = rssi_low;
|
||||
bss_conf->cqm_rssi_high = rssi_high;
|
||||
bss_conf->cqm_rssi_thold = 0;
|
||||
bss_conf->cqm_rssi_hyst = 0;
|
||||
sdata->u.mgd.last_cqm_event_signal = 0;
|
||||
|
||||
/* tell the driver upon association, unless already associated */
|
||||
|
@ -2658,6 +2729,21 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* If active validate the setting and reject it if it doesn't leave
|
||||
* at least one basic rate usable, since we really have to be able
|
||||
* to send something, and if we're an AP we have to be able to do
|
||||
* so at a basic rate so that all clients can receive it.
|
||||
*/
|
||||
if (rcu_access_pointer(sdata->vif.chanctx_conf) &&
|
||||
sdata->vif.bss_conf.chandef.chan) {
|
||||
u32 basic_rates = sdata->vif.bss_conf.basic_rates;
|
||||
enum nl80211_band band = sdata->vif.bss_conf.chandef.chan->band;
|
||||
|
||||
if (!(mask->control[band].legacy & basic_rates))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_NL80211_BANDS; i++) {
|
||||
struct ieee80211_supported_band *sband = wiphy->bands[i];
|
||||
int j;
|
||||
|
@ -3639,6 +3725,7 @@ const struct cfg80211_ops mac80211_config_ops = {
|
|||
.mgmt_tx = ieee80211_mgmt_tx,
|
||||
.mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,
|
||||
.set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
|
||||
.set_cqm_rssi_range_config = ieee80211_set_cqm_rssi_range_config,
|
||||
.mgmt_frame_register = ieee80211_mgmt_frame_register,
|
||||
.set_antenna = ieee80211_set_antenna,
|
||||
.get_antenna = ieee80211_get_antenna,
|
||||
|
|
|
@ -425,7 +425,7 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
case NL80211_CHAN_WIDTH_5:
|
||||
case NL80211_CHAN_WIDTH_10:
|
||||
cfg80211_chandef_create(&chandef, cbss->channel,
|
||||
NL80211_CHAN_WIDTH_20_NOHT);
|
||||
NL80211_CHAN_NO_HT);
|
||||
chandef.width = sdata->u.ibss.chandef.width;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_80:
|
||||
|
@ -437,7 +437,7 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
default:
|
||||
/* fall back to 20 MHz for unsupported modes */
|
||||
cfg80211_chandef_create(&chandef, cbss->channel,
|
||||
NL80211_CHAN_WIDTH_20_NOHT);
|
||||
NL80211_CHAN_NO_HT);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -839,6 +839,8 @@ struct txq_info {
|
|||
struct ieee80211_if_mntr {
|
||||
u32 flags;
|
||||
u8 mu_follow_addr[ETH_ALEN] __aligned(2);
|
||||
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1259,6 +1261,7 @@ struct ieee80211_local {
|
|||
|
||||
/* see iface.c */
|
||||
struct list_head interfaces;
|
||||
struct list_head mon_list; /* only that are IFF_UP && !cooked */
|
||||
struct mutex iflist_mtx;
|
||||
|
||||
/*
|
||||
|
|
|
@ -676,7 +676,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
|||
|
||||
set_bit(SDATA_STATE_RUNNING, &sdata->state);
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_WDS) {
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_WDS:
|
||||
/* Create STA entry for the WDS peer */
|
||||
sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
|
||||
GFP_KERNEL);
|
||||
|
@ -697,8 +698,17 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
|||
|
||||
rate_control_rate_init(sta);
|
||||
netif_carrier_on(dev);
|
||||
} else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) {
|
||||
break;
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
rcu_assign_pointer(local->p2p_sdata, sdata);
|
||||
break;
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)
|
||||
break;
|
||||
list_add_tail_rcu(&sdata->u.mntr.list, &local->mon_list);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -817,6 +827,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
|||
case NL80211_IFTYPE_AP:
|
||||
cancel_work_sync(&sdata->u.ap.request_smps_work);
|
||||
break;
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)
|
||||
break;
|
||||
list_del_rcu(&sdata->u.mntr.list);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -603,6 +603,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
|
|||
ARRAY_SIZE(local->ext_capa);
|
||||
|
||||
INIT_LIST_HEAD(&local->interfaces);
|
||||
INIT_LIST_HEAD(&local->mon_list);
|
||||
|
||||
__hw_addr_init(&local->mc_list);
|
||||
|
||||
|
|
|
@ -1100,8 +1100,14 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
|
|||
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
|
||||
return;
|
||||
|
||||
if (mesh_matches_local(sdata, &elems))
|
||||
mesh_neighbour_update(sdata, mgmt->sa, &elems);
|
||||
if (mesh_matches_local(sdata, &elems)) {
|
||||
mpl_dbg(sdata, "rssi_threshold=%d,rx_status->signal=%d\n",
|
||||
sdata->u.mesh.mshcfg.rssi_threshold, rx_status->signal);
|
||||
if (!sdata->u.mesh.user_mpm ||
|
||||
sdata->u.mesh.mshcfg.rssi_threshold == 0 ||
|
||||
sdata->u.mesh.mshcfg.rssi_threshold < rx_status->signal)
|
||||
mesh_neighbour_update(sdata, mgmt->sa, &elems);
|
||||
}
|
||||
|
||||
if (ifmsh->sync_ops)
|
||||
ifmsh->sync_ops->rx_bcn_presp(sdata,
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define TEST_FRAME_LEN 8192
|
||||
#define MAX_METRIC 0xffffffff
|
||||
#define ARITH_SHIFT 8
|
||||
#define LINK_FAIL_THRESH 95
|
||||
|
||||
#define MAX_PREQ_QUEUE_LEN 64
|
||||
|
||||
|
@ -307,10 +308,12 @@ void ieee80211s_update_metric(struct ieee80211_local *local,
|
|||
|
||||
failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK);
|
||||
|
||||
/* moving average, scaled to 100 */
|
||||
sta->mesh->fail_avg =
|
||||
((80 * sta->mesh->fail_avg + 5) / 100 + 20 * failed);
|
||||
if (sta->mesh->fail_avg > 95)
|
||||
/* moving average, scaled to 100.
|
||||
* feed failure as 100 and success as 0
|
||||
*/
|
||||
ewma_mesh_fail_avg_add(&sta->mesh->fail_avg, failed * 100);
|
||||
if (ewma_mesh_fail_avg_read(&sta->mesh->fail_avg) >
|
||||
LINK_FAIL_THRESH)
|
||||
mesh_plink_broken(sta);
|
||||
}
|
||||
|
||||
|
@ -325,6 +328,8 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local,
|
|||
int rate, err;
|
||||
u32 tx_time, estimated_retx;
|
||||
u64 result;
|
||||
unsigned long fail_avg =
|
||||
ewma_mesh_fail_avg_read(&sta->mesh->fail_avg);
|
||||
|
||||
/* Try to get rate based on HW/SW RC algorithm.
|
||||
* Rate is returned in units of Kbps, correct this
|
||||
|
@ -336,7 +341,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local,
|
|||
if (rate) {
|
||||
err = 0;
|
||||
} else {
|
||||
if (sta->mesh->fail_avg >= 100)
|
||||
if (fail_avg > LINK_FAIL_THRESH)
|
||||
return MAX_METRIC;
|
||||
|
||||
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,
|
|||
if (WARN_ON(!rate))
|
||||
return MAX_METRIC;
|
||||
|
||||
err = (sta->mesh->fail_avg << ARITH_SHIFT) / 100;
|
||||
err = (fail_avg << ARITH_SHIFT) / 100;
|
||||
}
|
||||
|
||||
/* 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,
|
|||
? mpath->exp_time : exp_time;
|
||||
mesh_path_activate(mpath);
|
||||
spin_unlock_bh(&mpath->state_lock);
|
||||
ewma_mesh_fail_avg_init(&sta->mesh->fail_avg);
|
||||
/* init it at a low value - 0 start is tricky */
|
||||
ewma_mesh_fail_avg_add(&sta->mesh->fail_avg, 1);
|
||||
mesh_path_tx_pending(mpath);
|
||||
/* draft says preq_id should be saved to, but there does
|
||||
* 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,
|
|||
? mpath->exp_time : exp_time;
|
||||
mesh_path_activate(mpath);
|
||||
spin_unlock_bh(&mpath->state_lock);
|
||||
ewma_mesh_fail_avg_init(&sta->mesh->fail_avg);
|
||||
/* init it at a low value - 0 start is tricky */
|
||||
ewma_mesh_fail_avg_add(&sta->mesh->fail_avg, 1);
|
||||
mesh_path_tx_pending(mpath);
|
||||
} else
|
||||
spin_unlock_bh(&mpath->state_lock);
|
||||
|
|
|
@ -397,11 +397,10 @@ struct mesh_path *mesh_path_new(struct ieee80211_sub_if_data *sdata,
|
|||
new_mpath->sdata = sdata;
|
||||
new_mpath->flags = 0;
|
||||
skb_queue_head_init(&new_mpath->frame_queue);
|
||||
new_mpath->timer.data = (unsigned long) new_mpath;
|
||||
new_mpath->timer.function = mesh_path_timer;
|
||||
new_mpath->exp_time = jiffies;
|
||||
spin_lock_init(&new_mpath->state_lock);
|
||||
init_timer(&new_mpath->timer);
|
||||
setup_timer(&new_mpath->timer, mesh_path_timer,
|
||||
(unsigned long) new_mpath);
|
||||
|
||||
return new_mpath;
|
||||
}
|
||||
|
@ -829,6 +828,9 @@ void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop)
|
|||
mpath->flags = MESH_PATH_FIXED | MESH_PATH_SN_VALID;
|
||||
mesh_path_activate(mpath);
|
||||
spin_unlock_bh(&mpath->state_lock);
|
||||
ewma_mesh_fail_avg_init(&next_hop->mesh->fail_avg);
|
||||
/* init it at a low value - 0 start is tricky */
|
||||
ewma_mesh_fail_avg_add(&next_hop->mesh->fail_avg, 1);
|
||||
mesh_path_tx_pending(mpath);
|
||||
}
|
||||
|
||||
|
|
|
@ -1908,6 +1908,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
|
|||
sdata->u.mgd.associated = cbss;
|
||||
memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN);
|
||||
|
||||
ieee80211_check_rate_mask(sdata);
|
||||
|
||||
sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;
|
||||
|
||||
if (sdata->vif.p2p ||
|
||||
|
@ -2797,8 +2799,9 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
|
||||
|
||||
sdata_info(sdata, "disassociated from %pM (Reason: %u)\n",
|
||||
mgmt->sa, reason_code);
|
||||
sdata_info(sdata, "disassociated from %pM (Reason: %u=%s)\n",
|
||||
mgmt->sa, reason_code,
|
||||
ieee80211_get_reason_code_string(reason_code));
|
||||
|
||||
ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
|
||||
|
||||
|
@ -2822,15 +2825,15 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
|
|||
*have_higher_than_11mbit = true;
|
||||
|
||||
/*
|
||||
* BSS_MEMBERSHIP_SELECTOR_HT_PHY is defined in 802.11n-2009
|
||||
* 7.3.2.2 as a magic value instead of a rate. Hence, skip it.
|
||||
* Skip HT and VHT BSS membership selectors since they're not
|
||||
* rates.
|
||||
*
|
||||
* Note: Even through the membership selector and the basic
|
||||
* Note: Even though the membership selector and the basic
|
||||
* rate flag share the same bit, they are not exactly
|
||||
* the same.
|
||||
*/
|
||||
if (!!(supp_rates[i] & 0x80) &&
|
||||
(supp_rates[i] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
|
||||
if (supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY) ||
|
||||
supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY))
|
||||
continue;
|
||||
|
||||
for (j = 0; j < sband->n_bitrates; j++) {
|
||||
|
@ -3430,6 +3433,30 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
}
|
||||
|
||||
if (bss_conf->cqm_rssi_low &&
|
||||
ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
|
||||
int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
|
||||
int last_event = ifmgd->last_cqm_event_signal;
|
||||
int low = bss_conf->cqm_rssi_low;
|
||||
int high = bss_conf->cqm_rssi_high;
|
||||
|
||||
if (sig < low &&
|
||||
(last_event == 0 || last_event >= low)) {
|
||||
ifmgd->last_cqm_event_signal = sig;
|
||||
ieee80211_cqm_rssi_notify(
|
||||
&sdata->vif,
|
||||
NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
|
||||
sig, GFP_KERNEL);
|
||||
} else if (sig > high &&
|
||||
(last_event == 0 || last_event <= high)) {
|
||||
ifmgd->last_cqm_event_signal = sig;
|
||||
ieee80211_cqm_rssi_notify(
|
||||
&sdata->vif,
|
||||
NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
|
||||
sig, GFP_KERNEL);
|
||||
}
|
||||
}
|
||||
|
||||
if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) {
|
||||
mlme_dbg_ratelimited(sdata,
|
||||
"cancelling AP probe due to a received beacon\n");
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Copyright 2002-2005, Instant802 Networks, Inc.
|
||||
* Copyright 2005-2006, Devicescape Software, Inc.
|
||||
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2017 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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)
|
|||
/* try default if specific alg requested but not found */
|
||||
ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo);
|
||||
|
||||
/* try built-in one if specific alg requested but not found */
|
||||
if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT))
|
||||
/* Note: check for > 0 is intentional to avoid clang warning */
|
||||
if (!ops && (strlen(CONFIG_MAC80211_RC_DEFAULT) > 0))
|
||||
/* try built-in one if specific alg requested but not found */
|
||||
ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT);
|
||||
|
||||
kernel_param_unlock(THIS_MODULE);
|
||||
|
||||
return ops;
|
||||
|
@ -208,7 +211,6 @@ static struct rate_control_ref *rate_control_alloc(const char *name,
|
|||
ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL);
|
||||
if (!ref)
|
||||
return NULL;
|
||||
ref->local = local;
|
||||
ref->ops = ieee80211_rate_control_ops_get(name);
|
||||
if (!ref->ops)
|
||||
goto free;
|
||||
|
@ -229,18 +231,45 @@ static struct rate_control_ref *rate_control_alloc(const char *name,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void rate_control_free(struct rate_control_ref *ctrl_ref)
|
||||
static void rate_control_free(struct ieee80211_local *local,
|
||||
struct rate_control_ref *ctrl_ref)
|
||||
{
|
||||
ctrl_ref->ops->free(ctrl_ref->priv);
|
||||
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
debugfs_remove_recursive(ctrl_ref->local->debugfs.rcdir);
|
||||
ctrl_ref->local->debugfs.rcdir = NULL;
|
||||
debugfs_remove_recursive(local->debugfs.rcdir);
|
||||
local->debugfs.rcdir = NULL;
|
||||
#endif
|
||||
|
||||
kfree(ctrl_ref);
|
||||
}
|
||||
|
||||
void ieee80211_check_rate_mask(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_supported_band *sband;
|
||||
u32 user_mask, basic_rates = sdata->vif.bss_conf.basic_rates;
|
||||
enum nl80211_band band;
|
||||
|
||||
if (WARN_ON(!sdata->vif.bss_conf.chandef.chan))
|
||||
return;
|
||||
|
||||
if (WARN_ON_ONCE(!basic_rates))
|
||||
return;
|
||||
|
||||
band = sdata->vif.bss_conf.chandef.chan->band;
|
||||
user_mask = sdata->rc_rateidx_mask[band];
|
||||
sband = local->hw.wiphy->bands[band];
|
||||
|
||||
if (user_mask & basic_rates)
|
||||
return;
|
||||
|
||||
sdata_dbg(sdata,
|
||||
"no overlap between basic rates (0x%x) and user mask (0x%x on band %d) - clearing the latter",
|
||||
basic_rates, user_mask, band);
|
||||
sdata->rc_rateidx_mask[band] = (1 << sband->n_bitrates) - 1;
|
||||
}
|
||||
|
||||
static bool rc_no_data_or_no_ack_use_min(struct ieee80211_tx_rate_control *txrc)
|
||||
{
|
||||
struct sk_buff *skb = txrc->skb;
|
||||
|
@ -936,6 +965,6 @@ void rate_control_deinitialize(struct ieee80211_local *local)
|
|||
return;
|
||||
|
||||
local->rate_ctrl = NULL;
|
||||
rate_control_free(ref);
|
||||
rate_control_free(local, ref);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "driver-ops.h"
|
||||
|
||||
struct rate_control_ref {
|
||||
struct ieee80211_local *local;
|
||||
const struct rate_control_ops *ops;
|
||||
void *priv;
|
||||
};
|
||||
|
@ -111,6 +110,8 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta)
|
|||
#endif
|
||||
}
|
||||
|
||||
void ieee80211_check_rate_mask(struct ieee80211_sub_if_data *sdata);
|
||||
|
||||
/* Get a reference to the rate control algorithm. If `name' is NULL, get the
|
||||
* first available algorithm. */
|
||||
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,
|
|||
* This function cleans up the SKB, i.e. it removes all the stuff
|
||||
* only useful for monitoring.
|
||||
*/
|
||||
static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
|
||||
struct sk_buff *skb,
|
||||
unsigned int rtap_vendor_space)
|
||||
static void remove_monitor_info(struct sk_buff *skb,
|
||||
unsigned int present_fcs_len,
|
||||
unsigned int rtap_vendor_space)
|
||||
{
|
||||
if (ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)) {
|
||||
if (likely(skb->len > FCS_LEN))
|
||||
__pskb_trim(skb, skb->len - FCS_LEN);
|
||||
else {
|
||||
/* driver bug */
|
||||
WARN_ON(1);
|
||||
dev_kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (present_fcs_len)
|
||||
__pskb_trim(skb, skb->len - present_fcs_len);
|
||||
__pskb_pull(skb, rtap_vendor_space);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
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,
|
|||
* the SKB because it has a bad FCS/PLCP checksum.
|
||||
*/
|
||||
|
||||
if (ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS))
|
||||
if (ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)) {
|
||||
if (unlikely(origskb->len <= FCS_LEN)) {
|
||||
/* driver bug */
|
||||
WARN_ON(1);
|
||||
dev_kfree_skb(origskb);
|
||||
return NULL;
|
||||
}
|
||||
present_fcs_len = FCS_LEN;
|
||||
}
|
||||
|
||||
/* ensure hdr->frame_control and vendor radiotap data are in skb head */
|
||||
if (!pskb_may_pull(origskb, 2 + rtap_vendor_space)) {
|
||||
|
@ -550,7 +546,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return remove_monitor_info(local, origskb, rtap_vendor_space);
|
||||
remove_monitor_info(origskb, present_fcs_len,
|
||||
rtap_vendor_space);
|
||||
return origskb;
|
||||
}
|
||||
|
||||
/* room for the radiotap header based on driver features */
|
||||
|
@ -580,9 +578,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
|
|||
* and FCS from the original.
|
||||
*/
|
||||
skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC);
|
||||
|
||||
origskb = remove_monitor_info(local, origskb,
|
||||
rtap_vendor_space);
|
||||
remove_monitor_info(origskb, present_fcs_len,
|
||||
rtap_vendor_space);
|
||||
|
||||
if (!skb)
|
||||
return origskb;
|
||||
|
@ -596,16 +593,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
|
|||
skb->pkt_type = PACKET_OTHERHOST;
|
||||
skb->protocol = htons(ETH_P_802_2);
|
||||
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
|
||||
continue;
|
||||
|
||||
if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)
|
||||
continue;
|
||||
|
||||
if (!ieee80211_sdata_running(sdata))
|
||||
continue;
|
||||
|
||||
list_for_each_entry_rcu(sdata, &local->mon_list, u.mntr.list) {
|
||||
if (prev_dev) {
|
||||
skb2 = skb_clone(skb, GFP_ATOMIC);
|
||||
if (skb2) {
|
||||
|
|
|
@ -132,9 +132,9 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_vht_operation vht_oper = {
|
||||
.chan_width =
|
||||
wide_bw_chansw_ie->new_channel_width,
|
||||
.center_freq_seg1_idx =
|
||||
.center_freq_seg0_idx =
|
||||
wide_bw_chansw_ie->new_center_freq_seg0,
|
||||
.center_freq_seg2_idx =
|
||||
.center_freq_seg1_idx =
|
||||
wide_bw_chansw_ie->new_center_freq_seg1,
|
||||
/* .basic_mcs_set doesn't matter */
|
||||
};
|
||||
|
|
|
@ -1960,14 +1960,17 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate,
|
|||
rinfo->bw = (rate & STA_STATS_RATE_BW_MASK) >>
|
||||
STA_STATS_RATE_BW_SHIFT;
|
||||
|
||||
if (rate & STA_STATS_RATE_VHT) {
|
||||
switch (rate & STA_STATS_RATE_TYPE_MASK) {
|
||||
case STA_STATS_RATE_TYPE_VHT:
|
||||
rinfo->flags = RATE_INFO_FLAGS_VHT_MCS;
|
||||
rinfo->mcs = rate & 0xf;
|
||||
rinfo->nss = (rate & 0xf0) >> 4;
|
||||
} else if (rate & STA_STATS_RATE_HT) {
|
||||
break;
|
||||
case STA_STATS_RATE_TYPE_HT:
|
||||
rinfo->flags = RATE_INFO_FLAGS_MCS;
|
||||
rinfo->mcs = rate & 0xff;
|
||||
} else if (rate & STA_STATS_RATE_LEGACY) {
|
||||
break;
|
||||
case STA_STATS_RATE_TYPE_LEGACY: {
|
||||
struct ieee80211_supported_band *sband;
|
||||
u16 brate;
|
||||
unsigned int shift;
|
||||
|
@ -1982,6 +1985,8 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u16 rate,
|
|||
else
|
||||
shift = 0;
|
||||
rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rate & STA_STATS_RATE_SGI)
|
||||
|
|
|
@ -324,6 +324,9 @@ struct ieee80211_fast_rx {
|
|||
struct rcu_head rcu_head;
|
||||
};
|
||||
|
||||
/* we use only values in the range 0-100, so pick a large precision */
|
||||
DECLARE_EWMA(mesh_fail_avg, 20, 8)
|
||||
|
||||
/**
|
||||
* struct mesh_sta - mesh STA information
|
||||
* @plink_lock: serialize access to plink fields
|
||||
|
@ -369,7 +372,7 @@ struct mesh_sta {
|
|||
enum nl80211_mesh_power_mode nonpeer_pm;
|
||||
|
||||
/* moving percentage of failed MSDUs */
|
||||
unsigned int fail_avg;
|
||||
struct ewma_mesh_fail_avg fail_avg;
|
||||
};
|
||||
|
||||
DECLARE_EWMA(signal, 10, 8)
|
||||
|
@ -725,9 +728,10 @@ void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta);
|
|||
unsigned long ieee80211_sta_last_active(struct sta_info *sta);
|
||||
|
||||
#define STA_STATS_RATE_INVALID 0
|
||||
#define STA_STATS_RATE_VHT 0x8000
|
||||
#define STA_STATS_RATE_HT 0x4000
|
||||
#define STA_STATS_RATE_LEGACY 0x2000
|
||||
#define STA_STATS_RATE_TYPE_MASK 0xC000
|
||||
#define STA_STATS_RATE_TYPE_LEGACY 0x4000
|
||||
#define STA_STATS_RATE_TYPE_HT 0x8000
|
||||
#define STA_STATS_RATE_TYPE_VHT 0xC000
|
||||
#define STA_STATS_RATE_SGI 0x1000
|
||||
#define STA_STATS_RATE_BW_SHIFT 9
|
||||
#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)
|
|||
r |= STA_STATS_RATE_SGI;
|
||||
|
||||
if (s->flag & RX_FLAG_VHT)
|
||||
r |= STA_STATS_RATE_VHT | (s->vht_nss << 4);
|
||||
r |= STA_STATS_RATE_TYPE_VHT | (s->vht_nss << 4);
|
||||
else if (s->flag & RX_FLAG_HT)
|
||||
r |= STA_STATS_RATE_HT;
|
||||
r |= STA_STATS_RATE_TYPE_HT;
|
||||
else
|
||||
r |= STA_STATS_RATE_LEGACY | (s->band << 4);
|
||||
r |= STA_STATS_RATE_TYPE_LEGACY | (s->band << 4);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -682,10 +682,6 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
|
|||
txrc.skb = tx->skb;
|
||||
txrc.reported_rate.idx = -1;
|
||||
txrc.rate_idx_mask = tx->sdata->rc_rateidx_mask[info->band];
|
||||
if (txrc.rate_idx_mask == (1 << sband->n_bitrates) - 1)
|
||||
txrc.max_rate_idx = -1;
|
||||
else
|
||||
txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
|
||||
|
||||
if (tx->sdata->rc_has_mcs_mask[info->band])
|
||||
txrc.rate_idx_mcs_mask =
|
||||
|
@ -4249,10 +4245,6 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw,
|
|||
txrc.skb = skb;
|
||||
txrc.reported_rate.idx = -1;
|
||||
txrc.rate_idx_mask = sdata->rc_rateidx_mask[band];
|
||||
if (txrc.rate_idx_mask == (1 << txrc.sband->n_bitrates) - 1)
|
||||
txrc.max_rate_idx = -1;
|
||||
else
|
||||
txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
|
||||
txrc.bss = true;
|
||||
rate_control_get_rate(sdata, NULL, &txrc);
|
||||
|
||||
|
|
|
@ -2413,13 +2413,13 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
|||
*pos++ = WLAN_EID_VHT_OPERATION;
|
||||
*pos++ = sizeof(struct ieee80211_vht_operation);
|
||||
vht_oper = (struct ieee80211_vht_operation *)pos;
|
||||
vht_oper->center_freq_seg1_idx = ieee80211_frequency_to_channel(
|
||||
vht_oper->center_freq_seg0_idx = ieee80211_frequency_to_channel(
|
||||
chandef->center_freq1);
|
||||
if (chandef->center_freq2)
|
||||
vht_oper->center_freq_seg2_idx =
|
||||
vht_oper->center_freq_seg1_idx =
|
||||
ieee80211_frequency_to_channel(chandef->center_freq2);
|
||||
else
|
||||
vht_oper->center_freq_seg2_idx = 0x00;
|
||||
vht_oper->center_freq_seg1_idx = 0x00;
|
||||
|
||||
switch (chandef->width) {
|
||||
case NL80211_CHAN_WIDTH_160:
|
||||
|
@ -2428,11 +2428,11 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
|||
* workaround.
|
||||
*/
|
||||
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
|
||||
vht_oper->center_freq_seg2_idx = vht_oper->center_freq_seg1_idx;
|
||||
vht_oper->center_freq_seg1_idx = vht_oper->center_freq_seg0_idx;
|
||||
if (chandef->chan->center_freq < chandef->center_freq1)
|
||||
vht_oper->center_freq_seg1_idx -= 8;
|
||||
vht_oper->center_freq_seg0_idx -= 8;
|
||||
else
|
||||
vht_oper->center_freq_seg1_idx += 8;
|
||||
vht_oper->center_freq_seg0_idx += 8;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_80P80:
|
||||
/*
|
||||
|
@ -2491,9 +2491,9 @@ bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
|
|||
if (!oper)
|
||||
return false;
|
||||
|
||||
cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
|
||||
cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg0_idx,
|
||||
chandef->chan->band);
|
||||
cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg2_idx,
|
||||
cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
|
||||
chandef->chan->band);
|
||||
|
||||
switch (oper->chan_width) {
|
||||
|
@ -2503,11 +2503,11 @@ bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
|
|||
new.width = NL80211_CHAN_WIDTH_80;
|
||||
new.center_freq1 = cf1;
|
||||
/* If needed, adjust based on the newer interop workaround. */
|
||||
if (oper->center_freq_seg2_idx) {
|
||||
if (oper->center_freq_seg1_idx) {
|
||||
unsigned int diff;
|
||||
|
||||
diff = abs(oper->center_freq_seg2_idx -
|
||||
oper->center_freq_seg1_idx);
|
||||
diff = abs(oper->center_freq_seg1_idx -
|
||||
oper->center_freq_seg0_idx);
|
||||
if (diff == 8) {
|
||||
new.width = NL80211_CHAN_WIDTH_160;
|
||||
new.center_freq1 = cf2;
|
||||
|
|
|
@ -32,6 +32,11 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
|||
rdev_set_qos_map(rdev, dev, NULL);
|
||||
if (notify)
|
||||
nl80211_send_ap_stopped(wdev);
|
||||
|
||||
/* Should we apply the grace period during beaconing interface
|
||||
* shutdown also?
|
||||
*/
|
||||
cfg80211_sched_dfs_chan_update(rdev);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
|
@ -456,6 +456,123 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
|
|||
return (r1 + r2 > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if center frequency of chan falls with in the bandwidth
|
||||
* range of chandef.
|
||||
*/
|
||||
bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef,
|
||||
struct ieee80211_channel *chan)
|
||||
{
|
||||
int width;
|
||||
u32 cf_offset, freq;
|
||||
|
||||
if (chandef->chan->center_freq == chan->center_freq)
|
||||
return true;
|
||||
|
||||
width = cfg80211_chandef_get_width(chandef);
|
||||
if (width <= 20)
|
||||
return false;
|
||||
|
||||
cf_offset = width / 2 - 10;
|
||||
|
||||
for (freq = chandef->center_freq1 - width / 2 + 10;
|
||||
freq <= chandef->center_freq1 + width / 2 - 10; freq += 20) {
|
||||
if (chan->center_freq == freq)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!chandef->center_freq2)
|
||||
return false;
|
||||
|
||||
for (freq = chandef->center_freq2 - width / 2 + 10;
|
||||
freq <= chandef->center_freq2 + width / 2 - 10; freq += 20) {
|
||||
if (chan->center_freq == freq)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
|
||||
{
|
||||
bool active = false;
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (!wdev->chandef.chan)
|
||||
return false;
|
||||
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
active = wdev->beacon_interval != 0;
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
active = wdev->ssid_len != 0;
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
active = wdev->mesh_id_len != 0;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_OCB:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
/* Can NAN type be considered as beaconing interface? */
|
||||
case NL80211_IFTYPE_NAN:
|
||||
break;
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
case NUM_NL80211_IFTYPES:
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
return active;
|
||||
}
|
||||
|
||||
static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *chan)
|
||||
{
|
||||
struct wireless_dev *wdev;
|
||||
|
||||
list_for_each_entry(wdev, &wiphy->wdev_list, list) {
|
||||
wdev_lock(wdev);
|
||||
if (!cfg80211_beaconing_iface_active(wdev)) {
|
||||
wdev_unlock(wdev);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cfg80211_is_sub_chan(&wdev->chandef, chan)) {
|
||||
wdev_unlock(wdev);
|
||||
return true;
|
||||
}
|
||||
wdev_unlock(wdev);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *chan)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (!(chan->flags & IEEE80211_CHAN_RADAR))
|
||||
return false;
|
||||
|
||||
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
|
||||
if (!reg_dfs_domain_same(wiphy, &rdev->wiphy))
|
||||
continue;
|
||||
|
||||
if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
|
||||
u32 center_freq,
|
||||
|
|
|
@ -357,6 +357,38 @@ static void cfg80211_sched_scan_stop_wk(struct work_struct *work)
|
|||
rtnl_unlock();
|
||||
}
|
||||
|
||||
static void cfg80211_propagate_radar_detect_wk(struct work_struct *work)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
|
||||
rdev = container_of(work, struct cfg80211_registered_device,
|
||||
propagate_radar_detect_wk);
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
regulatory_propagate_dfs_state(&rdev->wiphy, &rdev->radar_chandef,
|
||||
NL80211_DFS_UNAVAILABLE,
|
||||
NL80211_RADAR_DETECTED);
|
||||
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
static void cfg80211_propagate_cac_done_wk(struct work_struct *work)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
|
||||
rdev = container_of(work, struct cfg80211_registered_device,
|
||||
propagate_cac_done_wk);
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
regulatory_propagate_dfs_state(&rdev->wiphy, &rdev->cac_done_chandef,
|
||||
NL80211_DFS_AVAILABLE,
|
||||
NL80211_RADAR_CAC_FINISHED);
|
||||
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
/* exported functions */
|
||||
|
||||
struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
|
||||
|
@ -456,6 +488,9 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
|
|||
spin_lock_init(&rdev->destroy_list_lock);
|
||||
INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk);
|
||||
INIT_WORK(&rdev->sched_scan_stop_wk, cfg80211_sched_scan_stop_wk);
|
||||
INIT_WORK(&rdev->propagate_radar_detect_wk,
|
||||
cfg80211_propagate_radar_detect_wk);
|
||||
INIT_WORK(&rdev->propagate_cac_done_wk, cfg80211_propagate_cac_done_wk);
|
||||
|
||||
#ifdef CONFIG_CFG80211_DEFAULT_PS
|
||||
rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
|
||||
|
@ -915,6 +950,8 @@ void wiphy_unregister(struct wiphy *wiphy)
|
|||
flush_work(&rdev->destroy_work);
|
||||
flush_work(&rdev->sched_scan_stop_wk);
|
||||
flush_work(&rdev->mlme_unreg_wk);
|
||||
flush_work(&rdev->propagate_radar_detect_wk);
|
||||
flush_work(&rdev->propagate_cac_done_wk);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
|
||||
|
@ -954,6 +991,12 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
|
|||
}
|
||||
EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
|
||||
|
||||
void cfg80211_cqm_config_free(struct wireless_dev *wdev)
|
||||
{
|
||||
kfree(wdev->cqm_config);
|
||||
wdev->cqm_config = NULL;
|
||||
}
|
||||
|
||||
void cfg80211_unregister_wdev(struct wireless_dev *wdev)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
|
@ -980,6 +1023,8 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
|
|||
WARN_ON_ONCE(1);
|
||||
break;
|
||||
}
|
||||
|
||||
cfg80211_cqm_config_free(wdev);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_unregister_wdev);
|
||||
|
||||
|
@ -1114,7 +1159,15 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
|||
INIT_LIST_HEAD(&wdev->mgmt_registrations);
|
||||
spin_lock_init(&wdev->mgmt_registrations_lock);
|
||||
|
||||
wdev->identifier = ++rdev->wdev_id;
|
||||
/*
|
||||
* We get here also when the interface changes network namespaces,
|
||||
* as it's registered into the new one, but we don't want it to
|
||||
* change ID in that case. Checking if the ID is already assigned
|
||||
* works, because 0 isn't considered a valid ID and the memory is
|
||||
* 0-initialized.
|
||||
*/
|
||||
if (!wdev->identifier)
|
||||
wdev->identifier = ++rdev->wdev_id;
|
||||
list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
|
||||
rdev->devlist_generation++;
|
||||
/* can only change netns with wiphy */
|
||||
|
@ -1208,12 +1261,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
|||
*/
|
||||
if ((wdev->iftype == NL80211_IFTYPE_STATION ||
|
||||
wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) &&
|
||||
rdev->ops->set_power_mgmt)
|
||||
if (rdev_set_power_mgmt(rdev, dev, wdev->ps,
|
||||
wdev->ps_timeout)) {
|
||||
/* assume this means it's off */
|
||||
wdev->ps = false;
|
||||
}
|
||||
rdev->ops->set_power_mgmt &&
|
||||
rdev_set_power_mgmt(rdev, dev, wdev->ps,
|
||||
wdev->ps_timeout)) {
|
||||
/* assume this means it's off */
|
||||
wdev->ps = false;
|
||||
}
|
||||
break;
|
||||
case NETDEV_UNREGISTER:
|
||||
/*
|
||||
|
@ -1234,6 +1287,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
|||
kzfree(wdev->wext.keys);
|
||||
#endif
|
||||
flush_work(&wdev->disconnect_wk);
|
||||
cfg80211_cqm_config_free(wdev);
|
||||
}
|
||||
/*
|
||||
* synchronise (so that we won't find this netdev
|
||||
|
|
|
@ -97,6 +97,12 @@ struct cfg80211_registered_device {
|
|||
|
||||
struct work_struct sched_scan_stop_wk;
|
||||
|
||||
struct cfg80211_chan_def radar_chandef;
|
||||
struct work_struct propagate_radar_detect_wk;
|
||||
|
||||
struct cfg80211_chan_def cac_done_chandef;
|
||||
struct work_struct propagate_cac_done_wk;
|
||||
|
||||
/* must be last because of the way we do wiphy_priv(),
|
||||
* and it should at least be aligned to NETDEV_ALIGN */
|
||||
struct wiphy wiphy __aligned(NETDEV_ALIGN);
|
||||
|
@ -220,16 +226,7 @@ struct cfg80211_event {
|
|||
enum cfg80211_event_type type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
u8 bssid[ETH_ALEN];
|
||||
const u8 *req_ie;
|
||||
const u8 *resp_ie;
|
||||
size_t req_ie_len;
|
||||
size_t resp_ie_len;
|
||||
struct cfg80211_bss *bss;
|
||||
int status; /* -1 = failed; 0..65535 = status code */
|
||||
enum nl80211_timeout_reason timeout_reason;
|
||||
} cr;
|
||||
struct cfg80211_connect_resp_params cr;
|
||||
struct {
|
||||
const u8 *req_ie;
|
||||
const u8 *resp_ie;
|
||||
|
@ -272,6 +269,13 @@ struct cfg80211_iface_destroy {
|
|||
u32 nlportid;
|
||||
};
|
||||
|
||||
struct cfg80211_cqm_config {
|
||||
u32 rssi_hyst;
|
||||
s32 last_rssi_event_value;
|
||||
int n_rssi_thresholds;
|
||||
s32 rssi_thresholds[0];
|
||||
};
|
||||
|
||||
void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev);
|
||||
|
||||
/* free object */
|
||||
|
@ -385,12 +389,9 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
|
|||
struct cfg80211_connect_params *connect,
|
||||
struct cfg80211_cached_keys *connkeys,
|
||||
const u8 *prev_bssid);
|
||||
void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
const u8 *resp_ie, size_t resp_ie_len,
|
||||
int status, bool wextev,
|
||||
struct cfg80211_bss *bss,
|
||||
enum nl80211_timeout_reason timeout_reason);
|
||||
void __cfg80211_connect_result(struct net_device *dev,
|
||||
struct cfg80211_connect_resp_params *params,
|
||||
bool wextev);
|
||||
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
|
||||
size_t ie_len, u16 reason, bool from_ap);
|
||||
int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
|
||||
|
@ -429,7 +430,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
|
|||
void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
|
||||
int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, enum nl80211_iftype ntype,
|
||||
u32 *flags, struct vif_params *params);
|
||||
struct vif_params *params);
|
||||
void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
|
||||
void cfg80211_process_wdev_events(struct wireless_dev *wdev);
|
||||
|
||||
|
@ -459,6 +460,16 @@ unsigned int
|
|||
cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
|
||||
const struct cfg80211_chan_def *chandef);
|
||||
|
||||
void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev);
|
||||
|
||||
bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
|
||||
struct ieee80211_channel *chan);
|
||||
|
||||
bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev);
|
||||
|
||||
bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef,
|
||||
struct ieee80211_channel *chan);
|
||||
|
||||
static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
|
||||
{
|
||||
unsigned long end = jiffies;
|
||||
|
@ -512,4 +523,6 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
|
|||
#define CFG80211_DEV_WARN_ON(cond) ({bool __r = (cond); __r; })
|
||||
#endif
|
||||
|
||||
void cfg80211_cqm_config_free(struct wireless_dev *wdev);
|
||||
|
||||
#endif /* __NET_WIRELESS_CORE_H */
|
||||
|
|
|
@ -190,6 +190,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
|
|||
if (!nowext)
|
||||
wdev->wext.ibss.ssid_len = 0;
|
||||
#endif
|
||||
cfg80211_sched_dfs_chan_update(rdev);
|
||||
}
|
||||
|
||||
void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
|
||||
|
|
|
@ -262,6 +262,7 @@ int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
|
|||
wdev->beacon_interval = 0;
|
||||
memset(&wdev->chandef, 0, sizeof(wdev->chandef));
|
||||
rdev_set_qos_map(rdev, dev, NULL);
|
||||
cfg80211_sched_dfs_chan_update(rdev);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
|
@ -26,9 +26,16 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
|
|||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
|
||||
u8 *ie = mgmt->u.assoc_resp.variable;
|
||||
int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
|
||||
u16 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
|
||||
struct cfg80211_connect_resp_params cr;
|
||||
|
||||
memset(&cr, 0, sizeof(cr));
|
||||
cr.status = (int)le16_to_cpu(mgmt->u.assoc_resp.status_code);
|
||||
cr.bssid = mgmt->bssid;
|
||||
cr.bss = bss;
|
||||
cr.resp_ie = mgmt->u.assoc_resp.variable;
|
||||
cr.resp_ie_len =
|
||||
len - offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
|
||||
cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED;
|
||||
|
||||
trace_cfg80211_send_rx_assoc(dev, bss);
|
||||
|
||||
|
@ -38,7 +45,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
|
|||
* and got a reject -- we only try again with an assoc
|
||||
* frame instead of reassoc.
|
||||
*/
|
||||
if (cfg80211_sme_rx_assoc_resp(wdev, status_code)) {
|
||||
if (cfg80211_sme_rx_assoc_resp(wdev, cr.status)) {
|
||||
cfg80211_unhold_bss(bss_from_pub(bss));
|
||||
cfg80211_put_bss(wiphy, bss);
|
||||
return;
|
||||
|
@ -46,10 +53,7 @@ void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
|
|||
|
||||
nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL, uapsd_queues);
|
||||
/* update current_bss etc., consumes the bss reference */
|
||||
__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
|
||||
status_code,
|
||||
status_code == WLAN_STATUS_SUCCESS, bss,
|
||||
NL80211_TIMEOUT_UNSPECIFIED);
|
||||
__cfg80211_connect_result(dev, &cr, cr.status == WLAN_STATUS_SUCCESS);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_rx_assoc_resp);
|
||||
|
||||
|
@ -745,6 +749,12 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
|
|||
}
|
||||
EXPORT_SYMBOL(cfg80211_rx_mgmt);
|
||||
|
||||
void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev)
|
||||
{
|
||||
cancel_delayed_work(&rdev->dfs_update_channels_wk);
|
||||
queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk, 0);
|
||||
}
|
||||
|
||||
void cfg80211_dfs_channels_update_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *delayed_work = to_delayed_work(work);
|
||||
|
@ -755,6 +765,8 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work)
|
|||
struct wiphy *wiphy;
|
||||
bool check_again = false;
|
||||
unsigned long timeout, next_time = 0;
|
||||
unsigned long time_dfs_update;
|
||||
enum nl80211_radar_event radar_event;
|
||||
int bandid, i;
|
||||
|
||||
rdev = container_of(delayed_work, struct cfg80211_registered_device,
|
||||
|
@ -770,11 +782,27 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work)
|
|||
for (i = 0; i < sband->n_channels; i++) {
|
||||
c = &sband->channels[i];
|
||||
|
||||
if (c->dfs_state != NL80211_DFS_UNAVAILABLE)
|
||||
if (!(c->flags & IEEE80211_CHAN_RADAR))
|
||||
continue;
|
||||
|
||||
timeout = c->dfs_state_entered + msecs_to_jiffies(
|
||||
IEEE80211_DFS_MIN_NOP_TIME_MS);
|
||||
if (c->dfs_state != NL80211_DFS_UNAVAILABLE &&
|
||||
c->dfs_state != NL80211_DFS_AVAILABLE)
|
||||
continue;
|
||||
|
||||
if (c->dfs_state == NL80211_DFS_UNAVAILABLE) {
|
||||
time_dfs_update = IEEE80211_DFS_MIN_NOP_TIME_MS;
|
||||
radar_event = NL80211_RADAR_NOP_FINISHED;
|
||||
} else {
|
||||
if (regulatory_pre_cac_allowed(wiphy) ||
|
||||
cfg80211_any_wiphy_oper_chan(wiphy, c))
|
||||
continue;
|
||||
|
||||
time_dfs_update = REG_PRE_CAC_EXPIRY_GRACE_MS;
|
||||
radar_event = NL80211_RADAR_PRE_CAC_EXPIRED;
|
||||
}
|
||||
|
||||
timeout = c->dfs_state_entered +
|
||||
msecs_to_jiffies(time_dfs_update);
|
||||
|
||||
if (time_after_eq(jiffies, timeout)) {
|
||||
c->dfs_state = NL80211_DFS_USABLE;
|
||||
|
@ -784,8 +812,12 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work)
|
|||
NL80211_CHAN_NO_HT);
|
||||
|
||||
nl80211_radar_notify(rdev, &chandef,
|
||||
NL80211_RADAR_NOP_FINISHED,
|
||||
NULL, GFP_ATOMIC);
|
||||
radar_event, NULL,
|
||||
GFP_ATOMIC);
|
||||
|
||||
regulatory_propagate_dfs_state(wiphy, &chandef,
|
||||
c->dfs_state,
|
||||
radar_event);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -810,7 +842,6 @@ void cfg80211_radar_event(struct wiphy *wiphy,
|
|||
gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
|
||||
unsigned long timeout;
|
||||
|
||||
trace_cfg80211_radar_event(wiphy, chandef);
|
||||
|
||||
|
@ -820,11 +851,12 @@ void cfg80211_radar_event(struct wiphy *wiphy,
|
|||
*/
|
||||
cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE);
|
||||
|
||||
timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_NOP_TIME_MS);
|
||||
queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk,
|
||||
timeout);
|
||||
cfg80211_sched_dfs_chan_update(rdev);
|
||||
|
||||
nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp);
|
||||
|
||||
memcpy(&rdev->radar_chandef, chandef, sizeof(struct cfg80211_chan_def));
|
||||
queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_radar_event);
|
||||
|
||||
|
@ -851,6 +883,10 @@ void cfg80211_cac_event(struct net_device *netdev,
|
|||
msecs_to_jiffies(wdev->cac_time_ms);
|
||||
WARN_ON(!time_after_eq(jiffies, timeout));
|
||||
cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
|
||||
memcpy(&rdev->cac_done_chandef, chandef,
|
||||
sizeof(struct cfg80211_chan_def));
|
||||
queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
|
||||
cfg80211_sched_dfs_chan_update(rdev);
|
||||
break;
|
||||
case NL80211_RADAR_CAC_ABORTED:
|
||||
break;
|
||||
|
|
|
@ -410,6 +410,15 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
|||
.len = sizeof(struct nl80211_bss_select_rssi_adjust)
|
||||
},
|
||||
[NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_FILS_ERP_USERNAME] = { .type = NLA_BINARY,
|
||||
.len = FILS_ERP_MAX_USERNAME_LEN },
|
||||
[NL80211_ATTR_FILS_ERP_REALM] = { .type = NLA_BINARY,
|
||||
.len = FILS_ERP_MAX_REALM_LEN },
|
||||
[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
|
||||
.len = FILS_ERP_MAX_RRK_LEN },
|
||||
[NL80211_ATTR_FILS_CACHE_ID] = { .len = 2 },
|
||||
[NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
|
@ -2705,9 +2714,74 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
|
|||
if (flags[flag])
|
||||
*mntrflags |= (1<<flag);
|
||||
|
||||
*mntrflags |= MONITOR_FLAG_CHANGED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nl80211_parse_mon_options(struct cfg80211_registered_device *rdev,
|
||||
enum nl80211_iftype type,
|
||||
struct genl_info *info,
|
||||
struct vif_params *params)
|
||||
{
|
||||
bool change = false;
|
||||
int err;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
|
||||
if (type != NL80211_IFTYPE_MONITOR)
|
||||
return -EINVAL;
|
||||
|
||||
err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
|
||||
¶ms->flags);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
change = true;
|
||||
}
|
||||
|
||||
if (params->flags & MONITOR_FLAG_ACTIVE &&
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) {
|
||||
const u8 *mumimo_groups;
|
||||
u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
|
||||
|
||||
if (type != NL80211_IFTYPE_MONITOR)
|
||||
return -EINVAL;
|
||||
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mumimo_groups =
|
||||
nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]);
|
||||
|
||||
/* bits 0 and 63 are reserved and must be zero */
|
||||
if ((mumimo_groups[0] & BIT(7)) ||
|
||||
(mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(0)))
|
||||
return -EINVAL;
|
||||
|
||||
params->vht_mumimo_groups = mumimo_groups;
|
||||
change = true;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) {
|
||||
u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
|
||||
|
||||
if (type != NL80211_IFTYPE_MONITOR)
|
||||
return -EINVAL;
|
||||
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
params->vht_mumimo_follow_addr =
|
||||
nla_data(info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]);
|
||||
change = true;
|
||||
}
|
||||
|
||||
return change ? 1 : 0;
|
||||
}
|
||||
|
||||
static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, u8 use_4addr,
|
||||
enum nl80211_iftype iftype)
|
||||
|
@ -2741,7 +2815,6 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
int err;
|
||||
enum nl80211_iftype otype, ntype;
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
u32 _flags, *flags = NULL;
|
||||
bool change = false;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
@ -2784,56 +2857,14 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
params.use_4addr = -1;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
|
||||
if (ntype != NL80211_IFTYPE_MONITOR)
|
||||
return -EINVAL;
|
||||
err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
|
||||
&_flags);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
flags = &_flags;
|
||||
err = nl80211_parse_mon_options(rdev, ntype, info, ¶ms);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (err > 0)
|
||||
change = true;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]) {
|
||||
const u8 *mumimo_groups;
|
||||
u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
|
||||
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mumimo_groups =
|
||||
nla_data(info->attrs[NL80211_ATTR_MU_MIMO_GROUP_DATA]);
|
||||
|
||||
/* bits 0 and 63 are reserved and must be zero */
|
||||
if ((mumimo_groups[0] & BIT(7)) ||
|
||||
(mumimo_groups[VHT_MUMIMO_GROUPS_DATA_LEN - 1] & BIT(0)))
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(params.vht_mumimo_groups, mumimo_groups,
|
||||
VHT_MUMIMO_GROUPS_DATA_LEN);
|
||||
change = true;
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR]) {
|
||||
u32 cap_flag = NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER;
|
||||
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy, cap_flag))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
nla_memcpy(params.macaddr,
|
||||
info->attrs[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR],
|
||||
ETH_ALEN);
|
||||
change = true;
|
||||
}
|
||||
|
||||
if (flags && (*flags & MONITOR_FLAG_ACTIVE) &&
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (change)
|
||||
err = cfg80211_change_iface(rdev, dev, ntype, flags, ¶ms);
|
||||
err = cfg80211_change_iface(rdev, dev, ntype, ¶ms);
|
||||
else
|
||||
err = 0;
|
||||
|
||||
|
@ -2851,7 +2882,6 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
struct sk_buff *msg;
|
||||
int err;
|
||||
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
|
||||
u32 flags;
|
||||
|
||||
/* to avoid failing a new interface creation due to pending removal */
|
||||
cfg80211_destroy_ifaces(rdev);
|
||||
|
@ -2887,13 +2917,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
return err;
|
||||
}
|
||||
|
||||
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
|
||||
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
|
||||
&flags);
|
||||
|
||||
if (!err && (flags & MONITOR_FLAG_ACTIVE) &&
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
|
||||
return -EOPNOTSUPP;
|
||||
err = nl80211_parse_mon_options(rdev, type, info, ¶ms);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!msg)
|
||||
|
@ -2901,8 +2927,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
wdev = rdev_add_virtual_intf(rdev,
|
||||
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
|
||||
NET_NAME_USER, type, err ? NULL : &flags,
|
||||
¶ms);
|
||||
NET_NAME_USER, type, ¶ms);
|
||||
if (WARN_ON(!wdev)) {
|
||||
nlmsg_free(msg);
|
||||
return -EPROTO;
|
||||
|
@ -3820,6 +3845,19 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
|
|||
return false;
|
||||
return true;
|
||||
case NL80211_CMD_CONNECT:
|
||||
/* SAE not supported yet */
|
||||
if (auth_type == NL80211_AUTHTYPE_SAE)
|
||||
return false;
|
||||
/* FILS with SK PFS or PK not supported yet */
|
||||
if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
|
||||
auth_type == NL80211_AUTHTYPE_FILS_PK)
|
||||
return false;
|
||||
if (!wiphy_ext_feature_isset(
|
||||
&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
|
||||
auth_type == NL80211_AUTHTYPE_FILS_SK)
|
||||
return false;
|
||||
return true;
|
||||
case NL80211_CMD_START_AP:
|
||||
/* SAE not supported yet */
|
||||
if (auth_type == NL80211_AUTHTYPE_SAE)
|
||||
|
@ -4153,7 +4191,7 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
|
|||
struct nlattr *rate;
|
||||
u32 bitrate;
|
||||
u16 bitrate_compat;
|
||||
enum nl80211_attrs rate_flg;
|
||||
enum nl80211_rate_info rate_flg;
|
||||
|
||||
rate = nla_nest_start(msg, attr);
|
||||
if (!rate)
|
||||
|
@ -5705,7 +5743,7 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
|
|||
cur_params.dot11MeshGateAnnouncementProtocol) ||
|
||||
nla_put_u8(msg, NL80211_MESHCONF_FORWARDING,
|
||||
cur_params.dot11MeshForwarding) ||
|
||||
nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
|
||||
nla_put_s32(msg, NL80211_MESHCONF_RSSI_THRESHOLD,
|
||||
cur_params.rssi_threshold) ||
|
||||
nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE,
|
||||
cur_params.ht_opmode) ||
|
||||
|
@ -6548,6 +6586,19 @@ static int nl80211_parse_random_mac(struct nlattr **attrs,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev)
|
||||
{
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (!cfg80211_beaconing_iface_active(wdev))
|
||||
return true;
|
||||
|
||||
if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR))
|
||||
return true;
|
||||
|
||||
return regulatory_pre_cac_allowed(wdev->wiphy);
|
||||
}
|
||||
|
||||
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
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)
|
|||
|
||||
request->n_channels = i;
|
||||
|
||||
wdev_lock(wdev);
|
||||
if (!cfg80211_off_channel_oper_allowed(wdev)) {
|
||||
struct ieee80211_channel *chan;
|
||||
|
||||
if (request->n_channels != 1) {
|
||||
wdev_unlock(wdev);
|
||||
err = -EBUSY;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
chan = request->channels[0];
|
||||
if (chan->center_freq != wdev->chandef.chan->center_freq) {
|
||||
wdev_unlock(wdev);
|
||||
err = -EBUSY;
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
wdev_unlock(wdev);
|
||||
|
||||
i = 0;
|
||||
if (n_ssids) {
|
||||
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,
|
|||
|
||||
rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);
|
||||
|
||||
nl80211_send_sched_scan(rdev, dev,
|
||||
NL80211_CMD_START_SCHED_SCAN);
|
||||
nl80211_send_sched_scan(sched_scan_req, NL80211_CMD_START_SCHED_SCAN);
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
|
@ -8873,6 +8942,35 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
|
|||
}
|
||||
}
|
||||
|
||||
if (wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] &&
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_REALM] &&
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] &&
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
|
||||
connect.fils_erp_username =
|
||||
nla_data(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
|
||||
connect.fils_erp_username_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_FILS_ERP_USERNAME]);
|
||||
connect.fils_erp_realm =
|
||||
nla_data(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
|
||||
connect.fils_erp_realm_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_FILS_ERP_REALM]);
|
||||
connect.fils_erp_next_seq_num =
|
||||
nla_get_u16(
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM]);
|
||||
connect.fils_erp_rrk =
|
||||
nla_data(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
|
||||
connect.fils_erp_rrk_len =
|
||||
nla_len(info->attrs[NL80211_ATTR_FILS_ERP_RRK]);
|
||||
} else if (info->attrs[NL80211_ATTR_FILS_ERP_USERNAME] ||
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_REALM] ||
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] ||
|
||||
info->attrs[NL80211_ATTR_FILS_ERP_RRK]) {
|
||||
kzfree(connkeys);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wdev_lock(dev->ieee80211_ptr);
|
||||
|
||||
err = cfg80211_connect(rdev, dev, &connect, connkeys,
|
||||
|
@ -8992,14 +9090,28 @@ static int nl80211_setdel_pmksa(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
memset(&pmksa, 0, sizeof(struct cfg80211_pmksa));
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_MAC])
|
||||
return -EINVAL;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_PMKID])
|
||||
return -EINVAL;
|
||||
|
||||
pmksa.pmkid = nla_data(info->attrs[NL80211_ATTR_PMKID]);
|
||||
pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MAC]) {
|
||||
pmksa.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
} else if (info->attrs[NL80211_ATTR_SSID] &&
|
||||
info->attrs[NL80211_ATTR_FILS_CACHE_ID] &&
|
||||
(info->genlhdr->cmd == NL80211_CMD_DEL_PMKSA ||
|
||||
info->attrs[NL80211_ATTR_PMK])) {
|
||||
pmksa.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
|
||||
pmksa.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
|
||||
pmksa.cache_id =
|
||||
nla_data(info->attrs[NL80211_ATTR_FILS_CACHE_ID]);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (info->attrs[NL80211_ATTR_PMK]) {
|
||||
pmksa.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
|
||||
pmksa.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
|
||||
}
|
||||
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT)
|
||||
|
@ -9102,6 +9214,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
|
|||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct wireless_dev *wdev = info->user_ptr[1];
|
||||
struct cfg80211_chan_def chandef;
|
||||
const struct cfg80211_chan_def *compat_chandef;
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
u64 cookie;
|
||||
|
@ -9130,6 +9243,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
wdev_lock(wdev);
|
||||
if (!cfg80211_off_channel_oper_allowed(wdev) &&
|
||||
!cfg80211_chandef_identical(&wdev->chandef, &chandef)) {
|
||||
compat_chandef = cfg80211_chandef_compatible(&wdev->chandef,
|
||||
&chandef);
|
||||
if (compat_chandef != &chandef) {
|
||||
wdev_unlock(wdev);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
wdev_unlock(wdev);
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
@ -9305,6 +9430,13 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
|
|||
if (!chandef.chan && params.offchan)
|
||||
return -EINVAL;
|
||||
|
||||
wdev_lock(wdev);
|
||||
if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev)) {
|
||||
wdev_unlock(wdev);
|
||||
return -EBUSY;
|
||||
}
|
||||
wdev_unlock(wdev);
|
||||
|
||||
params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
|
||||
params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
|
||||
|
||||
|
@ -9472,7 +9604,7 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
static const struct nla_policy
|
||||
nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
|
||||
[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_BINARY },
|
||||
[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
|
||||
|
@ -9501,28 +9633,123 @@ static int nl80211_set_cqm_txe(struct genl_info *info,
|
|||
return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
|
||||
}
|
||||
|
||||
static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
s32 last, low, high;
|
||||
u32 hyst;
|
||||
int i, n;
|
||||
int err;
|
||||
|
||||
/* RSSI reporting disabled? */
|
||||
if (!wdev->cqm_config)
|
||||
return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
|
||||
|
||||
/*
|
||||
* Obtain current RSSI value if possible, if not and no RSSI threshold
|
||||
* event has been received yet, we should receive an event after a
|
||||
* connection is established and enough beacons received to calculate
|
||||
* the average.
|
||||
*/
|
||||
if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss &&
|
||||
rdev->ops->get_station) {
|
||||
struct station_info sinfo;
|
||||
u8 *mac_addr;
|
||||
|
||||
mac_addr = wdev->current_bss->pub.bssid;
|
||||
|
||||
err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (sinfo.filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
|
||||
wdev->cqm_config->last_rssi_event_value =
|
||||
(s8) sinfo.rx_beacon_signal_avg;
|
||||
}
|
||||
|
||||
last = wdev->cqm_config->last_rssi_event_value;
|
||||
hyst = wdev->cqm_config->rssi_hyst;
|
||||
n = wdev->cqm_config->n_rssi_thresholds;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if (last < wdev->cqm_config->rssi_thresholds[i])
|
||||
break;
|
||||
|
||||
low = i > 0 ?
|
||||
(wdev->cqm_config->rssi_thresholds[i - 1] - hyst) : S32_MIN;
|
||||
high = i < n ?
|
||||
(wdev->cqm_config->rssi_thresholds[i] + hyst - 1) : S32_MAX;
|
||||
|
||||
return rdev_set_cqm_rssi_range_config(rdev, dev, low, high);
|
||||
}
|
||||
|
||||
static int nl80211_set_cqm_rssi(struct genl_info *info,
|
||||
s32 threshold, u32 hysteresis)
|
||||
const s32 *thresholds, int n_thresholds,
|
||||
u32 hysteresis)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int i, err;
|
||||
s32 prev = S32_MIN;
|
||||
|
||||
if (threshold > 0)
|
||||
return -EINVAL;
|
||||
/* Check all values negative and sorted */
|
||||
for (i = 0; i < n_thresholds; i++) {
|
||||
if (thresholds[i] > 0 || thresholds[i] <= prev)
|
||||
return -EINVAL;
|
||||
|
||||
/* disabling - hysteresis should also be zero then */
|
||||
if (threshold == 0)
|
||||
hysteresis = 0;
|
||||
|
||||
if (!rdev->ops->set_cqm_rssi_config)
|
||||
return -EOPNOTSUPP;
|
||||
prev = thresholds[i];
|
||||
}
|
||||
|
||||
if (wdev->iftype != NL80211_IFTYPE_STATION &&
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return rdev_set_cqm_rssi_config(rdev, dev, threshold, hysteresis);
|
||||
wdev_lock(wdev);
|
||||
cfg80211_cqm_config_free(wdev);
|
||||
wdev_unlock(wdev);
|
||||
|
||||
if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) {
|
||||
if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */
|
||||
return rdev_set_cqm_rssi_config(rdev, dev, 0, 0);
|
||||
|
||||
return rdev_set_cqm_rssi_config(rdev, dev,
|
||||
thresholds[0], hysteresis);
|
||||
}
|
||||
|
||||
if (!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_CQM_RSSI_LIST))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (n_thresholds == 1 && thresholds[0] == 0) /* Disabling */
|
||||
n_thresholds = 0;
|
||||
|
||||
wdev_lock(wdev);
|
||||
if (n_thresholds) {
|
||||
struct cfg80211_cqm_config *cqm_config;
|
||||
|
||||
cqm_config = kzalloc(sizeof(struct cfg80211_cqm_config) +
|
||||
n_thresholds * sizeof(s32), GFP_KERNEL);
|
||||
if (!cqm_config) {
|
||||
err = -ENOMEM;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
cqm_config->rssi_hyst = hysteresis;
|
||||
cqm_config->n_rssi_thresholds = n_thresholds;
|
||||
memcpy(cqm_config->rssi_thresholds, thresholds,
|
||||
n_thresholds * sizeof(s32));
|
||||
|
||||
wdev->cqm_config = cqm_config;
|
||||
}
|
||||
|
||||
err = cfg80211_cqm_rssi_update(rdev, dev);
|
||||
|
||||
unlock:
|
||||
wdev_unlock(wdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
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)
|
|||
|
||||
if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
|
||||
attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
|
||||
s32 threshold = nla_get_s32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
|
||||
const s32 *thresholds =
|
||||
nla_data(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
|
||||
int len = nla_len(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
|
||||
u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
|
||||
|
||||
return nl80211_set_cqm_rssi(info, threshold, hysteresis);
|
||||
if (len % 4)
|
||||
return -EINVAL;
|
||||
|
||||
return nl80211_set_cqm_rssi(info, thresholds, len / 4,
|
||||
hysteresis);
|
||||
}
|
||||
|
||||
if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
|
||||
|
@ -12977,18 +13210,19 @@ static int nl80211_prep_scan_msg(struct sk_buff *msg,
|
|||
|
||||
static int
|
||||
nl80211_prep_sched_scan_msg(struct sk_buff *msg,
|
||||
struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev,
|
||||
u32 portid, u32 seq, int flags, u32 cmd)
|
||||
struct cfg80211_sched_scan_request *req, u32 cmd)
|
||||
{
|
||||
void *hdr;
|
||||
|
||||
hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
|
||||
hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
|
||||
if (!hdr)
|
||||
return -1;
|
||||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY,
|
||||
wiphy_to_rdev(req->wiphy)->wiphy_idx) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, req->dev->ifindex) ||
|
||||
nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->reqid,
|
||||
NL80211_ATTR_PAD))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
|
@ -13048,8 +13282,7 @@ void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
|
|||
NL80211_MCGRP_SCAN, GFP_KERNEL);
|
||||
}
|
||||
|
||||
void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, u32 cmd)
|
||||
void nl80211_send_sched_scan(struct cfg80211_sched_scan_request *req, u32 cmd)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
|
||||
|
@ -13057,12 +13290,12 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
|
|||
if (!msg)
|
||||
return;
|
||||
|
||||
if (nl80211_prep_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
|
||||
if (nl80211_prep_sched_scan_msg(msg, req, cmd) < 0) {
|
||||
nlmsg_free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
|
||||
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(req->wiphy), msg, 0,
|
||||
NL80211_MCGRP_SCAN, GFP_KERNEL);
|
||||
}
|
||||
|
||||
|
@ -13303,17 +13536,16 @@ void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
|
|||
}
|
||||
|
||||
void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
const u8 *resp_ie, size_t resp_ie_len,
|
||||
int status,
|
||||
enum nl80211_timeout_reason timeout_reason,
|
||||
struct net_device *netdev,
|
||||
struct cfg80211_connect_resp_params *cr,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
|
||||
msg = nlmsg_new(100 + req_ie_len + resp_ie_len, gfp);
|
||||
msg = nlmsg_new(100 + cr->req_ie_len + cr->resp_ie_len +
|
||||
cr->fils_kek_len + cr->pmk_len +
|
||||
(cr->pmkid ? WLAN_PMKID_LEN : 0), gfp);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
|
@ -13325,17 +13557,31 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
|
|||
|
||||
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
|
||||
(bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) ||
|
||||
(cr->bssid &&
|
||||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, cr->bssid)) ||
|
||||
nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
|
||||
status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
|
||||
status) ||
|
||||
(status < 0 &&
|
||||
cr->status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
|
||||
cr->status) ||
|
||||
(cr->status < 0 &&
|
||||
(nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
|
||||
nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON, timeout_reason))) ||
|
||||
(req_ie &&
|
||||
nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
|
||||
(resp_ie &&
|
||||
nla_put(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie)))
|
||||
nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON,
|
||||
cr->timeout_reason))) ||
|
||||
(cr->req_ie &&
|
||||
nla_put(msg, NL80211_ATTR_REQ_IE, cr->req_ie_len, cr->req_ie)) ||
|
||||
(cr->resp_ie &&
|
||||
nla_put(msg, NL80211_ATTR_RESP_IE, cr->resp_ie_len,
|
||||
cr->resp_ie)) ||
|
||||
(cr->update_erp_next_seq_num &&
|
||||
nla_put_u16(msg, NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM,
|
||||
cr->fils_erp_next_seq_num)) ||
|
||||
(cr->status == WLAN_STATUS_SUCCESS &&
|
||||
((cr->fils_kek &&
|
||||
nla_put(msg, NL80211_ATTR_FILS_KEK, cr->fils_kek_len,
|
||||
cr->fils_kek)) ||
|
||||
(cr->pmk &&
|
||||
nla_put(msg, NL80211_ATTR_PMK, cr->pmk_len, cr->pmk)) ||
|
||||
(cr->pmkid &&
|
||||
nla_put(msg, NL80211_ATTR_PMKID, WLAN_PMKID_LEN, cr->pmkid)))))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
|
@ -13975,6 +14221,8 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
|
|||
s32 rssi_level, gfp_t gfp)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
|
||||
trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
|
||||
|
||||
|
@ -13982,6 +14230,15 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
|
|||
rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
|
||||
return;
|
||||
|
||||
if (wdev->cqm_config) {
|
||||
wdev->cqm_config->last_rssi_event_value = rssi_level;
|
||||
|
||||
cfg80211_cqm_rssi_update(rdev, dev);
|
||||
|
||||
if (rssi_level == 0)
|
||||
rssi_level = wdev->cqm_config->last_rssi_event_value;
|
||||
}
|
||||
|
||||
msg = cfg80211_prepare_cqm(dev, NULL, gfp);
|
||||
if (!msg)
|
||||
return;
|
||||
|
|
|
@ -16,8 +16,7 @@ struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
|
|||
struct wireless_dev *wdev, bool aborted);
|
||||
void nl80211_send_scan_msg(struct cfg80211_registered_device *rdev,
|
||||
struct sk_buff *msg);
|
||||
void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, u32 cmd);
|
||||
void nl80211_send_sched_scan(struct cfg80211_sched_scan_request *req, u32 cmd);
|
||||
void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
|
||||
struct regulatory_request *request);
|
||||
|
||||
|
@ -53,11 +52,8 @@ void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
|
|||
struct net_device *netdev,
|
||||
const u8 *addr, gfp_t gfp);
|
||||
void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
const u8 *resp_ie, size_t resp_ie_len,
|
||||
int status,
|
||||
enum nl80211_timeout_reason timeout_reason,
|
||||
struct net_device *netdev,
|
||||
struct cfg80211_connect_resp_params *params,
|
||||
gfp_t gfp);
|
||||
void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *netdev, const u8 *bssid,
|
||||
|
|
|
@ -36,13 +36,13 @@ static inline void rdev_set_wakeup(struct cfg80211_registered_device *rdev,
|
|||
static inline struct wireless_dev
|
||||
*rdev_add_virtual_intf(struct cfg80211_registered_device *rdev, char *name,
|
||||
unsigned char name_assign_type,
|
||||
enum nl80211_iftype type, u32 *flags,
|
||||
enum nl80211_iftype type,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct wireless_dev *ret;
|
||||
trace_rdev_add_virtual_intf(&rdev->wiphy, name, type);
|
||||
ret = rdev->ops->add_virtual_intf(&rdev->wiphy, name, name_assign_type,
|
||||
type, flags, params);
|
||||
type, params);
|
||||
trace_rdev_return_wdev(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -61,12 +61,11 @@ rdev_del_virtual_intf(struct cfg80211_registered_device *rdev,
|
|||
static inline int
|
||||
rdev_change_virtual_intf(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, enum nl80211_iftype type,
|
||||
u32 *flags, struct vif_params *params)
|
||||
struct vif_params *params)
|
||||
{
|
||||
int ret;
|
||||
trace_rdev_change_virtual_intf(&rdev->wiphy, dev, type);
|
||||
ret = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, type, flags,
|
||||
params);
|
||||
ret = rdev->ops->change_virtual_intf(&rdev->wiphy, dev, type, params);
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -749,6 +748,18 @@ rdev_set_cqm_rssi_config(struct cfg80211_registered_device *rdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
rdev_set_cqm_rssi_range_config(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, s32 low, s32 high)
|
||||
{
|
||||
int ret;
|
||||
trace_rdev_set_cqm_rssi_range_config(&rdev->wiphy, dev, low, high);
|
||||
ret = rdev->ops->set_cqm_rssi_range_config(&rdev->wiphy, dev,
|
||||
low, high);
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
rdev_set_cqm_txe_config(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, u32 rate, u32 pkts, u32 intvl)
|
||||
|
|
|
@ -2067,6 +2067,88 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
|
|||
return REG_REQ_IGNORE;
|
||||
}
|
||||
|
||||
bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2)
|
||||
{
|
||||
const struct ieee80211_regdomain *wiphy1_regd = NULL;
|
||||
const struct ieee80211_regdomain *wiphy2_regd = NULL;
|
||||
const struct ieee80211_regdomain *cfg80211_regd = NULL;
|
||||
bool dfs_domain_same;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
cfg80211_regd = rcu_dereference(cfg80211_regdomain);
|
||||
wiphy1_regd = rcu_dereference(wiphy1->regd);
|
||||
if (!wiphy1_regd)
|
||||
wiphy1_regd = cfg80211_regd;
|
||||
|
||||
wiphy2_regd = rcu_dereference(wiphy2->regd);
|
||||
if (!wiphy2_regd)
|
||||
wiphy2_regd = cfg80211_regd;
|
||||
|
||||
dfs_domain_same = wiphy1_regd->dfs_region == wiphy2_regd->dfs_region;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return dfs_domain_same;
|
||||
}
|
||||
|
||||
static void reg_copy_dfs_chan_state(struct ieee80211_channel *dst_chan,
|
||||
struct ieee80211_channel *src_chan)
|
||||
{
|
||||
if (!(dst_chan->flags & IEEE80211_CHAN_RADAR) ||
|
||||
!(src_chan->flags & IEEE80211_CHAN_RADAR))
|
||||
return;
|
||||
|
||||
if (dst_chan->flags & IEEE80211_CHAN_DISABLED ||
|
||||
src_chan->flags & IEEE80211_CHAN_DISABLED)
|
||||
return;
|
||||
|
||||
if (src_chan->center_freq == dst_chan->center_freq &&
|
||||
dst_chan->dfs_state == NL80211_DFS_USABLE) {
|
||||
dst_chan->dfs_state = src_chan->dfs_state;
|
||||
dst_chan->dfs_state_entered = src_chan->dfs_state_entered;
|
||||
}
|
||||
}
|
||||
|
||||
static void wiphy_share_dfs_chan_state(struct wiphy *dst_wiphy,
|
||||
struct wiphy *src_wiphy)
|
||||
{
|
||||
struct ieee80211_supported_band *src_sband, *dst_sband;
|
||||
struct ieee80211_channel *src_chan, *dst_chan;
|
||||
int i, j, band;
|
||||
|
||||
if (!reg_dfs_domain_same(dst_wiphy, src_wiphy))
|
||||
return;
|
||||
|
||||
for (band = 0; band < NUM_NL80211_BANDS; band++) {
|
||||
dst_sband = dst_wiphy->bands[band];
|
||||
src_sband = src_wiphy->bands[band];
|
||||
if (!dst_sband || !src_sband)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < dst_sband->n_channels; i++) {
|
||||
dst_chan = &dst_sband->channels[i];
|
||||
for (j = 0; j < src_sband->n_channels; j++) {
|
||||
src_chan = &src_sband->channels[j];
|
||||
reg_copy_dfs_chan_state(dst_chan, src_chan);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wiphy_all_share_dfs_chan_state(struct wiphy *wiphy)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
|
||||
if (wiphy == &rdev->wiphy)
|
||||
continue;
|
||||
wiphy_share_dfs_chan_state(wiphy, &rdev->wiphy);
|
||||
}
|
||||
}
|
||||
|
||||
/* This processes *all* regulatory hints */
|
||||
static void reg_process_hint(struct regulatory_request *reg_request)
|
||||
{
|
||||
|
@ -2110,6 +2192,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
|
|||
if (treatment == REG_REQ_ALREADY_SET && wiphy &&
|
||||
wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
|
||||
wiphy_update_regulatory(wiphy, reg_request->initiator);
|
||||
wiphy_all_share_dfs_chan_state(wiphy);
|
||||
reg_check_channels();
|
||||
}
|
||||
|
||||
|
@ -3061,6 +3144,7 @@ void wiphy_regulatory_register(struct wiphy *wiphy)
|
|||
|
||||
lr = get_last_request();
|
||||
wiphy_update_regulatory(wiphy, lr->initiator);
|
||||
wiphy_all_share_dfs_chan_state(wiphy);
|
||||
}
|
||||
|
||||
void wiphy_regulatory_deregister(struct wiphy *wiphy)
|
||||
|
@ -3120,6 +3204,70 @@ bool regulatory_indoor_allowed(void)
|
|||
return reg_is_indoor;
|
||||
}
|
||||
|
||||
bool regulatory_pre_cac_allowed(struct wiphy *wiphy)
|
||||
{
|
||||
const struct ieee80211_regdomain *regd = NULL;
|
||||
const struct ieee80211_regdomain *wiphy_regd = NULL;
|
||||
bool pre_cac_allowed = false;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
regd = rcu_dereference(cfg80211_regdomain);
|
||||
wiphy_regd = rcu_dereference(wiphy->regd);
|
||||
if (!wiphy_regd) {
|
||||
if (regd->dfs_region == NL80211_DFS_ETSI)
|
||||
pre_cac_allowed = true;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return pre_cac_allowed;
|
||||
}
|
||||
|
||||
if (regd->dfs_region == wiphy_regd->dfs_region &&
|
||||
wiphy_regd->dfs_region == NL80211_DFS_ETSI)
|
||||
pre_cac_allowed = true;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return pre_cac_allowed;
|
||||
}
|
||||
|
||||
void regulatory_propagate_dfs_state(struct wiphy *wiphy,
|
||||
struct cfg80211_chan_def *chandef,
|
||||
enum nl80211_dfs_state dfs_state,
|
||||
enum nl80211_radar_event event)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (WARN_ON(!cfg80211_chandef_valid(chandef)))
|
||||
return;
|
||||
|
||||
if (WARN_ON(!(chandef->chan->flags & IEEE80211_CHAN_RADAR)))
|
||||
return;
|
||||
|
||||
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
|
||||
if (wiphy == &rdev->wiphy)
|
||||
continue;
|
||||
|
||||
if (!reg_dfs_domain_same(wiphy, &rdev->wiphy))
|
||||
continue;
|
||||
|
||||
if (!ieee80211_get_channel(&rdev->wiphy,
|
||||
chandef->chan->center_freq))
|
||||
continue;
|
||||
|
||||
cfg80211_set_dfs_state(&rdev->wiphy, chandef, dfs_state);
|
||||
|
||||
if (event == NL80211_RADAR_DETECTED ||
|
||||
event == NL80211_RADAR_CAC_FINISHED)
|
||||
cfg80211_sched_dfs_chan_update(rdev);
|
||||
|
||||
nl80211_radar_notify(rdev, chandef, event, NULL, GFP_KERNEL);
|
||||
}
|
||||
}
|
||||
|
||||
int __init regulatory_init(void)
|
||||
{
|
||||
int err = 0;
|
||||
|
|
|
@ -143,4 +143,40 @@ int cfg80211_get_unii(int freq);
|
|||
*/
|
||||
bool regulatory_indoor_allowed(void);
|
||||
|
||||
/*
|
||||
* Grace period to timeout pre-CAC results on the dfs channels. This timeout
|
||||
* value is used for Non-ETSI domain.
|
||||
* TODO: May be make this timeout available through regdb?
|
||||
*/
|
||||
#define REG_PRE_CAC_EXPIRY_GRACE_MS 2000
|
||||
|
||||
/**
|
||||
* regulatory_pre_cac_allowed - if pre-CAC allowed in the current dfs domain
|
||||
* @wiphy: wiphy for which pre-CAC capability is checked.
|
||||
|
||||
* Pre-CAC is allowed only in ETSI domain.
|
||||
*/
|
||||
bool regulatory_pre_cac_allowed(struct wiphy *wiphy);
|
||||
|
||||
/**
|
||||
* regulatory_propagate_dfs_state - Propagate DFS channel state to other wiphys
|
||||
* @wiphy - wiphy on which radar is detected and the event will be propagated
|
||||
* to other available wiphys having the same DFS domain
|
||||
* @chandef - Channel definition of radar detected channel
|
||||
* @dfs_state - DFS channel state to be set
|
||||
* @event - Type of radar event which triggered this DFS state change
|
||||
*
|
||||
* This function should be called with rtnl lock held.
|
||||
*/
|
||||
void regulatory_propagate_dfs_state(struct wiphy *wiphy,
|
||||
struct cfg80211_chan_def *chandef,
|
||||
enum nl80211_dfs_state dfs_state,
|
||||
enum nl80211_radar_event event);
|
||||
|
||||
/**
|
||||
* reg_dfs_domain_same - Checks if both wiphy have same DFS domain configured
|
||||
* @wiphy1 - wiphy it's dfs_region to be checked against that of wiphy2
|
||||
* @wiphy2 - wiphy it's dfs_region to be checked against that of wiphy1
|
||||
*/
|
||||
bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2);
|
||||
#endif /* __NET_WIRELESS_REG_H */
|
||||
|
|
|
@ -321,8 +321,7 @@ void __cfg80211_sched_scan_results(struct work_struct *wk)
|
|||
spin_unlock_bh(&rdev->bss_lock);
|
||||
request->scan_start = jiffies;
|
||||
}
|
||||
nl80211_send_sched_scan(rdev, request->dev,
|
||||
NL80211_CMD_SCHED_SCAN_RESULTS);
|
||||
nl80211_send_sched_scan(request, NL80211_CMD_SCHED_SCAN_RESULTS);
|
||||
}
|
||||
|
||||
rtnl_unlock();
|
||||
|
@ -379,7 +378,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
|
|||
return err;
|
||||
}
|
||||
|
||||
nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED);
|
||||
nl80211_send_sched_scan(sched_scan_req, NL80211_CMD_SCHED_SCAN_STOPPED);
|
||||
|
||||
RCU_INIT_POINTER(rdev->sched_scan_req, NULL);
|
||||
kfree_rcu(sched_scan_req, rcu_head);
|
||||
|
|
|
@ -253,10 +253,13 @@ void cfg80211_conn_work(struct work_struct *work)
|
|||
}
|
||||
treason = NL80211_TIMEOUT_UNSPECIFIED;
|
||||
if (cfg80211_conn_do_work(wdev, &treason)) {
|
||||
__cfg80211_connect_result(
|
||||
wdev->netdev, bssid,
|
||||
NULL, 0, NULL, 0, -1, false, NULL,
|
||||
treason);
|
||||
struct cfg80211_connect_resp_params cr;
|
||||
|
||||
memset(&cr, 0, sizeof(cr));
|
||||
cr.status = -1;
|
||||
cr.bssid = bssid;
|
||||
cr.timeout_reason = treason;
|
||||
__cfg80211_connect_result(wdev->netdev, &cr, false);
|
||||
}
|
||||
wdev_unlock(wdev);
|
||||
}
|
||||
|
@ -359,10 +362,13 @@ void cfg80211_sme_rx_auth(struct wireless_dev *wdev, const u8 *buf, size_t len)
|
|||
wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT;
|
||||
schedule_work(&rdev->conn_work);
|
||||
} else if (status_code != WLAN_STATUS_SUCCESS) {
|
||||
__cfg80211_connect_result(wdev->netdev, mgmt->bssid,
|
||||
NULL, 0, NULL, 0,
|
||||
status_code, false, NULL,
|
||||
NL80211_TIMEOUT_UNSPECIFIED);
|
||||
struct cfg80211_connect_resp_params cr;
|
||||
|
||||
memset(&cr, 0, sizeof(cr));
|
||||
cr.status = status_code;
|
||||
cr.bssid = mgmt->bssid;
|
||||
cr.timeout_reason = NL80211_TIMEOUT_UNSPECIFIED;
|
||||
__cfg80211_connect_result(wdev->netdev, &cr, false);
|
||||
} else if (wdev->conn->state == CFG80211_CONN_AUTHENTICATING) {
|
||||
wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT;
|
||||
schedule_work(&rdev->conn_work);
|
||||
|
@ -669,12 +675,9 @@ static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
|
|||
*/
|
||||
|
||||
/* This method must consume bss one way or another */
|
||||
void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||
const u8 *req_ie, size_t req_ie_len,
|
||||
const u8 *resp_ie, size_t resp_ie_len,
|
||||
int status, bool wextev,
|
||||
struct cfg80211_bss *bss,
|
||||
enum nl80211_timeout_reason timeout_reason)
|
||||
void __cfg80211_connect_result(struct net_device *dev,
|
||||
struct cfg80211_connect_resp_params *cr,
|
||||
bool wextev)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
const u8 *country_ie;
|
||||
|
@ -686,48 +689,48 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
|
||||
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
|
||||
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) {
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
cfg80211_put_bss(wdev->wiphy, cr->bss);
|
||||
return;
|
||||
}
|
||||
|
||||
nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev,
|
||||
bssid, req_ie, req_ie_len,
|
||||
resp_ie, resp_ie_len,
|
||||
status, timeout_reason, GFP_KERNEL);
|
||||
nl80211_send_connect_result(wiphy_to_rdev(wdev->wiphy), dev, cr,
|
||||
GFP_KERNEL);
|
||||
|
||||
#ifdef CONFIG_CFG80211_WEXT
|
||||
if (wextev) {
|
||||
if (req_ie && status == WLAN_STATUS_SUCCESS) {
|
||||
if (cr->req_ie && cr->status == WLAN_STATUS_SUCCESS) {
|
||||
memset(&wrqu, 0, sizeof(wrqu));
|
||||
wrqu.data.length = req_ie_len;
|
||||
wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, req_ie);
|
||||
wrqu.data.length = cr->req_ie_len;
|
||||
wireless_send_event(dev, IWEVASSOCREQIE, &wrqu,
|
||||
cr->req_ie);
|
||||
}
|
||||
|
||||
if (resp_ie && status == WLAN_STATUS_SUCCESS) {
|
||||
if (cr->resp_ie && cr->status == WLAN_STATUS_SUCCESS) {
|
||||
memset(&wrqu, 0, sizeof(wrqu));
|
||||
wrqu.data.length = resp_ie_len;
|
||||
wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
|
||||
wrqu.data.length = cr->resp_ie_len;
|
||||
wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu,
|
||||
cr->resp_ie);
|
||||
}
|
||||
|
||||
memset(&wrqu, 0, sizeof(wrqu));
|
||||
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
if (bssid && status == WLAN_STATUS_SUCCESS) {
|
||||
memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
|
||||
memcpy(wdev->wext.prev_bssid, bssid, ETH_ALEN);
|
||||
if (cr->bssid && cr->status == WLAN_STATUS_SUCCESS) {
|
||||
memcpy(wrqu.ap_addr.sa_data, cr->bssid, ETH_ALEN);
|
||||
memcpy(wdev->wext.prev_bssid, cr->bssid, ETH_ALEN);
|
||||
wdev->wext.prev_bssid_valid = true;
|
||||
}
|
||||
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!bss && (status == WLAN_STATUS_SUCCESS)) {
|
||||
if (!cr->bss && (cr->status == WLAN_STATUS_SUCCESS)) {
|
||||
WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect);
|
||||
bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
|
||||
wdev->ssid, wdev->ssid_len,
|
||||
wdev->conn_bss_type,
|
||||
IEEE80211_PRIVACY_ANY);
|
||||
if (bss)
|
||||
cfg80211_hold_bss(bss_from_pub(bss));
|
||||
cr->bss = cfg80211_get_bss(wdev->wiphy, NULL, cr->bssid,
|
||||
wdev->ssid, wdev->ssid_len,
|
||||
wdev->conn_bss_type,
|
||||
IEEE80211_PRIVACY_ANY);
|
||||
if (cr->bss)
|
||||
cfg80211_hold_bss(bss_from_pub(cr->bss));
|
||||
}
|
||||
|
||||
if (wdev->current_bss) {
|
||||
|
@ -736,29 +739,29 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
wdev->current_bss = NULL;
|
||||
}
|
||||
|
||||
if (status != WLAN_STATUS_SUCCESS) {
|
||||
if (cr->status != WLAN_STATUS_SUCCESS) {
|
||||
kzfree(wdev->connect_keys);
|
||||
wdev->connect_keys = NULL;
|
||||
wdev->ssid_len = 0;
|
||||
wdev->conn_owner_nlportid = 0;
|
||||
if (bss) {
|
||||
cfg80211_unhold_bss(bss_from_pub(bss));
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
if (cr->bss) {
|
||||
cfg80211_unhold_bss(bss_from_pub(cr->bss));
|
||||
cfg80211_put_bss(wdev->wiphy, cr->bss);
|
||||
}
|
||||
cfg80211_sme_free(wdev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (WARN_ON(!bss))
|
||||
if (WARN_ON(!cr->bss))
|
||||
return;
|
||||
|
||||
wdev->current_bss = bss_from_pub(bss);
|
||||
wdev->current_bss = bss_from_pub(cr->bss);
|
||||
|
||||
if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP))
|
||||
cfg80211_upload_connect_keys(wdev);
|
||||
|
||||
rcu_read_lock();
|
||||
country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
|
||||
country_ie = ieee80211_bss_get_ie(cr->bss, WLAN_EID_COUNTRY);
|
||||
if (!country_ie) {
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
|
@ -775,64 +778,95 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
|||
* - country_ie + 2, the start of the country ie data, and
|
||||
* - and country_ie[1] which is the IE length
|
||||
*/
|
||||
regulatory_hint_country_ie(wdev->wiphy, bss->channel->band,
|
||||
regulatory_hint_country_ie(wdev->wiphy, cr->bss->channel->band,
|
||||
country_ie + 2, country_ie[1]);
|
||||
kfree(country_ie);
|
||||
}
|
||||
|
||||
/* Consumes bss object one way or another */
|
||||
void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
|
||||
struct cfg80211_bss *bss, const u8 *req_ie,
|
||||
size_t req_ie_len, const u8 *resp_ie,
|
||||
size_t resp_ie_len, int status, gfp_t gfp,
|
||||
enum nl80211_timeout_reason timeout_reason)
|
||||
void cfg80211_connect_done(struct net_device *dev,
|
||||
struct cfg80211_connect_resp_params *params,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
struct cfg80211_event *ev;
|
||||
unsigned long flags;
|
||||
u8 *next;
|
||||
|
||||
if (bss) {
|
||||
if (params->bss) {
|
||||
/* Make sure the bss entry provided by the driver is valid. */
|
||||
struct cfg80211_internal_bss *ibss = bss_from_pub(bss);
|
||||
struct cfg80211_internal_bss *ibss = bss_from_pub(params->bss);
|
||||
|
||||
if (WARN_ON(list_empty(&ibss->list))) {
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
cfg80211_put_bss(wdev->wiphy, params->bss);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp);
|
||||
ev = kzalloc(sizeof(*ev) + (params->bssid ? ETH_ALEN : 0) +
|
||||
params->req_ie_len + params->resp_ie_len +
|
||||
params->fils_kek_len + params->pmk_len +
|
||||
(params->pmkid ? WLAN_PMKID_LEN : 0), gfp);
|
||||
if (!ev) {
|
||||
cfg80211_put_bss(wdev->wiphy, bss);
|
||||
cfg80211_put_bss(wdev->wiphy, params->bss);
|
||||
return;
|
||||
}
|
||||
|
||||
ev->type = EVENT_CONNECT_RESULT;
|
||||
if (bssid)
|
||||
memcpy(ev->cr.bssid, bssid, ETH_ALEN);
|
||||
if (req_ie_len) {
|
||||
ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev);
|
||||
ev->cr.req_ie_len = req_ie_len;
|
||||
memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len);
|
||||
next = ((u8 *)ev) + sizeof(*ev);
|
||||
if (params->bssid) {
|
||||
ev->cr.bssid = next;
|
||||
memcpy((void *)ev->cr.bssid, params->bssid, ETH_ALEN);
|
||||
next += ETH_ALEN;
|
||||
}
|
||||
if (resp_ie_len) {
|
||||
ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
|
||||
ev->cr.resp_ie_len = resp_ie_len;
|
||||
memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len);
|
||||
if (params->req_ie_len) {
|
||||
ev->cr.req_ie = next;
|
||||
ev->cr.req_ie_len = params->req_ie_len;
|
||||
memcpy((void *)ev->cr.req_ie, params->req_ie,
|
||||
params->req_ie_len);
|
||||
next += params->req_ie_len;
|
||||
}
|
||||
if (bss)
|
||||
cfg80211_hold_bss(bss_from_pub(bss));
|
||||
ev->cr.bss = bss;
|
||||
ev->cr.status = status;
|
||||
ev->cr.timeout_reason = timeout_reason;
|
||||
if (params->resp_ie_len) {
|
||||
ev->cr.resp_ie = next;
|
||||
ev->cr.resp_ie_len = params->resp_ie_len;
|
||||
memcpy((void *)ev->cr.resp_ie, params->resp_ie,
|
||||
params->resp_ie_len);
|
||||
next += params->resp_ie_len;
|
||||
}
|
||||
if (params->fils_kek_len) {
|
||||
ev->cr.fils_kek = next;
|
||||
ev->cr.fils_kek_len = params->fils_kek_len;
|
||||
memcpy((void *)ev->cr.fils_kek, params->fils_kek,
|
||||
params->fils_kek_len);
|
||||
next += params->fils_kek_len;
|
||||
}
|
||||
if (params->pmk_len) {
|
||||
ev->cr.pmk = next;
|
||||
ev->cr.pmk_len = params->pmk_len;
|
||||
memcpy((void *)ev->cr.pmk, params->pmk, params->pmk_len);
|
||||
next += params->pmk_len;
|
||||
}
|
||||
if (params->pmkid) {
|
||||
ev->cr.pmkid = next;
|
||||
memcpy((void *)ev->cr.pmkid, params->pmkid, WLAN_PMKID_LEN);
|
||||
next += WLAN_PMKID_LEN;
|
||||
}
|
||||
ev->cr.update_erp_next_seq_num = params->update_erp_next_seq_num;
|
||||
if (params->update_erp_next_seq_num)
|
||||
ev->cr.fils_erp_next_seq_num = params->fils_erp_next_seq_num;
|
||||
if (params->bss)
|
||||
cfg80211_hold_bss(bss_from_pub(params->bss));
|
||||
ev->cr.bss = params->bss;
|
||||
ev->cr.status = params->status;
|
||||
ev->cr.timeout_reason = params->timeout_reason;
|
||||
|
||||
spin_lock_irqsave(&wdev->event_lock, flags);
|
||||
list_add_tail(&ev->list, &wdev->event_list);
|
||||
spin_unlock_irqrestore(&wdev->event_lock, flags);
|
||||
queue_work(cfg80211_wq, &rdev->event_work);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_connect_bss);
|
||||
EXPORT_SYMBOL(cfg80211_connect_done);
|
||||
|
||||
/* Consumes bss object one way or another */
|
||||
void __cfg80211_roamed(struct wireless_dev *wdev,
|
||||
|
|
|
@ -1322,6 +1322,28 @@ TRACE_EVENT(rdev_set_cqm_rssi_config,
|
|||
__entry->rssi_thold, __entry->rssi_hyst)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_set_cqm_rssi_range_config,
|
||||
TP_PROTO(struct wiphy *wiphy,
|
||||
struct net_device *netdev, s32 low, s32 high),
|
||||
TP_ARGS(wiphy, netdev, low, high),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
NETDEV_ENTRY
|
||||
__field(s32, rssi_low)
|
||||
__field(s32, rssi_high)
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
NETDEV_ASSIGN;
|
||||
__entry->rssi_low = low;
|
||||
__entry->rssi_high = high;
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT
|
||||
", range: %d - %d ",
|
||||
WIPHY_PR_ARG, NETDEV_PR_ARG,
|
||||
__entry->rssi_low, __entry->rssi_high)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_set_cqm_txe_config,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 rate,
|
||||
u32 pkts, u32 intvl),
|
||||
|
|
|
@ -659,7 +659,7 @@ __ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame,
|
|||
int offset, int len)
|
||||
{
|
||||
struct skb_shared_info *sh = skb_shinfo(skb);
|
||||
const skb_frag_t *frag = &sh->frags[-1];
|
||||
const skb_frag_t *frag = &sh->frags[0];
|
||||
struct page *frag_page;
|
||||
void *frag_ptr;
|
||||
int frag_len, frag_size;
|
||||
|
@ -672,10 +672,10 @@ __ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame,
|
|||
|
||||
while (offset >= frag_size) {
|
||||
offset -= frag_size;
|
||||
frag++;
|
||||
frag_page = skb_frag_page(frag);
|
||||
frag_ptr = skb_frag_address(frag);
|
||||
frag_size = skb_frag_size(frag);
|
||||
frag++;
|
||||
}
|
||||
|
||||
frag_ptr += offset;
|
||||
|
@ -687,12 +687,12 @@ __ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame,
|
|||
len -= cur_len;
|
||||
|
||||
while (len > 0) {
|
||||
frag++;
|
||||
frag_len = skb_frag_size(frag);
|
||||
cur_len = min(len, frag_len);
|
||||
__frame_add_frag(frame, skb_frag_page(frag),
|
||||
skb_frag_address(frag), cur_len, frag_len);
|
||||
len -= cur_len;
|
||||
frag++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -914,11 +914,11 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
|
|||
netdev_err(dev, "failed to set key %d\n", i);
|
||||
continue;
|
||||
}
|
||||
if (wdev->connect_keys->def == i)
|
||||
if (rdev_set_default_key(rdev, dev, i, true, true)) {
|
||||
netdev_err(dev, "failed to set defkey %d\n", i);
|
||||
continue;
|
||||
}
|
||||
if (wdev->connect_keys->def == i &&
|
||||
rdev_set_default_key(rdev, dev, i, true, true)) {
|
||||
netdev_err(dev, "failed to set defkey %d\n", i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
kzfree(wdev->connect_keys);
|
||||
|
@ -929,7 +929,6 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
|
|||
{
|
||||
struct cfg80211_event *ev;
|
||||
unsigned long flags;
|
||||
const u8 *bssid = NULL;
|
||||
|
||||
spin_lock_irqsave(&wdev->event_lock, flags);
|
||||
while (!list_empty(&wdev->event_list)) {
|
||||
|
@ -941,15 +940,10 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
|
|||
wdev_lock(wdev);
|
||||
switch (ev->type) {
|
||||
case EVENT_CONNECT_RESULT:
|
||||
if (!is_zero_ether_addr(ev->cr.bssid))
|
||||
bssid = ev->cr.bssid;
|
||||
__cfg80211_connect_result(
|
||||
wdev->netdev, bssid,
|
||||
ev->cr.req_ie, ev->cr.req_ie_len,
|
||||
ev->cr.resp_ie, ev->cr.resp_ie_len,
|
||||
ev->cr.status,
|
||||
ev->cr.status == WLAN_STATUS_SUCCESS,
|
||||
ev->cr.bss, ev->cr.timeout_reason);
|
||||
wdev->netdev,
|
||||
&ev->cr,
|
||||
ev->cr.status == WLAN_STATUS_SUCCESS);
|
||||
break;
|
||||
case EVENT_ROAMED:
|
||||
__cfg80211_roamed(wdev, ev->rm.bss, ev->rm.req_ie,
|
||||
|
@ -991,7 +985,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev)
|
|||
|
||||
int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, enum nl80211_iftype ntype,
|
||||
u32 *flags, struct vif_params *params)
|
||||
struct vif_params *params)
|
||||
{
|
||||
int err;
|
||||
enum nl80211_iftype otype = dev->ieee80211_ptr->iftype;
|
||||
|
@ -1049,7 +1043,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
|||
cfg80211_process_rdev_events(rdev);
|
||||
}
|
||||
|
||||
err = rdev_change_virtual_intf(rdev, dev, ntype, flags, params);
|
||||
err = rdev_change_virtual_intf(rdev, dev, ntype, params);
|
||||
|
||||
WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
|
||||
|
||||
|
@ -1097,6 +1091,35 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
|||
return err;
|
||||
}
|
||||
|
||||
static u32 cfg80211_calculate_bitrate_ht(struct rate_info *rate)
|
||||
{
|
||||
int modulation, streams, bitrate;
|
||||
|
||||
/* the formula below does only work for MCS values smaller than 32 */
|
||||
if (WARN_ON_ONCE(rate->mcs >= 32))
|
||||
return 0;
|
||||
|
||||
modulation = rate->mcs & 7;
|
||||
streams = (rate->mcs >> 3) + 1;
|
||||
|
||||
bitrate = (rate->bw == RATE_INFO_BW_40) ? 13500000 : 6500000;
|
||||
|
||||
if (modulation < 4)
|
||||
bitrate *= (modulation + 1);
|
||||
else if (modulation == 4)
|
||||
bitrate *= (modulation + 2);
|
||||
else
|
||||
bitrate *= (modulation + 3);
|
||||
|
||||
bitrate *= streams;
|
||||
|
||||
if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
|
||||
bitrate = (bitrate / 9) * 10;
|
||||
|
||||
/* do NOT round down here */
|
||||
return (bitrate + 50000) / 100000;
|
||||
}
|
||||
|
||||
static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate)
|
||||
{
|
||||
static const u32 __mcs2bitrate[] = {
|
||||
|
@ -1230,39 +1253,14 @@ static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
|
|||
|
||||
u32 cfg80211_calculate_bitrate(struct rate_info *rate)
|
||||
{
|
||||
int modulation, streams, bitrate;
|
||||
|
||||
if (!(rate->flags & RATE_INFO_FLAGS_MCS) &&
|
||||
!(rate->flags & RATE_INFO_FLAGS_VHT_MCS))
|
||||
return rate->legacy;
|
||||
if (rate->flags & RATE_INFO_FLAGS_MCS)
|
||||
return cfg80211_calculate_bitrate_ht(rate);
|
||||
if (rate->flags & RATE_INFO_FLAGS_60G)
|
||||
return cfg80211_calculate_bitrate_60g(rate);
|
||||
if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
|
||||
return cfg80211_calculate_bitrate_vht(rate);
|
||||
|
||||
/* the formula below does only work for MCS values smaller than 32 */
|
||||
if (WARN_ON_ONCE(rate->mcs >= 32))
|
||||
return 0;
|
||||
|
||||
modulation = rate->mcs & 7;
|
||||
streams = (rate->mcs >> 3) + 1;
|
||||
|
||||
bitrate = (rate->bw == RATE_INFO_BW_40) ? 13500000 : 6500000;
|
||||
|
||||
if (modulation < 4)
|
||||
bitrate *= (modulation + 1);
|
||||
else if (modulation == 4)
|
||||
bitrate *= (modulation + 2);
|
||||
else
|
||||
bitrate *= (modulation + 3);
|
||||
|
||||
bitrate *= streams;
|
||||
|
||||
if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
|
||||
bitrate = (bitrate / 9) * 10;
|
||||
|
||||
/* do NOT round down here */
|
||||
return (bitrate + 50000) / 100000;
|
||||
return rate->legacy;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_calculate_bitrate);
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
|
|||
|
||||
memset(&vifparams, 0, sizeof(vifparams));
|
||||
|
||||
return cfg80211_change_iface(rdev, dev, type, NULL, &vifparams);
|
||||
return cfg80211_change_iface(rdev, dev, type, &vifparams);
|
||||
}
|
||||
EXPORT_WEXT_HANDLER(cfg80211_wext_siwmode);
|
||||
|
||||
|
|
Loading…
Reference in New Issue