Commit 7eb2450a authored by John W. Linville's avatar John W. Linville
parents 474a41e9 73fb08e2
...@@ -154,6 +154,10 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2) ...@@ -154,6 +154,10 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2)
802.11e clarifies the figure in section 7.1.2. The frame body is 802.11e clarifies the figure in section 7.1.2. The frame body is
up to 2304 octets long (maximum MSDU size) plus any crypt overhead. */ up to 2304 octets long (maximum MSDU size) plus any crypt overhead. */
#define IEEE80211_MAX_DATA_LEN 2304 #define IEEE80211_MAX_DATA_LEN 2304
/* 802.11ad extends maximum MSDU size for DMG (freq > 40Ghz) networks
* to 7920 bytes, see 8.2.3 General frame format
*/
#define IEEE80211_MAX_DATA_LEN_DMG 7920
/* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */ /* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */
#define IEEE80211_MAX_FRAME_LEN 2352 #define IEEE80211_MAX_FRAME_LEN 2352
......
...@@ -151,6 +151,7 @@ enum ieee80211_channel_flags { ...@@ -151,6 +151,7 @@ enum ieee80211_channel_flags {
* @dfs_state: current state of this channel. Only relevant if radar is required * @dfs_state: current state of this channel. Only relevant if radar is required
* on this channel. * on this channel.
* @dfs_state_entered: timestamp (jiffies) when the dfs state was entered. * @dfs_state_entered: timestamp (jiffies) when the dfs state was entered.
* @dfs_cac_ms: DFS CAC time in milliseconds, this is valid for DFS channels.
*/ */
struct ieee80211_channel { struct ieee80211_channel {
enum ieee80211_band band; enum ieee80211_band band;
...@@ -165,6 +166,7 @@ struct ieee80211_channel { ...@@ -165,6 +166,7 @@ struct ieee80211_channel {
int orig_mag, orig_mpwr; int orig_mag, orig_mpwr;
enum nl80211_dfs_state dfs_state; enum nl80211_dfs_state dfs_state;
unsigned long dfs_state_entered; unsigned long dfs_state_entered;
unsigned int dfs_cac_ms;
}; };
/** /**
...@@ -2503,7 +2505,8 @@ struct cfg80211_ops { ...@@ -2503,7 +2505,8 @@ struct cfg80211_ops {
int (*start_radar_detection)(struct wiphy *wiphy, int (*start_radar_detection)(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
struct cfg80211_chan_def *chandef); struct cfg80211_chan_def *chandef,
u32 cac_time_ms);
int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev, int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_update_ft_ies_params *ftie); struct cfg80211_update_ft_ies_params *ftie);
int (*crit_proto_start)(struct wiphy *wiphy, int (*crit_proto_start)(struct wiphy *wiphy,
...@@ -3180,6 +3183,7 @@ struct cfg80211_cached_keys; ...@@ -3180,6 +3183,7 @@ struct cfg80211_cached_keys;
* @p2p_started: true if this is a P2P Device that has been started * @p2p_started: true if this is a P2P Device that has been started
* @cac_started: true if DFS channel availability check has been started * @cac_started: true if DFS channel availability check has been started
* @cac_start_time: timestamp (jiffies) when the dfs state was entered. * @cac_start_time: timestamp (jiffies) when the dfs state was entered.
* @cac_time_ms: CAC time in ms
* @ps: powersave mode is enabled * @ps: powersave mode is enabled
* @ps_timeout: dynamic powersave timeout * @ps_timeout: dynamic powersave timeout
* @ap_unexpected_nlportid: (private) netlink port ID of application * @ap_unexpected_nlportid: (private) netlink port ID of application
...@@ -3235,6 +3239,7 @@ struct wireless_dev { ...@@ -3235,6 +3239,7 @@ struct wireless_dev {
bool cac_started; bool cac_started;
unsigned long cac_start_time; unsigned long cac_start_time;
unsigned int cac_time_ms;
#ifdef CONFIG_CFG80211_WEXT #ifdef CONFIG_CFG80211_WEXT
/* wext data */ /* wext data */
...@@ -3667,7 +3672,7 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy); ...@@ -3667,7 +3672,7 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy);
* cfg80211_inform_bss_width_frame - inform cfg80211 of a received BSS frame * cfg80211_inform_bss_width_frame - inform cfg80211 of a received BSS frame
* *
* @wiphy: the wiphy reporting the BSS * @wiphy: the wiphy reporting the BSS
* @channel: The channel the frame was received on * @rx_channel: The channel the frame was received on
* @scan_width: width of the control channel * @scan_width: width of the control channel
* @mgmt: the management frame (probe response or beacon) * @mgmt: the management frame (probe response or beacon)
* @len: length of the management frame * @len: length of the management frame
...@@ -3682,18 +3687,18 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy); ...@@ -3682,18 +3687,18 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy);
*/ */
struct cfg80211_bss * __must_check struct cfg80211_bss * __must_check
cfg80211_inform_bss_width_frame(struct wiphy *wiphy, cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
struct ieee80211_channel *channel, struct ieee80211_channel *rx_channel,
enum nl80211_bss_scan_width scan_width, enum nl80211_bss_scan_width scan_width,
struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_mgmt *mgmt, size_t len,
s32 signal, gfp_t gfp); s32 signal, gfp_t gfp);
static inline struct cfg80211_bss * __must_check static inline struct cfg80211_bss * __must_check
cfg80211_inform_bss_frame(struct wiphy *wiphy, cfg80211_inform_bss_frame(struct wiphy *wiphy,
struct ieee80211_channel *channel, struct ieee80211_channel *rx_channel,
struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_mgmt *mgmt, size_t len,
s32 signal, gfp_t gfp) s32 signal, gfp_t gfp)
{ {
return cfg80211_inform_bss_width_frame(wiphy, channel, return cfg80211_inform_bss_width_frame(wiphy, rx_channel,
NL80211_BSS_CHAN_WIDTH_20, NL80211_BSS_CHAN_WIDTH_20,
mgmt, len, signal, gfp); mgmt, len, signal, gfp);
} }
...@@ -3702,7 +3707,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, ...@@ -3702,7 +3707,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
* cfg80211_inform_bss - inform cfg80211 of a new BSS * cfg80211_inform_bss - inform cfg80211 of a new BSS
* *
* @wiphy: the wiphy reporting the BSS * @wiphy: the wiphy reporting the BSS
* @channel: The channel the frame was received on * @rx_channel: The channel the frame was received on
* @scan_width: width of the control channel * @scan_width: width of the control channel
* @bssid: the BSSID of the BSS * @bssid: the BSSID of the BSS
* @tsf: the TSF sent by the peer in the beacon/probe response (or 0) * @tsf: the TSF sent by the peer in the beacon/probe response (or 0)
...@@ -3721,7 +3726,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, ...@@ -3721,7 +3726,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
*/ */
struct cfg80211_bss * __must_check struct cfg80211_bss * __must_check
cfg80211_inform_bss_width(struct wiphy *wiphy, cfg80211_inform_bss_width(struct wiphy *wiphy,
struct ieee80211_channel *channel, struct ieee80211_channel *rx_channel,
enum nl80211_bss_scan_width scan_width, enum nl80211_bss_scan_width scan_width,
const u8 *bssid, u64 tsf, u16 capability, const u8 *bssid, u64 tsf, u16 capability,
u16 beacon_interval, const u8 *ie, size_t ielen, u16 beacon_interval, const u8 *ie, size_t ielen,
...@@ -3729,12 +3734,12 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, ...@@ -3729,12 +3734,12 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
static inline struct cfg80211_bss * __must_check static inline struct cfg80211_bss * __must_check
cfg80211_inform_bss(struct wiphy *wiphy, cfg80211_inform_bss(struct wiphy *wiphy,
struct ieee80211_channel *channel, struct ieee80211_channel *rx_channel,
const u8 *bssid, u64 tsf, u16 capability, const u8 *bssid, u64 tsf, u16 capability,
u16 beacon_interval, const u8 *ie, size_t ielen, u16 beacon_interval, const u8 *ie, size_t ielen,
s32 signal, gfp_t gfp) s32 signal, gfp_t gfp)
{ {
return cfg80211_inform_bss_width(wiphy, channel, return cfg80211_inform_bss_width(wiphy, rx_channel,
NL80211_BSS_CHAN_WIDTH_20, NL80211_BSS_CHAN_WIDTH_20,
bssid, tsf, capability, bssid, tsf, capability,
beacon_interval, ie, ielen, signal, beacon_interval, ie, ielen, signal,
......
...@@ -697,11 +697,11 @@ struct ieee80211_tx_info { ...@@ -697,11 +697,11 @@ struct ieee80211_tx_info {
} control; } control;
struct { struct {
struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES]; struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];
int ack_signal; s32 ack_signal;
u8 ampdu_ack_len; u8 ampdu_ack_len;
u8 ampdu_len; u8 ampdu_len;
u8 antenna; u8 antenna;
/* 21 bytes free */ void *status_driver_data[21 / sizeof(void *)];
} status; } status;
struct { struct {
struct ieee80211_tx_rate driver_rates[ struct ieee80211_tx_rate driver_rates[
...@@ -877,11 +877,13 @@ enum mac80211_rx_flags { ...@@ -877,11 +877,13 @@ enum mac80211_rx_flags {
* @RX_VHT_FLAG_80MHZ: 80 MHz was used * @RX_VHT_FLAG_80MHZ: 80 MHz was used
* @RX_VHT_FLAG_80P80MHZ: 80+80 MHz was used * @RX_VHT_FLAG_80P80MHZ: 80+80 MHz was used
* @RX_VHT_FLAG_160MHZ: 160 MHz was used * @RX_VHT_FLAG_160MHZ: 160 MHz was used
* @RX_VHT_FLAG_BF: packet was beamformed
*/ */
enum mac80211_rx_vht_flags { enum mac80211_rx_vht_flags {
RX_VHT_FLAG_80MHZ = BIT(0), RX_VHT_FLAG_80MHZ = BIT(0),
RX_VHT_FLAG_80P80MHZ = BIT(1), RX_VHT_FLAG_80P80MHZ = BIT(1),
RX_VHT_FLAG_160MHZ = BIT(2), RX_VHT_FLAG_160MHZ = BIT(2),
RX_VHT_FLAG_BF = BIT(3),
}; };
/** /**
......
...@@ -155,6 +155,7 @@ struct ieee80211_reg_rule { ...@@ -155,6 +155,7 @@ struct ieee80211_reg_rule {
struct ieee80211_freq_range freq_range; struct ieee80211_freq_range freq_range;
struct ieee80211_power_rule power_rule; struct ieee80211_power_rule power_rule;
u32 flags; u32 flags;
u32 dfs_cac_ms;
}; };
struct ieee80211_regdomain { struct ieee80211_regdomain {
...@@ -172,14 +173,18 @@ struct ieee80211_regdomain { ...@@ -172,14 +173,18 @@ struct ieee80211_regdomain {
#define DBM_TO_MBM(gain) ((gain) * 100) #define DBM_TO_MBM(gain) ((gain) * 100)
#define MBM_TO_DBM(gain) ((gain) / 100) #define MBM_TO_DBM(gain) ((gain) / 100)
#define REG_RULE(start, end, bw, gain, eirp, reg_flags) \ #define REG_RULE_EXT(start, end, bw, gain, eirp, dfs_cac, reg_flags) \
{ \ { \
.freq_range.start_freq_khz = MHZ_TO_KHZ(start), \ .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \
.freq_range.end_freq_khz = MHZ_TO_KHZ(end), \ .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \
.freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \ .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \
.power_rule.max_antenna_gain = DBI_TO_MBI(gain),\ .power_rule.max_antenna_gain = DBI_TO_MBI(gain), \
.power_rule.max_eirp = DBM_TO_MBM(eirp), \ .power_rule.max_eirp = DBM_TO_MBM(eirp), \
.flags = reg_flags, \ .flags = reg_flags, \
.dfs_cac_ms = dfs_cac, \
} }
#define REG_RULE(start, end, bw, gain, eirp, reg_flags) \
REG_RULE_EXT(start, end, bw, gain, eirp, 0, reg_flags)
#endif #endif
...@@ -2335,6 +2335,7 @@ enum nl80211_band_attr { ...@@ -2335,6 +2335,7 @@ enum nl80211_band_attr {
* @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel * @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel
* using this channel as the primary or any of the secondary channels * using this channel as the primary or any of the secondary channels
* isn't possible * isn't possible
* @NL80211_FREQUENCY_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined * currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
...@@ -2353,6 +2354,7 @@ enum nl80211_frequency_attr { ...@@ -2353,6 +2354,7 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_NO_HT40_PLUS, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS,
NL80211_FREQUENCY_ATTR_NO_80MHZ, NL80211_FREQUENCY_ATTR_NO_80MHZ,
NL80211_FREQUENCY_ATTR_NO_160MHZ, NL80211_FREQUENCY_ATTR_NO_160MHZ,
NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
/* keep last */ /* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST, __NL80211_FREQUENCY_ATTR_AFTER_LAST,
...@@ -2449,6 +2451,8 @@ enum nl80211_reg_type { ...@@ -2449,6 +2451,8 @@ enum nl80211_reg_type {
* If you don't have one then don't send this. * If you don't have one then don't send this.
* @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
* a given frequency range. The value is in mBm (100 * dBm). * a given frequency range. The value is in mBm (100 * dBm).
* @NL80211_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds.
* If not present or 0 default CAC time will be used.
* @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number
* currently defined * currently defined
* @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use
...@@ -2464,6 +2468,8 @@ enum nl80211_reg_rule_attr { ...@@ -2464,6 +2468,8 @@ enum nl80211_reg_rule_attr {
NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
NL80211_ATTR_POWER_RULE_MAX_EIRP, NL80211_ATTR_POWER_RULE_MAX_EIRP,
NL80211_ATTR_DFS_CAC_TIME,
/* keep last */ /* keep last */
__NL80211_REG_RULE_ATTR_AFTER_LAST, __NL80211_REG_RULE_ATTR_AFTER_LAST,
NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1 NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
......
...@@ -2914,11 +2914,11 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, ...@@ -2914,11 +2914,11 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
static int ieee80211_start_radar_detection(struct wiphy *wiphy, static int ieee80211_start_radar_detection(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef,
u32 cac_time_ms)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
unsigned long timeout;
int err; int err;
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
...@@ -2937,9 +2937,9 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy, ...@@ -2937,9 +2937,9 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
if (err) if (err)
goto out_unlock; goto out_unlock;
timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS);
ieee80211_queue_delayed_work(&sdata->local->hw, ieee80211_queue_delayed_work(&sdata->local->hw,
&sdata->dfs_cac_timer_work, timeout); &sdata->dfs_cac_timer_work,
msecs_to_jiffies(cac_time_ms));
out_unlock: out_unlock:
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
...@@ -3089,52 +3089,11 @@ void ieee80211_csa_finalize_work(struct work_struct *work) ...@@ -3089,52 +3089,11 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
sdata_unlock(sdata); sdata_unlock(sdata);
} }
int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
struct cfg80211_csa_settings *params) struct cfg80211_csa_settings *params,
u32 *changed)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); int err;
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_chanctx *chanctx;
struct ieee80211_if_mesh __maybe_unused *ifmsh;
int err, num_chanctx, changed = 0;
sdata_assert_lock(sdata);
if (!list_empty(&local->roc_list) || local->scanning)
return -EBUSY;
if (sdata->wdev.cac_started)
return -EBUSY;
if (cfg80211_chandef_identical(&params->chandef,
&sdata->vif.bss_conf.chandef))
return -EINVAL;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf) {
rcu_read_unlock();
return -EBUSY;
}
/* don't handle for multi-VIF cases */
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
if (chanctx->refcount > 1) {
rcu_read_unlock();
return -EBUSY;
}
num_chanctx = 0;
list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
num_chanctx++;
rcu_read_unlock();
if (num_chanctx > 1)
return -EBUSY;
/* don't allow another channel switch if one is already active. */
if (sdata->vif.csa_active)
return -EBUSY;
switch (sdata->vif.type) { switch (sdata->vif.type) {
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
...@@ -3170,7 +3129,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, ...@@ -3170,7 +3129,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
kfree(sdata->u.ap.next_beacon); kfree(sdata->u.ap.next_beacon);
return err; return err;
} }
changed |= err; *changed |= err;
break; break;
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
...@@ -3204,15 +3163,15 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, ...@@ -3204,15 +3163,15 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
err = ieee80211_ibss_csa_beacon(sdata, params); err = ieee80211_ibss_csa_beacon(sdata, params);
if (err < 0) if (err < 0)
return err; return err;
changed |= err; *changed |= err;
} }
ieee80211_send_action_csa(sdata, params); ieee80211_send_action_csa(sdata, params);
break; break;
#ifdef CONFIG_MAC80211_MESH #ifdef CONFIG_MAC80211_MESH
case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MESH_POINT: {
ifmsh = &sdata->u.mesh; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
if (params->chandef.width != sdata->vif.bss_conf.chandef.width) if (params->chandef.width != sdata->vif.bss_conf.chandef.width)
return -EINVAL; return -EINVAL;
...@@ -3237,18 +3196,72 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, ...@@ -3237,18 +3196,72 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
return err; return err;
} }
changed |= err; *changed |= err;
} }
if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT) if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT)
ieee80211_send_action_csa(sdata, params); ieee80211_send_action_csa(sdata, params);
break; break;
}
#endif #endif
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
return 0;
}
int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_csa_settings *params)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_chanctx *chanctx;
int err, num_chanctx, changed = 0;
sdata_assert_lock(sdata);
if (!list_empty(&local->roc_list) || local->scanning)
return -EBUSY;
if (sdata->wdev.cac_started)
return -EBUSY;
if (cfg80211_chandef_identical(&params->chandef,
&sdata->vif.bss_conf.chandef))
return -EINVAL;
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (!chanctx_conf) {
rcu_read_unlock();
return -EBUSY;
}
/* don't handle for multi-VIF cases */
chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
if (chanctx->refcount > 1) {
rcu_read_unlock();
return -EBUSY;
}
num_chanctx = 0;
list_for_each_entry_rcu(chanctx, &local->chanctx_list, list)
num_chanctx++;
rcu_read_unlock();
if (num_chanctx > 1)
return -EBUSY;
/* don't allow another channel switch if one is already active. */
if (sdata->vif.csa_active)
return -EBUSY;
err = ieee80211_set_csa_beacon(sdata, params, &changed);
if (err)
return err;
sdata->csa_radar_required = params->radar_required; sdata->csa_radar_required = params->radar_required;
if (params->block_tx) if (params->block_tx)
......
...@@ -991,7 +991,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, ...@@ -991,7 +991,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems) struct ieee802_11_elems *elems)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
int freq;
struct cfg80211_bss *cbss; struct cfg80211_bss *cbss;
struct ieee80211_bss *bss; struct ieee80211_bss *bss;
struct sta_info *sta; struct sta_info *sta;
...@@ -1003,15 +1002,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, ...@@ -1003,15 +1002,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
bool rates_updated = false; bool rates_updated = false;
if (elems->ds_params) channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
freq = ieee80211_channel_to_frequency(elems->ds_params[0], if (!channel)
band);
else
freq = rx_status->freq;
channel = ieee80211_get_channel(local->hw.wiphy, freq);
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
return; return;
if (sdata->vif.type == NL80211_IFTYPE_ADHOC && if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
......
...@@ -1391,6 +1391,7 @@ void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata); ...@@ -1391,6 +1391,7 @@ void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata);
void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata); void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata);
void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata, void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata,
__le16 fc, bool acked); __le16 fc, bool acked);
void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
/* IBSS code */ /* IBSS code */
......
...@@ -2783,28 +2783,20 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, ...@@ -2783,28 +2783,20 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems) struct ieee802_11_elems *elems)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
int freq;
struct ieee80211_bss *bss; struct ieee80211_bss *bss;
struct ieee80211_channel *channel; struct ieee80211_channel *channel;
sdata_assert_lock(sdata); sdata_assert_lock(sdata);
if (elems->ds_params) channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
freq = ieee80211_channel_to_frequency(elems->ds_params[0], if (!channel)
rx_status->band);
else
freq = rx_status->freq;
channel = ieee80211_get_channel(local->hw.wiphy, freq);
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
return; return;
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
channel); channel);
if (bss) { if (bss) {
ieee80211_rx_bss_put(local, bss);
sdata->vif.bss_conf.beacon_rate = bss->beacon_rate; sdata->vif.bss_conf.beacon_rate = bss->beacon_rate;
ieee80211_rx_bss_put(local, bss);
} }
} }
...@@ -3599,6 +3591,32 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) ...@@ -3599,6 +3591,32 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
sdata_lock(sdata);
if (ifmgd->auth_data) {
/*
* If we are trying to authenticate while suspending, cfg80211
* won't know and won't actually abort those attempts, thus we
* need to do that ourselves.
*/
ieee80211_send_deauth_disassoc(sdata,
ifmgd->auth_data->bss->bssid,
IEEE80211_STYPE_DEAUTH,
WLAN_REASON_DEAUTH_LEAVING,
false, frame_buf);
ieee80211_destroy_auth_data(sdata, false);
cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
IEEE80211_DEAUTH_FRAME_LEN);
}
sdata_unlock(sdata);
}
void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
{ {
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
...@@ -4417,37 +4435,41 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, ...@@ -4417,37 +4435,41 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
bool tx = !req->local_state_change; bool tx = !req->local_state_change;
bool report_frame = false;
sdata_info(sdata, if (ifmgd->auth_data &&
"deauthenticating from %pM by local choice (Reason: %u=%s)\n", ether_addr_equal(ifmgd->auth_data->bss->bssid, req->bssid)) {
req->bssid, req->reason_code, ieee80211_get_reason_code_string(req->reason_code)); sdata_info(sdata,
"aborting authentication with %pM by local choice (Reason: %u=%s)\n",
req->bssid, req->reason_code,
ieee80211_get_reason_code_string(req->reason_code));
if (ifmgd->auth_data) {
drv_mgd_prepare_tx(sdata->local, sdata); drv_mgd_prepare_tx(sdata->local, sdata);
ieee80211_send_deauth_disassoc(sdata, req->bssid, ieee80211_send_deauth_disassoc(sdata, req->bssid,
IEEE80211_STYPE_DEAUTH, IEEE80211_STYPE_DEAUTH,
req->reason_code, tx, req->reason_code, tx,
frame_buf); frame_buf);
ieee80211_destroy_auth_data(sdata, false); ieee80211_destroy_auth_data(sdata, false);
cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
IEEE80211_DEAUTH_FRAME_LEN);
report_frame = true; return 0;
goto out;
} }
if (ifmgd->associated && if (ifmgd->associated &&
ether_addr_equal(ifmgd->associated->bssid, req->bssid)) { ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
sdata_info(sdata,
"deauthenticating from %pM by local choice (Reason: %u=%s)\n",
req->bssid, req->reason_code,
ieee80211_get_reason_code_string(req->reason_code));
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
req->reason_code, tx, frame_buf); req->reason_code, tx, frame_buf);
report_frame = true;
}
out:
if (report_frame)
cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
IEEE80211_DEAUTH_FRAME_LEN); IEEE80211_DEAUTH_FRAME_LEN);
return 0;
}
return 0; return -ENOTCONN;
} }
int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
......
...@@ -100,10 +100,18 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) ...@@ -100,10 +100,18 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
/* remove all interfaces that were created in the driver */ /* remove all interfaces that were created in the driver */
list_for_each_entry(sdata, &local->interfaces, list) { list_for_each_entry(sdata, &local->interfaces, list) {
if (!ieee80211_sdata_running(sdata) || if (!ieee80211_sdata_running(sdata))
sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
sdata->vif.type == NL80211_IFTYPE_MONITOR)
continue; continue;
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_MONITOR:
continue;
case NL80211_IFTYPE_STATION:
ieee80211_mgd_quiesce(sdata);
break;
default:
break;
}
drv_remove_interface(local, sdata); drv_remove_interface(local, sdata);
} }
......
...@@ -333,6 +333,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, ...@@ -333,6 +333,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
/* in VHT, STBC is binary */ /* in VHT, STBC is binary */
if (status->flag & RX_FLAG_STBC_MASK) if (status->flag & RX_FLAG_STBC_MASK)
*pos |= IEEE80211_RADIOTAP_VHT_FLAG_STBC; *pos |= IEEE80211_RADIOTAP_VHT_FLAG_STBC;
if (status->vht_flag & RX_VHT_FLAG_BF)
*pos |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED;
pos++; pos++;
/* bandwidth */ /* bandwidth */
if (status->vht_flag & RX_VHT_FLAG_80MHZ) if (status->vht_flag & RX_VHT_FLAG_80MHZ)
...@@ -1245,6 +1247,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) ...@@ -1245,6 +1247,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
if (ieee80211_is_data(hdr->frame_control)) { if (ieee80211_is_data(hdr->frame_control)) {
sta->last_rx_rate_idx = status->rate_idx; sta->last_rx_rate_idx = status->rate_idx;
sta->last_rx_rate_flag = status->flag; sta->last_rx_rate_flag = status->flag;
sta->last_rx_rate_vht_flag = status->vht_flag;
sta->last_rx_rate_vht_nss = status->vht_nss; sta->last_rx_rate_vht_nss = status->vht_nss;
} }
} }
......
...@@ -1055,9 +1055,11 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) ...@@ -1055,9 +1055,11 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
/* We don't want to restart sched scan anymore. */ /* We don't want to restart sched scan anymore. */
local->sched_scan_req = NULL; local->sched_scan_req = NULL;
if (rcu_access_pointer(local->sched_scan_sdata)) if (rcu_access_pointer(local->sched_scan_sdata)) {
ret = drv_sched_scan_stop(local, sdata); ret = drv_sched_scan_stop(local, sdata);
if (!ret)
rcu_assign_pointer(local->sched_scan_sdata, NULL);
}
out: out:
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
......
...@@ -2900,7 +2900,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, ...@@ -2900,7 +2900,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
cpu_to_le16(IEEE80211_FCTL_MOREDATA); cpu_to_le16(IEEE80211_FCTL_MOREDATA);
} }
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) if (sdata->vif.type == NL80211_IFTYPE_AP)
sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev); sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
if (!ieee80211_tx_prepare(sdata, &tx, skb)) if (!ieee80211_tx_prepare(sdata, &tx, skb))
break; break;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
struct net_device *dev) struct net_device *dev, bool notify)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
int err; int err;
...@@ -30,20 +30,21 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, ...@@ -30,20 +30,21 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
memset(&wdev->chandef, 0, sizeof(wdev->chandef)); memset(&wdev->chandef, 0, sizeof(wdev->chandef));
wdev->ssid_len = 0; wdev->ssid_len = 0;
rdev_set_qos_map(rdev, dev, NULL); rdev_set_qos_map(rdev, dev, NULL);
nl80211_send_ap_stopped(wdev); if (notify)
nl80211_send_ap_stopped(wdev);
} }
return err; return err;
} }
int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
struct net_device *dev) struct net_device *dev, bool notify)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
int err; int err;
wdev_lock(wdev); wdev_lock(wdev);
err = __cfg80211_stop_ap(rdev, dev); err = __cfg80211_stop_ap(rdev, dev, notify);
wdev_unlock(wdev); wdev_unlock(wdev);
return err; return err;
......
...@@ -490,6 +490,62 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy, ...@@ -490,6 +490,62 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
return r; return r;
} }
static unsigned int cfg80211_get_chans_dfs_cac_time(struct wiphy *wiphy,
u32 center_freq,
u32 bandwidth)
{
struct ieee80211_channel *c;
u32 start_freq, end_freq, freq;
unsigned int dfs_cac_ms = 0;
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
for (freq = start_freq; freq <= end_freq; freq += 20) {
c = ieee80211_get_channel(wiphy, freq);
if (!c)
return 0;
if (c->flags & IEEE80211_CHAN_DISABLED)
return 0;
if (!(c->flags & IEEE80211_CHAN_RADAR))
continue;
if (c->dfs_cac_ms > dfs_cac_ms)
dfs_cac_ms = c->dfs_cac_ms;
}
return dfs_cac_ms;
}
unsigned int
cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef)
{
int width;
unsigned int t1 = 0, t2 = 0;
if (WARN_ON(!cfg80211_chandef_valid(chandef)))
return 0;
width = cfg80211_chandef_get_width(chandef);
if (width < 0)
return 0;
t1 = cfg80211_get_chans_dfs_cac_time(wiphy,
chandef->center_freq1,
width);
if (!chandef->center_freq2)
return t1;
t2 = cfg80211_get_chans_dfs_cac_time(wiphy,
chandef->center_freq2,
width);
return max(t1, t2);
}
static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
u32 center_freq, u32 bandwidth, u32 center_freq, u32 bandwidth,
......
...@@ -783,7 +783,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, ...@@ -783,7 +783,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
break; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_GO:
cfg80211_stop_ap(rdev, dev); cfg80211_stop_ap(rdev, dev, true);
break; break;
default: default:
break; break;
......
...@@ -166,7 +166,6 @@ static inline void wdev_unlock(struct wireless_dev *wdev) ...@@ -166,7 +166,6 @@ static inline void wdev_unlock(struct wireless_dev *wdev)
mutex_unlock(&wdev->mtx); mutex_unlock(&wdev->mtx);
} }
#define ASSERT_RDEV_LOCK(rdev) ASSERT_RTNL()
#define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx)
static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev) static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev)
...@@ -246,10 +245,6 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev, ...@@ -246,10 +245,6 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev,
unsigned long age_secs); unsigned long age_secs);
/* IBSS */ /* IBSS */
int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_ibss_params *params,
struct cfg80211_cached_keys *connkeys);
int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
struct net_device *dev, struct net_device *dev,
struct cfg80211_ibss_params *params, struct cfg80211_ibss_params *params,
...@@ -283,7 +278,7 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, ...@@ -283,7 +278,7 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
/* AP */ /* AP */
int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
struct net_device *dev); struct net_device *dev, bool notify);
/* MLME */ /* MLME */
int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
...@@ -402,6 +397,9 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy, ...@@ -402,6 +397,9 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy,
void cfg80211_dfs_channels_update_work(struct work_struct *work); void cfg80211_dfs_channels_update_work(struct work_struct *work);
unsigned int
cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef);
static inline int static inline int
cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
......
...@@ -66,6 +66,7 @@ function parse_reg_rule() ...@@ -66,6 +66,7 @@ function parse_reg_rule()
units = $8 units = $8
sub(/\)/, "", units) sub(/\)/, "", units)
sub(/,/, "", units) sub(/,/, "", units)
dfs_cac = $9
if (units == "mW") { if (units == "mW") {
if (power == 100) { if (power == 100) {
power = 20 power = 20
...@@ -78,7 +79,12 @@ function parse_reg_rule() ...@@ -78,7 +79,12 @@ function parse_reg_rule()
} else { } else {
print "Unknown power value in database!" print "Unknown power value in database!"
} }
} else {
dfs_cac = $8
} }
sub(/,/, "", dfs_cac)
sub(/\(/, "", dfs_cac)
sub(/\)/, "", dfs_cac)
flagstr = "" flagstr = ""
for (i=8; i<=NF; i++) for (i=8; i<=NF; i++)
flagstr = flagstr $i flagstr = flagstr $i
...@@ -111,7 +117,7 @@ function parse_reg_rule() ...@@ -111,7 +117,7 @@ function parse_reg_rule()
} }
flags = flags "0" flags = flags "0"
printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags printf "\t\tREG_RULE_EXT(%d, %d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, dfs_cac, flags
rules++ rules++
} }
......
...@@ -82,10 +82,10 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, ...@@ -82,10 +82,10 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
} }
EXPORT_SYMBOL(cfg80211_ibss_joined); EXPORT_SYMBOL(cfg80211_ibss_joined);
int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, static int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
struct net_device *dev, struct net_device *dev,
struct cfg80211_ibss_params *params, struct cfg80211_ibss_params *params,
struct cfg80211_cached_keys *connkeys) struct cfg80211_cached_keys *connkeys)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
struct ieee80211_channel *check_chan; struct ieee80211_channel *check_chan;
......
...@@ -778,7 +778,7 @@ void cfg80211_cac_event(struct net_device *netdev, ...@@ -778,7 +778,7 @@ void cfg80211_cac_event(struct net_device *netdev,
switch (event) { switch (event) {
case NL80211_RADAR_CAC_FINISHED: case NL80211_RADAR_CAC_FINISHED:
timeout = wdev->cac_start_time + timeout = wdev->cac_start_time +
msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); msecs_to_jiffies(wdev->cac_time_ms);
WARN_ON(!time_after_eq(jiffies, timeout)); WARN_ON(!time_after_eq(jiffies, timeout));
cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
break; break;
......
...@@ -593,6 +593,10 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, ...@@ -593,6 +593,10 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME, if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME,
time)) time))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_u32(msg,
NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
chan->dfs_cac_ms))
goto nla_put_failure;
} }
} }
...@@ -3328,7 +3332,7 @@ static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) ...@@ -3328,7 +3332,7 @@ static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1]; struct net_device *dev = info->user_ptr[1];
return cfg80211_stop_ap(rdev, dev); return cfg80211_stop_ap(rdev, dev, false);
} }
static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
...@@ -4614,6 +4618,7 @@ static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = ...@@ -4614,6 +4618,7 @@ static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] =
[NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
[NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
[NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
}; };
static int parse_reg_rule(struct nlattr *tb[], static int parse_reg_rule(struct nlattr *tb[],
...@@ -4649,6 +4654,10 @@ static int parse_reg_rule(struct nlattr *tb[], ...@@ -4649,6 +4654,10 @@ static int parse_reg_rule(struct nlattr *tb[],
power_rule->max_antenna_gain = power_rule->max_antenna_gain =
nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]); nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
if (tb[NL80211_ATTR_DFS_CAC_TIME])
reg_rule->dfs_cac_ms =
nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
return 0; return 0;
} }
...@@ -5136,7 +5145,9 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) ...@@ -5136,7 +5145,9 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
power_rule->max_antenna_gain) || power_rule->max_antenna_gain) ||
nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
power_rule->max_eirp)) power_rule->max_eirp) ||
nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME,
reg_rule->dfs_cac_ms))
goto nla_put_failure_rcu; goto nla_put_failure_rcu;
nla_nest_end(msg, nl_reg_rule); nla_nest_end(msg, nl_reg_rule);
...@@ -5768,6 +5779,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, ...@@ -5768,6 +5779,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_chan_def chandef; struct cfg80211_chan_def chandef;
enum nl80211_dfs_regions dfs_region; enum nl80211_dfs_regions dfs_region;
unsigned int cac_time_ms;
int err; int err;
dfs_region = reg_get_dfs_region(wdev->wiphy); dfs_region = reg_get_dfs_region(wdev->wiphy);
...@@ -5803,11 +5815,17 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, ...@@ -5803,11 +5815,17 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
if (err) if (err)
return err; return err;
err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
if (WARN_ON(!cac_time_ms))
cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef,
cac_time_ms);
if (!err) { if (!err) {
wdev->chandef = chandef; wdev->chandef = chandef;
wdev->cac_started = true; wdev->cac_started = true;
wdev->cac_start_time = jiffies; wdev->cac_start_time = jiffies;
wdev->cac_time_ms = cac_time_ms;
} }
return err; return err;
} }
......
...@@ -91,10 +91,6 @@ static struct regulatory_request __rcu *last_request = ...@@ -91,10 +91,6 @@ static struct regulatory_request __rcu *last_request =
/* To trigger userspace events */ /* To trigger userspace events */
static struct platform_device *reg_pdev; static struct platform_device *reg_pdev;
static const struct device_type reg_device_type = {
.uevent = reg_device_uevent,
};
/* /*
* Central wireless core regulatory domains, we only need two, * Central wireless core regulatory domains, we only need two,
* the current one and a world regulatory domain in case we have no * the current one and a world regulatory domain in case we have no
...@@ -244,19 +240,21 @@ static char user_alpha2[2]; ...@@ -244,19 +240,21 @@ static char user_alpha2[2];
module_param(ieee80211_regdom, charp, 0444); module_param(ieee80211_regdom, charp, 0444);
MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
static void reg_kfree_last_request(void) static void reg_free_request(struct regulatory_request *lr)
{ {
struct regulatory_request *lr;
lr = get_last_request();
if (lr != &core_request_world && lr) if (lr != &core_request_world && lr)
kfree_rcu(lr, rcu_head); kfree_rcu(lr, rcu_head);
} }
static void reg_update_last_request(struct regulatory_request *request) static void reg_update_last_request(struct regulatory_request *request)
{ {
reg_kfree_last_request(); struct regulatory_request *lr;
lr = get_last_request();
if (lr == request)
return;
reg_free_request(lr);
rcu_assign_pointer(last_request, request); rcu_assign_pointer(last_request, request);
} }
...@@ -487,11 +485,16 @@ static inline void reg_regdb_query(const char *alpha2) {} ...@@ -487,11 +485,16 @@ static inline void reg_regdb_query(const char *alpha2) {}
/* /*
* This lets us keep regulatory code which is updated on a regulatory * This lets us keep regulatory code which is updated on a regulatory
* basis in userspace. Country information is filled in by * basis in userspace.
* reg_device_uevent
*/ */
static int call_crda(const char *alpha2) static int call_crda(const char *alpha2)
{ {
char country[12];
char *env[] = { country, NULL };
snprintf(country, sizeof(country), "COUNTRY=%c%c",
alpha2[0], alpha2[1]);
if (!is_world_regdom((char *) alpha2)) if (!is_world_regdom((char *) alpha2))
pr_info("Calling CRDA for country: %c%c\n", pr_info("Calling CRDA for country: %c%c\n",
alpha2[0], alpha2[1]); alpha2[0], alpha2[1]);
...@@ -501,7 +504,7 @@ static int call_crda(const char *alpha2) ...@@ -501,7 +504,7 @@ static int call_crda(const char *alpha2)
/* query internal regulatory database (if it exists) */ /* query internal regulatory database (if it exists) */
reg_regdb_query(alpha2); reg_regdb_query(alpha2);
return kobject_uevent(&reg_pdev->dev.kobj, KOBJ_CHANGE); return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env);
} }
static enum reg_request_treatment static enum reg_request_treatment
...@@ -755,6 +758,9 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1, ...@@ -755,6 +758,9 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain, power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain,
power_rule2->max_antenna_gain); power_rule2->max_antenna_gain);
intersected_rule->dfs_cac_ms = max(rule1->dfs_cac_ms,
rule2->dfs_cac_ms);
if (!is_valid_reg_rule(intersected_rule)) if (!is_valid_reg_rule(intersected_rule))
return -EINVAL; return -EINVAL;
...@@ -1077,6 +1083,14 @@ static void handle_channel(struct wiphy *wiphy, ...@@ -1077,6 +1083,14 @@ static void handle_channel(struct wiphy *wiphy,
min_t(int, chan->orig_mag, min_t(int, chan->orig_mag,
MBI_TO_DBI(power_rule->max_antenna_gain)); MBI_TO_DBI(power_rule->max_antenna_gain));
chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp); chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
if (chan->flags & IEEE80211_CHAN_RADAR) {
if (reg_rule->dfs_cac_ms)
chan->dfs_cac_ms = reg_rule->dfs_cac_ms;
else
chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
}
if (chan->orig_mpwr) { if (chan->orig_mpwr) {
/* /*
* Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER * Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER
...@@ -2255,9 +2269,9 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) ...@@ -2255,9 +2269,9 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
const struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_reg_rule *reg_rule = NULL;
const struct ieee80211_freq_range *freq_range = NULL; const struct ieee80211_freq_range *freq_range = NULL;
const struct ieee80211_power_rule *power_rule = NULL; const struct ieee80211_power_rule *power_rule = NULL;
char bw[32]; char bw[32], cac_time[32];
pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n"); pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp), (dfs_cac_time)\n");
for (i = 0; i < rd->n_reg_rules; i++) { for (i = 0; i < rd->n_reg_rules; i++) {
reg_rule = &rd->reg_rules[i]; reg_rule = &rd->reg_rules[i];
...@@ -2272,23 +2286,32 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) ...@@ -2272,23 +2286,32 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
snprintf(bw, sizeof(bw), "%d KHz", snprintf(bw, sizeof(bw), "%d KHz",
freq_range->max_bandwidth_khz); freq_range->max_bandwidth_khz);
if (reg_rule->flags & NL80211_RRF_DFS)
scnprintf(cac_time, sizeof(cac_time), "%u s",
reg_rule->dfs_cac_ms/1000);
else
scnprintf(cac_time, sizeof(cac_time), "N/A");
/* /*
* There may not be documentation for max antenna gain * There may not be documentation for max antenna gain
* in certain regions * in certain regions
*/ */
if (power_rule->max_antenna_gain) if (power_rule->max_antenna_gain)
pr_info(" (%d KHz - %d KHz @ %s), (%d mBi, %d mBm)\n", pr_info(" (%d KHz - %d KHz @ %s), (%d mBi, %d mBm), (%s)\n",
freq_range->start_freq_khz, freq_range->start_freq_khz,
freq_range->end_freq_khz, freq_range->end_freq_khz,
bw, bw,
power_rule->max_antenna_gain, power_rule->max_antenna_gain,
power_rule->max_eirp); power_rule->max_eirp,
cac_time);
else else
pr_info(" (%d KHz - %d KHz @ %s), (N/A, %d mBm)\n", pr_info(" (%d KHz - %d KHz @ %s), (N/A, %d mBm), (%s)\n",
freq_range->start_freq_khz, freq_range->start_freq_khz,
freq_range->end_freq_khz, freq_range->end_freq_khz,
bw, bw,
power_rule->max_eirp); power_rule->max_eirp,
cac_time);
} }
} }
...@@ -2361,9 +2384,6 @@ static int reg_set_rd_user(const struct ieee80211_regdomain *rd, ...@@ -2361,9 +2384,6 @@ static int reg_set_rd_user(const struct ieee80211_regdomain *rd,
{ {
const struct ieee80211_regdomain *intersected_rd = NULL; const struct ieee80211_regdomain *intersected_rd = NULL;
if (is_world_regdom(rd->alpha2))
return -EINVAL;
if (!regdom_changes(rd->alpha2)) if (!regdom_changes(rd->alpha2))
return -EALREADY; return -EALREADY;
...@@ -2552,26 +2572,6 @@ int set_regdom(const struct ieee80211_regdomain *rd) ...@@ -2552,26 +2572,6 @@ int set_regdom(const struct ieee80211_regdomain *rd)
return 0; return 0;
} }
int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct regulatory_request *lr;
u8 alpha2[2];
bool add = false;
rcu_read_lock();
lr = get_last_request();
if (lr && !lr->processed) {
memcpy(alpha2, lr->alpha2, 2);
add = true;
}
rcu_read_unlock();
if (add)
return add_uevent_var(env, "COUNTRY=%c%c",
alpha2[0], alpha2[1]);
return 0;
}
void wiphy_regulatory_register(struct wiphy *wiphy) void wiphy_regulatory_register(struct wiphy *wiphy)
{ {
struct regulatory_request *lr; struct regulatory_request *lr;
...@@ -2622,8 +2622,6 @@ int __init regulatory_init(void) ...@@ -2622,8 +2622,6 @@ int __init regulatory_init(void)
if (IS_ERR(reg_pdev)) if (IS_ERR(reg_pdev))
return PTR_ERR(reg_pdev); return PTR_ERR(reg_pdev);
reg_pdev->dev.type = &reg_device_type;
spin_lock_init(&reg_requests_lock); spin_lock_init(&reg_requests_lock);
spin_lock_init(&reg_pending_beacons_lock); spin_lock_init(&reg_pending_beacons_lock);
......
...@@ -26,7 +26,6 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy); ...@@ -26,7 +26,6 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy);
int regulatory_hint_user(const char *alpha2, int regulatory_hint_user(const char *alpha2,
enum nl80211_user_reg_hint_type user_reg_hint_type); enum nl80211_user_reg_hint_type user_reg_hint_type);
int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env);
void wiphy_regulatory_register(struct wiphy *wiphy); void wiphy_regulatory_register(struct wiphy *wiphy);
void wiphy_regulatory_deregister(struct wiphy *wiphy); void wiphy_regulatory_deregister(struct wiphy *wiphy);
......
...@@ -659,9 +659,6 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev, ...@@ -659,9 +659,6 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev,
continue; continue;
if (ssidlen && ie[1] != ssidlen) if (ssidlen && ie[1] != ssidlen)
continue; continue;
/* that would be odd ... */
if (bss->pub.beacon_ies)
continue;
if (WARN_ON_ONCE(bss->pub.hidden_beacon_bss)) if (WARN_ON_ONCE(bss->pub.hidden_beacon_bss))
continue; continue;
if (WARN_ON_ONCE(!list_empty(&bss->hidden_list))) if (WARN_ON_ONCE(!list_empty(&bss->hidden_list)))
...@@ -680,7 +677,8 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev, ...@@ -680,7 +677,8 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev,
/* Returned bss is reference counted and must be cleaned up appropriately. */ /* Returned bss is reference counted and must be cleaned up appropriately. */
static struct cfg80211_internal_bss * static struct cfg80211_internal_bss *
cfg80211_bss_update(struct cfg80211_registered_device *dev, cfg80211_bss_update(struct cfg80211_registered_device *dev,
struct cfg80211_internal_bss *tmp) struct cfg80211_internal_bss *tmp,
bool signal_valid)
{ {
struct cfg80211_internal_bss *found = NULL; struct cfg80211_internal_bss *found = NULL;
...@@ -765,7 +763,12 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, ...@@ -765,7 +763,12 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
} }
found->pub.beacon_interval = tmp->pub.beacon_interval; found->pub.beacon_interval = tmp->pub.beacon_interval;
found->pub.signal = tmp->pub.signal; /*
* don't update the signal if beacon was heard on
* adjacent channel.
*/
if (signal_valid)
found->pub.signal = tmp->pub.signal;
found->pub.capability = tmp->pub.capability; found->pub.capability = tmp->pub.capability;
found->ts = tmp->ts; found->ts = tmp->ts;
} else { } else {
...@@ -869,13 +872,14 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen, ...@@ -869,13 +872,14 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
/* Returned bss is reference counted and must be cleaned up appropriately. */ /* Returned bss is reference counted and must be cleaned up appropriately. */
struct cfg80211_bss* struct cfg80211_bss*
cfg80211_inform_bss_width(struct wiphy *wiphy, cfg80211_inform_bss_width(struct wiphy *wiphy,
struct ieee80211_channel *channel, struct ieee80211_channel *rx_channel,
enum nl80211_bss_scan_width scan_width, enum nl80211_bss_scan_width scan_width,
const u8 *bssid, u64 tsf, u16 capability, const u8 *bssid, u64 tsf, u16 capability,
u16 beacon_interval, const u8 *ie, size_t ielen, u16 beacon_interval, const u8 *ie, size_t ielen,
s32 signal, gfp_t gfp) s32 signal, gfp_t gfp)
{ {
struct cfg80211_bss_ies *ies; struct cfg80211_bss_ies *ies;
struct ieee80211_channel *channel;
struct cfg80211_internal_bss tmp = {}, *res; struct cfg80211_internal_bss tmp = {}, *res;
if (WARN_ON(!wiphy)) if (WARN_ON(!wiphy))
...@@ -885,7 +889,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, ...@@ -885,7 +889,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
(signal < 0 || signal > 100))) (signal < 0 || signal > 100)))
return NULL; return NULL;
channel = cfg80211_get_bss_channel(wiphy, ie, ielen, channel); channel = cfg80211_get_bss_channel(wiphy, ie, ielen, rx_channel);
if (!channel) if (!channel)
return NULL; return NULL;
...@@ -913,7 +917,8 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, ...@@ -913,7 +917,8 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
rcu_assign_pointer(tmp.pub.beacon_ies, ies); rcu_assign_pointer(tmp.pub.beacon_ies, ies);
rcu_assign_pointer(tmp.pub.ies, ies); rcu_assign_pointer(tmp.pub.ies, ies);
res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp); res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp,
rx_channel == channel);
if (!res) if (!res)
return NULL; return NULL;
...@@ -929,20 +934,21 @@ EXPORT_SYMBOL(cfg80211_inform_bss_width); ...@@ -929,20 +934,21 @@ EXPORT_SYMBOL(cfg80211_inform_bss_width);
/* Returned bss is reference counted and must be cleaned up appropriately. */ /* Returned bss is reference counted and must be cleaned up appropriately. */
struct cfg80211_bss * struct cfg80211_bss *
cfg80211_inform_bss_width_frame(struct wiphy *wiphy, cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
struct ieee80211_channel *channel, struct ieee80211_channel *rx_channel,
enum nl80211_bss_scan_width scan_width, enum nl80211_bss_scan_width scan_width,
struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_mgmt *mgmt, size_t len,
s32 signal, gfp_t gfp) s32 signal, gfp_t gfp)
{ {
struct cfg80211_internal_bss tmp = {}, *res; struct cfg80211_internal_bss tmp = {}, *res;
struct cfg80211_bss_ies *ies; struct cfg80211_bss_ies *ies;
struct ieee80211_channel *channel;
size_t ielen = len - offsetof(struct ieee80211_mgmt, size_t ielen = len - offsetof(struct ieee80211_mgmt,
u.probe_resp.variable); u.probe_resp.variable);
BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) != BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
offsetof(struct ieee80211_mgmt, u.beacon.variable)); offsetof(struct ieee80211_mgmt, u.beacon.variable));
trace_cfg80211_inform_bss_width_frame(wiphy, channel, scan_width, mgmt, trace_cfg80211_inform_bss_width_frame(wiphy, rx_channel, scan_width, mgmt,
len, signal); len, signal);
if (WARN_ON(!mgmt)) if (WARN_ON(!mgmt))
...@@ -959,7 +965,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy, ...@@ -959,7 +965,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
return NULL; return NULL;
channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable, channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable,
ielen, channel); ielen, rx_channel);
if (!channel) if (!channel)
return NULL; return NULL;
...@@ -983,7 +989,8 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy, ...@@ -983,7 +989,8 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); tmp.pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); tmp.pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info);
res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp); res = cfg80211_bss_update(wiphy_to_dev(wiphy), &tmp,
rx_channel == channel);
if (!res) if (!res)
return NULL; return NULL;
......
...@@ -64,7 +64,6 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) ...@@ -64,7 +64,6 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
int n_channels, err; int n_channels, err;
ASSERT_RTNL(); ASSERT_RTNL();
ASSERT_RDEV_LOCK(rdev);
ASSERT_WDEV_LOCK(wdev); ASSERT_WDEV_LOCK(wdev);
if (rdev->scan_req || rdev->scan_msg) if (rdev->scan_req || rdev->scan_msg)
......
...@@ -838,7 +838,6 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) ...@@ -838,7 +838,6 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev)
struct wireless_dev *wdev; struct wireless_dev *wdev;
ASSERT_RTNL(); ASSERT_RTNL();
ASSERT_RDEV_LOCK(rdev);
list_for_each_entry(wdev, &rdev->wdev_list, list) list_for_each_entry(wdev, &rdev->wdev_list, list)
cfg80211_process_wdev_events(wdev); cfg80211_process_wdev_events(wdev);
...@@ -851,7 +850,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, ...@@ -851,7 +850,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
int err; int err;
enum nl80211_iftype otype = dev->ieee80211_ptr->iftype; enum nl80211_iftype otype = dev->ieee80211_ptr->iftype;
ASSERT_RDEV_LOCK(rdev); ASSERT_RTNL();
/* don't support changing VLANs, you just re-create them */ /* don't support changing VLANs, you just re-create them */
if (otype == NL80211_IFTYPE_AP_VLAN) if (otype == NL80211_IFTYPE_AP_VLAN)
...@@ -886,7 +885,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, ...@@ -886,7 +885,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
switch (otype) { switch (otype) {
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
cfg80211_stop_ap(rdev, dev); cfg80211_stop_ap(rdev, dev, true);
break; break;
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
cfg80211_leave_ibss(rdev, dev, false); cfg80211_leave_ibss(rdev, dev, false);
......
...@@ -21,7 +21,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, ...@@ -21,7 +21,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
const u8 *prev_bssid = NULL; const u8 *prev_bssid = NULL;
int err, i; int err, i;
ASSERT_RDEV_LOCK(rdev); ASSERT_RTNL();
ASSERT_WDEV_LOCK(wdev); ASSERT_WDEV_LOCK(wdev);
if (!netif_running(wdev->netdev)) if (!netif_running(wdev->netdev))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment