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 | ||||
|    up to 2304 octets long (maximum MSDU size) plus any crypt overhead. */ | ||||
| #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 */ | ||||
| #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 | ||||
|  *	on this channel. | ||||
|  * @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 { | ||||
| 	enum ieee80211_band band; | ||||
|  | @ -165,6 +166,7 @@ struct ieee80211_channel { | |||
| 	int orig_mag, orig_mpwr; | ||||
| 	enum nl80211_dfs_state dfs_state; | ||||
| 	unsigned long dfs_state_entered; | ||||
| 	unsigned int dfs_cac_ms; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -2503,7 +2505,8 @@ struct cfg80211_ops { | |||
| 
 | ||||
| 	int	(*start_radar_detection)(struct wiphy *wiphy, | ||||
| 					 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, | ||||
| 				 struct cfg80211_update_ft_ies_params *ftie); | ||||
| 	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 | ||||
|  * @cac_started: true if DFS channel availability check has been started | ||||
|  * @cac_start_time: timestamp (jiffies) when the dfs state was entered. | ||||
|  * @cac_time_ms: CAC time in ms | ||||
|  * @ps: powersave mode is enabled | ||||
|  * @ps_timeout: dynamic powersave timeout | ||||
|  * @ap_unexpected_nlportid: (private) netlink port ID of application | ||||
|  | @ -3235,6 +3239,7 @@ struct wireless_dev { | |||
| 
 | ||||
| 	bool cac_started; | ||||
| 	unsigned long cac_start_time; | ||||
| 	unsigned int cac_time_ms; | ||||
| 
 | ||||
| #ifdef CONFIG_CFG80211_WEXT | ||||
| 	/* 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 | ||||
|  * | ||||
|  * @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 | ||||
|  * @mgmt: the management frame (probe response or beacon) | ||||
|  * @len: length of the management frame | ||||
|  | @ -3682,18 +3687,18 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy); | |||
|  */ | ||||
| struct cfg80211_bss * __must_check | ||||
| cfg80211_inform_bss_width_frame(struct wiphy *wiphy, | ||||
| 				struct ieee80211_channel *channel, | ||||
| 				struct ieee80211_channel *rx_channel, | ||||
| 				enum nl80211_bss_scan_width scan_width, | ||||
| 				struct ieee80211_mgmt *mgmt, size_t len, | ||||
| 				s32 signal, gfp_t gfp); | ||||
| 
 | ||||
| static inline struct cfg80211_bss * __must_check | ||||
| cfg80211_inform_bss_frame(struct wiphy *wiphy, | ||||
| 			  struct ieee80211_channel *channel, | ||||
| 			  struct ieee80211_channel *rx_channel, | ||||
| 			  struct ieee80211_mgmt *mgmt, size_t len, | ||||
| 			  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, | ||||
| 					       mgmt, len, signal, gfp); | ||||
| } | ||||
|  | @ -3702,7 +3707,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
|  * cfg80211_inform_bss - inform cfg80211 of a new 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 | ||||
|  * @bssid: the BSSID of the BSS | ||||
|  * @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 | ||||
| cfg80211_inform_bss_width(struct wiphy *wiphy, | ||||
| 			  struct ieee80211_channel *channel, | ||||
| 			  struct ieee80211_channel *rx_channel, | ||||
| 			  enum nl80211_bss_scan_width scan_width, | ||||
| 			  const u8 *bssid, u64 tsf, u16 capability, | ||||
| 			  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 | ||||
| cfg80211_inform_bss(struct wiphy *wiphy, | ||||
| 		    struct ieee80211_channel *channel, | ||||
| 		    struct ieee80211_channel *rx_channel, | ||||
| 		    const u8 *bssid, u64 tsf, u16 capability, | ||||
| 		    u16 beacon_interval, const u8 *ie, size_t ielen, | ||||
| 		    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, | ||||
| 					 bssid, tsf, capability, | ||||
| 					 beacon_interval, ie, ielen, signal, | ||||
|  |  | |||
|  | @ -697,11 +697,11 @@ struct ieee80211_tx_info { | |||
| 		} control; | ||||
| 		struct { | ||||
| 			struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES]; | ||||
| 			int ack_signal; | ||||
| 			s32 ack_signal; | ||||
| 			u8 ampdu_ack_len; | ||||
| 			u8 ampdu_len; | ||||
| 			u8 antenna; | ||||
| 			/* 21 bytes free */ | ||||
| 			void *status_driver_data[21 / sizeof(void *)]; | ||||
| 		} status; | ||||
| 		struct { | ||||
| 			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_80P80MHZ: 80+80 MHz was used | ||||
|  * @RX_VHT_FLAG_160MHZ: 160 MHz was used | ||||
|  * @RX_VHT_FLAG_BF: packet was beamformed | ||||
|  */ | ||||
| enum mac80211_rx_vht_flags { | ||||
| 	RX_VHT_FLAG_80MHZ		= BIT(0), | ||||
| 	RX_VHT_FLAG_80P80MHZ		= BIT(1), | ||||
| 	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_power_rule power_rule; | ||||
| 	u32 flags; | ||||
| 	u32 dfs_cac_ms; | ||||
| }; | ||||
| 
 | ||||
| struct ieee80211_regdomain { | ||||
|  | @ -172,14 +173,18 @@ struct ieee80211_regdomain { | |||
| #define DBM_TO_MBM(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.end_freq_khz = MHZ_TO_KHZ(end),			\ | ||||
| 	.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),			\ | ||||
| 	.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 | ||||
|  |  | |||
|  | @ -2335,6 +2335,7 @@ enum nl80211_band_attr { | |||
|  * @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 | ||||
|  *	isn't possible | ||||
|  * @NL80211_FREQUENCY_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds. | ||||
|  * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number | ||||
|  *	currently defined | ||||
|  * @__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_80MHZ, | ||||
| 	NL80211_FREQUENCY_ATTR_NO_160MHZ, | ||||
| 	NL80211_FREQUENCY_ATTR_DFS_CAC_TIME, | ||||
| 
 | ||||
| 	/* keep 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. | ||||
|  * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for | ||||
|  * 	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 | ||||
|  *	currently defined | ||||
|  * @__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_EIRP, | ||||
| 
 | ||||
| 	NL80211_ATTR_DFS_CAC_TIME, | ||||
| 
 | ||||
| 	/* keep last */ | ||||
| 	__NL80211_REG_RULE_ATTR_AFTER_LAST, | ||||
| 	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, | ||||
| 					   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_local *local = sdata->local; | ||||
| 	unsigned long timeout; | ||||
| 	int err; | ||||
| 
 | ||||
| 	mutex_lock(&local->mtx); | ||||
|  | @ -2937,9 +2937,9 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy, | |||
| 	if (err) | ||||
| 		goto out_unlock; | ||||
| 
 | ||||
| 	timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS); | ||||
| 	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: | ||||
| 	mutex_unlock(&local->mtx); | ||||
|  | @ -3089,6 +3089,129 @@ unlock: | |||
| 	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, | ||||
| 			     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_chanctx_conf *chanctx_conf; | ||||
| 	struct ieee80211_chanctx *chanctx; | ||||
| 	struct ieee80211_if_mesh __maybe_unused *ifmsh; | ||||
| 	int err, num_chanctx, changed = 0; | ||||
| 
 | ||||
| 	sdata_assert_lock(sdata); | ||||
|  | @ -3136,118 +3258,9 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
| 	if (sdata->vif.csa_active) | ||||
| 		return -EBUSY; | ||||
| 
 | ||||
| 	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); | ||||
| 	err = ieee80211_set_csa_beacon(sdata, params, &changed); | ||||
| 	if (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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -991,7 +991,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 				  struct ieee802_11_elems *elems) | ||||
| { | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 	int freq; | ||||
| 	struct cfg80211_bss *cbss; | ||||
| 	struct ieee80211_bss *bss; | ||||
| 	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]; | ||||
| 	bool rates_updated = false; | ||||
| 
 | ||||
| 	if (elems->ds_params) | ||||
| 		freq = ieee80211_channel_to_frequency(elems->ds_params[0], | ||||
| 						      band); | ||||
| 	else | ||||
| 		freq = rx_status->freq; | ||||
| 
 | ||||
| 	channel = ieee80211_get_channel(local->hw.wiphy, freq); | ||||
| 
 | ||||
| 	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | ||||
| 	channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); | ||||
| 	if (!channel) | ||||
| 		return; | ||||
| 
 | ||||
| 	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_conn_tx_status(struct ieee80211_sub_if_data *sdata, | ||||
| 				  __le16 fc, bool acked); | ||||
| void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata); | ||||
| void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); | ||||
| 
 | ||||
| /* IBSS code */ | ||||
|  |  | |||
|  | @ -2783,28 +2783,20 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
| 				  struct ieee802_11_elems *elems) | ||||
| { | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 	int freq; | ||||
| 	struct ieee80211_bss *bss; | ||||
| 	struct ieee80211_channel *channel; | ||||
| 
 | ||||
| 	sdata_assert_lock(sdata); | ||||
| 
 | ||||
| 	if (elems->ds_params) | ||||
| 		freq = ieee80211_channel_to_frequency(elems->ds_params[0], | ||||
| 						      rx_status->band); | ||||
| 	else | ||||
| 		freq = rx_status->freq; | ||||
| 
 | ||||
| 	channel = ieee80211_get_channel(local->hw.wiphy, freq); | ||||
| 
 | ||||
| 	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | ||||
| 	channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq); | ||||
| 	if (!channel) | ||||
| 		return; | ||||
| 
 | ||||
| 	bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | ||||
| 					channel); | ||||
| 	if (bss) { | ||||
| 		ieee80211_rx_bss_put(local, bss); | ||||
| 		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 | ||||
| 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) | ||||
| { | ||||
| 	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; | ||||
| 	u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; | ||||
| 	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, | ||||
| 		   "deauthenticating from %pM by local choice (Reason: %u=%s)\n", | ||||
| 		   req->bssid, req->reason_code, ieee80211_get_reason_code_string(req->reason_code)); | ||||
| 			   "aborting authentication with %pM by local choice (Reason: %u=%s)\n", | ||||
| 			   req->bssid, req->reason_code, | ||||
| 			   ieee80211_get_reason_code_string(req->reason_code)); | ||||
| 
 | ||||
