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:
David S. Miller 2017-04-20 13:54:40 -04:00
commit 028f43bc64
84 changed files with 1802 additions and 540 deletions

View File

@ -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

View File

@ -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",

View File

@ -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);

View File

@ -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);

View File

@ -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.

View File

@ -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);

View File

@ -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)

View File

@ -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,

View File

@ -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:

View File

@ -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;
}

View File

@ -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;

View File

@ -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",

View File

@ -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);

View File

@ -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));

View File

@ -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;

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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",

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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");

View File

@ -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);

View File

@ -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);

View File

@ -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");

View File

@ -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;

View File

@ -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.
*/

View File

@ -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) {

View File

@ -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");

View File

@ -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",

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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(&params, 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, &params, 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,

View File

@ -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;

View File

@ -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,
};
/**

View File

@ -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 =

View File

@ -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++;

View File

@ -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,

View File

@ -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;
}

View File

@ -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;
/*

View File

@ -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;
}

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -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);
}

View File

@ -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");

View File

@ -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);
}

View File

@ -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,

View File

@ -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) {

View File

@ -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 */
};

View File

@ -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)

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -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 */

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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],
&params->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(&params, 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, &params);
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, &params);
err = cfg80211_change_iface(rdev, dev, ntype, &params);
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, &params);
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,
&params);
NET_NAME_USER, type, &params);
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;

View File

@ -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,

View File

@ -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)

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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,

View File

@ -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),

View File

@ -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);

View File

@ -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);