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
		Add a link
		
	
		Reference in a new issue
	
	 John W. Linville
				John W. Linville