| 	if (ifmgd->auth_data) { | ||||
| 		drv_mgd_prepare_tx(sdata->local, sdata); | ||||
| 		ieee80211_send_deauth_disassoc(sdata, req->bssid, | ||||
| 					       IEEE80211_STYPE_DEAUTH, | ||||
| 					       req->reason_code, tx, | ||||
| 					       frame_buf); | ||||
| 		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, | ||||
| 				      IEEE80211_DEAUTH_FRAME_LEN); | ||||
| 
 | ||||
| 		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, | ||||
|  |  | |||
|  | @ -100,10 +100,18 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
| 
 | ||||
| 	/* remove all interfaces that were created in the driver */ | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 		if (!ieee80211_sdata_running(sdata) || | ||||
| 		    sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | ||||
| 		    sdata->vif.type == NL80211_IFTYPE_MONITOR) | ||||
| 		if (!ieee80211_sdata_running(sdata)) | ||||
| 			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); | ||||
| 	} | ||||
|  |  | |||
|  | @ -333,6 +333,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
| 		/* in VHT, STBC is binary */ | ||||
| 		if (status->flag & RX_FLAG_STBC_MASK) | ||||
| 			*pos |= IEEE80211_RADIOTAP_VHT_FLAG_STBC; | ||||
| 		if (status->vht_flag & RX_VHT_FLAG_BF) | ||||
| 			*pos |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED; | ||||
| 		pos++; | ||||
| 		/* bandwidth */ | ||||
| 		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)) { | ||||
| 			sta->last_rx_rate_idx = status->rate_idx; | ||||
| 			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; | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
|  | @ -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. */ | ||||
| 	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); | ||||
| 
 | ||||
