Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
This commit is contained in:
commit
7eb2450a51
27 changed files with 402 additions and 258 deletions
|
@ -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 {
|
||||||
* @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 {
|
||||||
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 {
|
||||||
|
|
||||||
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;
|
||||||
* @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 {
|
||||||
|
|
||||||
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);
|
||||||
* 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);
|
||||||
*/
|
*/
|
||||||
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,
|
||||||
* 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,
|
||||||
*/
|
*/
|
||||||
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,
|
||||||
|
|
||||||
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 {
|
||||||
} 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 {
|
||||||
* @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 {
|
||||||
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 {
|
||||||
#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 {
|
||||||
* @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 {
|
||||||
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 {
|
||||||
* 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 {
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,6 +3089,129 @@ unlock:
|
||||||
sdata_unlock(sdata);
|
sdata_unlock(sdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
|
||||||
|
struct cfg80211_csa_settings *params,
|
||||||
|
u32 *changed)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
switch (sdata->vif.type) {
|
||||||
|
case NL80211_IFTYPE_AP:
|
||||||
|
sdata->u.ap.next_beacon =
|
||||||
|
cfg80211_beacon_dup(¶ms->beacon_after);
|
||||||
|
if (!sdata->u.ap.next_beacon)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With a count of 0, we don't have to wait for any
|
||||||
|
* TBTT before switching, so complete the CSA
|
||||||
|
* immediately. In theory, with a count == 1 we
|
||||||
|
* should delay the switch until just before the next
|
||||||
|
* TBTT, but that would complicate things so we switch
|
||||||
|
* immediately too. If we would delay the switch
|
||||||
|
* until the next TBTT, we would have to set the probe
|
||||||
|
* response here.
|
||||||
|
*
|
||||||
|
* TODO: A channel switch with count <= 1 without
|
||||||
|
* sending a CSA action frame is kind of useless,
|
||||||
|
* because the clients won't know we're changing
|
||||||
|
* channels. The action frame must be implemented
|
||||||
|
* either here or in the userspace.
|
||||||
|
*/
|
||||||
|
if (params->count <= 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
sdata->csa_counter_offset_beacon =
|
||||||
|
params->counter_offset_beacon;
|
||||||
|
sdata->csa_counter_offset_presp = params->counter_offset_presp;
|
||||||
|
err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa);
|
||||||
|
if (err < 0) {
|
||||||
|
kfree(sdata->u.ap.next_beacon);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
*changed |= err;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case NL80211_IFTYPE_ADHOC:
|
||||||
|
if (!sdata->vif.bss_conf.ibss_joined)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (params->chandef.width != sdata->u.ibss.chandef.width)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (params->chandef.width) {
|
||||||
|
case NL80211_CHAN_WIDTH_40:
|
||||||
|
if (cfg80211_get_chandef_type(¶ms->chandef) !=
|
||||||
|
cfg80211_get_chandef_type(&sdata->u.ibss.chandef))
|
||||||
|
return -EINVAL;
|
||||||
|
case NL80211_CHAN_WIDTH_5:
|
||||||
|
case NL80211_CHAN_WIDTH_10:
|
||||||
|
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||||
|
case NL80211_CHAN_WIDTH_20:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* changes into another band are not supported */
|
||||||
|
if (sdata->u.ibss.chandef.chan->band !=
|
||||||
|
params->chandef.chan->band)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* see comments in the NL80211_IFTYPE_AP block */
|
||||||
|
if (params->count > 1) {
|
||||||
|
err = ieee80211_ibss_csa_beacon(sdata, params);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
*changed |= err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ieee80211_send_action_csa(sdata, params);
|
||||||
|
|
||||||
|
break;
|
||||||
|
#ifdef CONFIG_MAC80211_MESH
|
||||||
|
case NL80211_IFTYPE_MESH_POINT: {
|
||||||
|
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||||
|
|
||||||
|
if (params->chandef.width != sdata->vif.bss_conf.chandef.width)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* changes into another band are not supported */
|
||||||
|
if (sdata->vif.bss_conf.chandef.chan->band !=
|
||||||
|
params->chandef.chan->band)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_NONE) {
|
||||||
|
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_INIT;
|
||||||
|
if (!ifmsh->pre_value)
|
||||||
|
ifmsh->pre_value = 1;
|
||||||
|
else
|
||||||
|
ifmsh->pre_value++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* see comments in the NL80211_IFTYPE_AP block */
|
||||||
|
if (params->count > 1) {
|
||||||
|
err = ieee80211_mesh_csa_beacon(sdata, params);
|
||||||
|
if (err < 0) {
|
||||||
|
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
*changed |= err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT)
|
||||||
|
ieee80211_send_action_csa(sdata, params);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
||||||
struct cfg80211_csa_settings *params)
|
struct cfg80211_csa_settings *params)
|
||||||
{
|
{
|
||||||
|
@ -3096,7 +3219,6 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
||||||
struct ieee80211_local *local = sdata->local;
|
struct ieee80211_local *local = sdata->local;
|
||||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||||
struct ieee80211_chanctx *chanctx;
|
struct ieee80211_chanctx *chanctx;
|
||||||
struct ieee80211_if_mesh __maybe_unused *ifmsh;
|
|
||||||
int err, num_chanctx, changed = 0;
|
int err, num_chanctx, changed = 0;
|
||||||
|
|
||||||
sdata_assert_lock(sdata);
|
sdata_assert_lock(sdata);
|
||||||
|
@ -3136,118 +3258,9 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
||||||
if (sdata->vif.csa_active)
|
if (sdata->vif.csa_active)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
switch (sdata->vif.type) {
|
err = ieee80211_set_csa_beacon(sdata, params, &changed);
|
||||||
case NL80211_IFTYPE_AP:
|
if (err)
|
||||||
sdata->u.ap.next_beacon =
|
|
||||||
cfg80211_beacon_dup(¶ms->beacon_after);
|
|
||||||
if (!sdata->u.ap.next_beacon)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* With a count of 0, we don't have to wait for any
|
|
||||||
* TBTT before switching, so complete the CSA
|
|
||||||
* immediately. In theory, with a count == 1 we
|
|
||||||
* should delay the switch until just before the next
|
|
||||||
* TBTT, but that would complicate things so we switch
|
|
||||||
* immediately too. If we would delay the switch
|
|
||||||
* until the next TBTT, we would have to set the probe
|
|
||||||
* response here.
|
|
||||||
*
|
|
||||||
* TODO: A channel switch with count <= 1 without
|
|
||||||
* sending a CSA action frame is kind of useless,
|
|
||||||
* because the clients won't know we're changing
|
|
||||||
* channels. The action frame must be implemented
|
|
||||||
* either here or in the userspace.
|
|
||||||
*/
|
|
||||||
if (params->count <= 1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
sdata->csa_counter_offset_beacon =
|
|
||||||
params->counter_offset_beacon;
|
|
||||||
sdata->csa_counter_offset_presp = params->counter_offset_presp;
|
|
||||||
err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa);
|
|
||||||
if (err < 0) {
|
|
||||||
kfree(sdata->u.ap.next_beacon);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
|
||||||
changed |= err;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case NL80211_IFTYPE_ADHOC:
|
|
||||||
if (!sdata->vif.bss_conf.ibss_joined)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (params->chandef.width != sdata->u.ibss.chandef.width)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
switch (params->chandef.width) {
|
|
||||||
case NL80211_CHAN_WIDTH_40:
|
|
||||||
if (cfg80211_get_chandef_type(¶ms->chandef) !=
|
|
||||||
cfg80211_get_chandef_type(&sdata->u.ibss.chandef))
|
|
||||||
return -EINVAL;
|
|
||||||
case NL80211_CHAN_WIDTH_5:
|
|
||||||
case NL80211_CHAN_WIDTH_10:
|
|
||||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
|
||||||
case NL80211_CHAN_WIDTH_20:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* changes into another band are not supported */
|
|
||||||
if (sdata->u.ibss.chandef.chan->band !=
|
|
||||||
params->chandef.chan->band)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* see comments in the NL80211_IFTYPE_AP block */
|
|
||||||
if (params->count > 1) {
|
|
||||||
err = ieee80211_ibss_csa_beacon(sdata, params);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
changed |= err;
|
|
||||||
}
|
|
||||||
|
|
||||||
ieee80211_send_action_csa(sdata, params);
|
|
||||||
|
|
||||||
break;
|
|
||||||
#ifdef CONFIG_MAC80211_MESH
|
|
||||||
case NL80211_IFTYPE_MESH_POINT:
|
|
||||||
ifmsh = &sdata->u.mesh;
|
|
||||||
|
|
||||||
if (params->chandef.width != sdata->vif.bss_conf.chandef.width)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* changes into another band are not supported */
|
|
||||||
if (sdata->vif.bss_conf.chandef.chan->band !=
|
|
||||||
params->chandef.chan->band)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_NONE) {
|
|
||||||
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_INIT;
|
|
||||||
if (!ifmsh->pre_value)
|
|
||||||
ifmsh->pre_value = 1;
|
|
||||||
else
|
|
||||||
ifmsh->pre_value++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* see comments in the NL80211_IFTYPE_AP block */
|
|
||||||
if (params->count > 1) {
|
|
||||||
err = ieee80211_mesh_csa_beacon(sdata, params);
|
|
||||||
if (err < 0) {
|
|
||||||
ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
changed |= err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT)
|
|
||||||
ieee80211_send_action_csa(sdata, params);
|
|
||||||
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
sdata->csa_radar_required = params->radar_required;
|
sdata->csa_radar_required = params->radar_required;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
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);
|
||||||
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,
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
#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,
|
||||||
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;
|
|
||||||
|
|
||||||
|
if (ifmgd->auth_data &&
|
||||||
|
ether_addr_equal(ifmgd->auth_data->bss->bssid, req->bssid)) {
|
||||||
sdata_info(sdata,
|
sdata_info(sdata,
|
||||||
"deauthenticating from %pM by local choice (Reason: %u=%s)\n",
|
"aborting authentication with %pM by local choice (Reason: %u=%s)\n",
|
||||||
req->bssid, req->reason_code, ieee80211_get_reason_code_string(req->reason_code));
|
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);
|
||||||
|
|
||||||
report_frame = true;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ifmgd->associated &&
|
|
||||||
ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
|
|
||||||
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
|
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ifmgd->associated &&
|
||||||
|
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,
|
||||||
|
req->reason_code, tx, frame_buf);
|
||||||
|
cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
|
||||||
|
IEEE80211_DEAUTH_FRAME_LEN);
|
||||||
|
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)
|
||||||
|
|
||||||
/* 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,
|
||||||
/* 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)
|
||||||
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)
|
||||||
/* 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,
|
||||||
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 @@
|
||||||
|
|
||||||
|
|
||||||
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,6 +30,7 @@ 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);
|
||||||
|
if (notify)
|
||||||
nl80211_send_ap_stopped(wdev);
|
nl80211_send_ap_stopped(wdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,13 +38,13 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
/* 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,
|
||||||
|
|
||||||
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()
|
||||||
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()
|
||||||
} 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()
|
||||||
|
|
||||||
}
|
}
|
||||||
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,7 +82,7 @@ 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)
|
||||||
|
|
|
@ -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,
|
||||||
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)
|
||||||
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] =
|
||||||
[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[],
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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 =
|
||||||
/* 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];
|
||||||
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) {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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)
|
||||||
/* 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(®_pdev->dev.kobj, KOBJ_CHANGE);
|
return kobject_uevent_env(®_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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
{
|
{
|
||||||
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)
|
||||||
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)
|
||||||
if (IS_ERR(reg_pdev))
|
if (IS_ERR(reg_pdev))
|
||||||
return PTR_ERR(reg_pdev);
|
return PTR_ERR(reg_pdev);
|
||||||
|
|
||||||
reg_pdev->dev.type = ®_device_type;
|
|
||||||
|
|
||||||
spin_lock_init(®_requests_lock);
|
spin_lock_init(®_requests_lock);
|
||||||
spin_lock_init(®_pending_beacons_lock);
|
spin_lock_init(®_pending_beacons_lock);
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
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,
|
||||||
/* 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,6 +763,11 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
found->pub.beacon_interval = tmp->pub.beacon_interval;
|
found->pub.beacon_interval = tmp->pub.beacon_interval;
|
||||||
|
/*
|
||||||
|
* don't update the signal if beacon was heard on
|
||||||
|
* adjacent channel.
|
||||||
|
*/
|
||||||
|
if (signal_valid)
|
||||||
found->pub.signal = tmp->pub.signal;
|
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;
|
||||||
|
@ -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,
|
||||||
(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,
|
||||||
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);
|
||||||
/* 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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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))
|
||||||
|
|
Loading…
Add table
Reference in a new issue