| 		if (!ret) | ||||
| 			rcu_assign_pointer(local->sched_scan_sdata, NULL); | ||||
| 	} | ||||
| out: | ||||
| 	mutex_unlock(&local->mtx); | ||||
| 
 | ||||
|  |  | |||
|  | @ -2900,7 +2900,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
| 				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); | ||||
| 		if (!ieee80211_tx_prepare(sdata, &tx, skb)) | ||||
| 			break; | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ | |||
| 
 | ||||
| 
 | ||||
| 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; | ||||
| 	int err; | ||||
|  | @ -30,6 +30,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | |||
| 		memset(&wdev->chandef, 0, sizeof(wdev->chandef)); | ||||
| 		wdev->ssid_len = 0; | ||||
| 		rdev_set_qos_map(rdev, dev, NULL); | ||||
| 		if (notify) | ||||
| 			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, | ||||
| 		     struct net_device *dev) | ||||
| 		     struct net_device *dev, bool notify) | ||||
| { | ||||
| 	struct wireless_dev *wdev = dev->ieee80211_ptr; | ||||
| 	int err; | ||||
| 
 | ||||
| 	wdev_lock(wdev); | ||||
| 	err = __cfg80211_stop_ap(rdev, dev); | ||||
| 	err = __cfg80211_stop_ap(rdev, dev, notify); | ||||
| 	wdev_unlock(wdev); | ||||
| 
 | ||||
| 	return err; | ||||
|  |  | |||
|  | @ -490,6 +490,62 @@ static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy, | |||
| 	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, | ||||
| 					u32 center_freq, u32 bandwidth, | ||||
|  |  | |||
|  | @ -783,7 +783,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
| 		break; | ||||
| 	case NL80211_IFTYPE_AP: | ||||
| 	case NL80211_IFTYPE_P2P_GO: | ||||
| 		cfg80211_stop_ap(rdev, dev); | ||||
| 		cfg80211_stop_ap(rdev, dev, true); | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
|  |  | |||
|  | @ -166,7 +166,6 @@ static inline void wdev_unlock(struct wireless_dev *wdev) | |||
| 	mutex_unlock(&wdev->mtx); | ||||
| } | ||||
| 
 | ||||
| #define ASSERT_RDEV_LOCK(rdev) ASSERT_RTNL() | ||||
| #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
| /* 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, | ||||
| 		       struct net_device *dev, | ||||
| 		       struct cfg80211_ibss_params *params, | ||||
|  | @ -283,7 +278,7 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, | |||
| 
 | ||||
| /* AP */ | ||||
| int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | ||||
| 		     struct net_device *dev); | ||||
| 		     struct net_device *dev, bool notify); | ||||
| 
 | ||||
| /* MLME */ | ||||
| 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); | ||||
| 
 | ||||
| unsigned int | ||||
| cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy, | ||||
| 			      const struct cfg80211_chan_def *chandef); | ||||
| 
 | ||||
| static inline int | ||||
| cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | ||||
|  |  | |||
|  | @ -66,6 +66,7 @@ function parse_reg_rule() | |||
| 	units = $8 | ||||
| 	sub(/\)/, "", units) | ||||
| 	sub(/,/, "", units) | ||||
| 	dfs_cac = $9 | ||||
| 	if (units == "mW") { | ||||
| 		if (power == 100) { | ||||
| 			power = 20 | ||||
|  | @ -78,7 +79,12 @@ function parse_reg_rule() | |||
| 		} else { | ||||
| 			print "Unknown power value in database!" | ||||
| 		} | ||||
| 	} else { | ||||
| 		dfs_cac = $8 | ||||
| 	} | ||||
| 	sub(/,/, "", dfs_cac) | ||||
| 	sub(/\(/, "", dfs_cac) | ||||
| 	sub(/\)/, "", dfs_cac) | ||||
| 	flagstr = "" | ||||
| 	for (i=8; i<=NF; i++) | ||||
| 		flagstr = flagstr $i | ||||
|  | @ -111,7 +117,7 @@ function parse_reg_rule() | |||
| 
 | ||||
| 	} | ||||
| 	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++ | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -82,7 +82,7 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, | |||
| } | ||||
| 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 cfg80211_ibss_params *params, | ||||
| 				struct cfg80211_cached_keys *connkeys) | ||||
|  |  | |||
|  | @ -778,7 +778,7 @@ void cfg80211_cac_event(struct net_device *netdev, | |||
| 	switch (event) { | ||||
| 	case NL80211_RADAR_CAC_FINISHED: | ||||
| 		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)); | ||||
| 		cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); | ||||
| 		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, | ||||
| 					time)) | ||||
| 				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 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] = { | ||||
|  | @ -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_POWER_RULE_MAX_ANT_GAIN]	= { .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[], | ||||
|  | @ -4649,6 +4654,10 @@ static int parse_reg_rule(struct nlattr *tb[], | |||
| 		power_rule->max_antenna_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; | ||||
| } | ||||
| 
 | ||||
|  | @ -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, | ||||
| 				power_rule->max_antenna_gain) || | ||||
| 		    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; | ||||
| 
 | ||||
| 		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 cfg80211_chan_def chandef; | ||||
| 	enum nl80211_dfs_regions dfs_region; | ||||
| 	unsigned int cac_time_ms; | ||||
| 	int err; | ||||
| 
 | ||||
| 	dfs_region = reg_get_dfs_region(wdev->wiphy); | ||||
|  | @ -5803,11 +5815,17 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
| 	if (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) { | ||||
| 		wdev->chandef = chandef; | ||||
| 		wdev->cac_started = true; | ||||
| 		wdev->cac_start_time = jiffies; | ||||
| 		wdev->cac_time_ms = cac_time_ms; | ||||
| 	} | ||||
| 	return err; | ||||
| } | ||||
|  |  | |||
|  | @ -91,10 +91,6 @@ static struct regulatory_request __rcu *last_request = | |||
| /* To trigger userspace events */ | ||||
| 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, | ||||
|  * 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_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) | ||||
| 		kfree_rcu(lr, rcu_head); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
|  | @ -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 | ||||
|  * basis in userspace. Country information is filled in by | ||||
|  * reg_device_uevent | ||||
|  * basis in userspace. | ||||
|  */ | ||||
| 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)) | ||||
| 		pr_info("Calling CRDA for country: %c%c\n", | ||||
| 			alpha2[0], alpha2[1]); | ||||
|  | @ -501,7 +504,7 @@ static int call_crda(const char *alpha2) | |||
| 	/* query internal regulatory database (if it exists) */ | ||||
| 	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 | ||||
|  | @ -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_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)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
|  | @ -1077,6 +1083,14 @@ static void handle_channel(struct wiphy *wiphy, | |||
| 		min_t(int, chan->orig_mag, | ||||
| 		      MBI_TO_DBI(power_rule->max_antenna_gain)); | ||||
| 	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) { | ||||
| 		/*
 | ||||
| 		 * 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_freq_range *freq_range = 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++) { | ||||
| 		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", | ||||
| 				 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 | ||||
| 		 * in certain regions | ||||
| 		 */ | ||||
| 		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->end_freq_khz, | ||||
| 				bw, | ||||
| 				power_rule->max_antenna_gain, | ||||
| 				power_rule->max_eirp); | ||||
| 				power_rule->max_eirp, | ||||
| 				cac_time); | ||||
| 		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->end_freq_khz, | ||||
| 				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; | ||||
| 
 | ||||
| 	if (is_world_regdom(rd->alpha2)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (!regdom_changes(rd->alpha2)) | ||||
| 		return -EALREADY; | ||||
| 
 | ||||
|  | @ -2552,26 +2572,6 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
| 	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) | ||||
| { | ||||
| 	struct regulatory_request *lr; | ||||
|  | @ -2622,8 +2622,6 @@ int __init regulatory_init(void) | |||
| 	if (IS_ERR(reg_pdev)) | ||||
| 		return PTR_ERR(reg_pdev); | ||||
| 
 | ||||
| 	reg_pdev->dev.type = ®_device_type; | ||||
| 
 | ||||
| 	spin_lock_init(®_requests_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, | ||||
| 			 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_deregister(struct wiphy *wiphy); | ||||
| 
 | ||||
|  |  | |||
|  | @ -659,9 +659,6 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *dev, | |||
| 			continue; | ||||
| 		if (ssidlen && ie[1] != ssidlen) | ||||
| 			continue; | ||||
| 		/* that would be odd ... */ | ||||
| 		if (bss->pub.beacon_ies) | ||||
| 			continue; | ||||
| 		if (WARN_ON_ONCE(bss->pub.hidden_beacon_bss)) | ||||
| 			continue; | ||||
| 		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. */ | ||||
| static struct cfg80211_internal_bss * | ||||
| 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; | ||||
| 
 | ||||
|  | @ -765,6 +763,11 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
| 		} | ||||
| 
 | ||||
| 		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.capability = tmp->pub.capability; | ||||
| 		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. */ | ||||
| struct cfg80211_bss* | ||||
| cfg80211_inform_bss_width(struct wiphy *wiphy, | ||||
| 			  struct ieee80211_channel *channel, | ||||
| 			  struct ieee80211_channel *rx_channel, | ||||
| 			  enum nl80211_bss_scan_width scan_width, | ||||
| 			  const u8 *bssid, u64 tsf, u16 capability, | ||||
| 			  u16 beacon_interval, const u8 *ie, size_t ielen, | ||||
| 			  s32 signal, gfp_t gfp) | ||||
| { | ||||
| 	struct cfg80211_bss_ies *ies; | ||||
| 	struct ieee80211_channel *channel; | ||||
| 	struct cfg80211_internal_bss tmp = {}, *res; | ||||
| 
 | ||||
| 	if (WARN_ON(!wiphy)) | ||||
|  | @ -885,7 +889,7 @@ cfg80211_inform_bss_width(struct wiphy *wiphy, | |||
| 			(signal < 0 || signal > 100))) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	channel = cfg80211_get_bss_channel(wiphy, ie, ielen, channel); | ||||
| 	channel = cfg80211_get_bss_channel(wiphy, ie, ielen, rx_channel); | ||||
| 	if (!channel) | ||||
| 		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.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) | ||||
| 		return NULL; | ||||
| 
 | ||||
|  | @ -929,20 +934,21 @@ EXPORT_SYMBOL(cfg80211_inform_bss_width); | |||
| /* Returned bss is reference counted and must be cleaned up appropriately. */ | ||||
| struct cfg80211_bss * | ||||
| cfg80211_inform_bss_width_frame(struct wiphy *wiphy, | ||||
| 				struct ieee80211_channel *channel, | ||||
| 				struct ieee80211_channel *rx_channel, | ||||
| 				enum nl80211_bss_scan_width scan_width, | ||||
| 				struct ieee80211_mgmt *mgmt, size_t len, | ||||
| 				s32 signal, gfp_t gfp) | ||||
| { | ||||
| 	struct cfg80211_internal_bss tmp = {}, *res; | ||||
| 	struct cfg80211_bss_ies *ies; | ||||
| 	struct ieee80211_channel *channel; | ||||
| 	size_t ielen = len - 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)); | ||||
| 
 | ||||
| 	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); | ||||
| 
 | ||||
| 	if (WARN_ON(!mgmt)) | ||||
|  | @ -959,7 +965,7 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy, | |||
| 		return NULL; | ||||
| 
 | ||||
| 	channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable, | ||||
| 					   ielen, channel); | ||||
| 					   ielen, rx_channel); | ||||
| 	if (!channel) | ||||
| 		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.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) | ||||
| 		return NULL; | ||||
| 
 | ||||
|  |  | |||
|  | @ -64,7 +64,6 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
| 	int n_channels, err; | ||||
| 
 | ||||
| 	ASSERT_RTNL(); | ||||
| 	ASSERT_RDEV_LOCK(rdev); | ||||
| 	ASSERT_WDEV_LOCK(wdev); | ||||
| 
 | ||||
| 	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; | ||||
| 
 | ||||
| 	ASSERT_RTNL(); | ||||
| 	ASSERT_RDEV_LOCK(rdev); | ||||
| 
 | ||||
| 	list_for_each_entry(wdev, &rdev->wdev_list, list) | ||||
| 		cfg80211_process_wdev_events(wdev); | ||||
|  | @ -851,7 +850,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
| 	int err; | ||||
| 	enum nl80211_iftype otype = dev->ieee80211_ptr->iftype; | ||||
| 
 | ||||
| 	ASSERT_RDEV_LOCK(rdev); | ||||
| 	ASSERT_RTNL(); | ||||
| 
 | ||||
| 	/* don't support changing VLANs, you just re-create them */ | ||||
| 	if (otype == NL80211_IFTYPE_AP_VLAN) | ||||
|  | @ -886,7 +885,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
| 
 | ||||
| 		switch (otype) { | ||||
| 		case NL80211_IFTYPE_AP: | ||||
| 			cfg80211_stop_ap(rdev, dev); | ||||
| 			cfg80211_stop_ap(rdev, dev, true); | ||||
| 			break; | ||||
| 		case NL80211_IFTYPE_ADHOC: | ||||
| 			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; | ||||
| 	int err, i; | ||||
| 
 | ||||
| 	ASSERT_RDEV_LOCK(rdev); | ||||
| 	ASSERT_RTNL(); | ||||
| 	ASSERT_WDEV_LOCK(wdev); | ||||
| 
 | ||||
| 	if (!netif_running(wdev->netdev)) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 John W. Linville
				John W. Linville