diff options
Diffstat (limited to 'net/mac80211/ibss.c')
| -rw-r--r-- | net/mac80211/ibss.c | 49 | 
1 files changed, 44 insertions, 5 deletions
| diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 21a0b8835cb3..275bbb2c1a5a 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -229,6 +229,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,  	struct beacon_data *presp;  	enum nl80211_bss_scan_width scan_width;  	bool have_higher_than_11mbit; +	bool radar_required = false;  	int err;  	sdata_assert_lock(sdata); @@ -273,6 +274,23 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,  		}  		chandef.width = NL80211_CHAN_WIDTH_20;  		chandef.center_freq1 = chan->center_freq; +		/* check again for downgraded chandef */ +		if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { +			sdata_info(sdata, +				   "Failed to join IBSS, beacons forbidden\n"); +			return; +		} +	} + +	err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, +					    &chandef); +	if (err > 0) { +		if (!ifibss->userspace_handles_dfs) { +			sdata_info(sdata, +				   "Failed to join IBSS, DFS channel without control program\n"); +			return; +		} +		radar_required = true;  	}  	ieee80211_vif_release_channel(sdata); @@ -297,6 +315,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,  	rcu_assign_pointer(ifibss->presp, presp);  	mgmt = (void *)presp->head; +	sdata->radar_required = radar_required;  	sdata->vif.bss_conf.enable_beacon = true;  	sdata->vif.bss_conf.beacon_int = beacon_int;  	sdata->vif.bss_conf.basic_rates = basic_rates; @@ -796,6 +815,21 @@ static void ieee80211_csa_connection_drop_work(struct work_struct *work)  	ieee80211_queue_work(&sdata->local->hw, &sdata->work);  } +static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata) +{ +	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; +	int err; + +	/* if the current channel is a DFS channel, mark the channel as +	 * unavailable. +	 */ +	err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy, +					    &ifibss->chandef); +	if (err > 0) +		cfg80211_radar_event(sdata->local->hw.wiphy, &ifibss->chandef, +				     GFP_ATOMIC); +} +  static bool  ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,  				  struct ieee802_11_elems *elems, @@ -880,8 +914,7 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,  		goto disconnect;  	} -	if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, ¶ms.chandef, -				     IEEE80211_CHAN_DISABLED)) { +	if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, ¶ms.chandef)) {  		sdata_info(sdata,  			   "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",  			   ifibss->bssid, @@ -897,10 +930,11 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,  	if (err < 0)  		goto disconnect;  	if (err) { -		params.radar_required = true; +		/* IBSS-DFS only allowed with a control program */ +		if (!ifibss->userspace_handles_dfs) +			goto disconnect; -		/* TODO: IBSS-DFS not (yet) supported, disconnect. */ -		goto disconnect; +		params.radar_required = true;  	}  	rcu_read_lock(); @@ -947,12 +981,16 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,  	ieee80211_bss_info_change_notify(sdata, err);  	drv_channel_switch_beacon(sdata, ¶ms.chandef); +	ieee80211_ibss_csa_mark_radar(sdata); +  	return true;  disconnect:  	ibss_dbg(sdata, "Can't handle channel switch, disconnect\n");  	ieee80211_queue_work(&sdata->local->hw,  			     &ifibss->csa_connection_drop_work); +	ieee80211_ibss_csa_mark_radar(sdata); +  	return true;  } @@ -1688,6 +1726,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,  	sdata->u.ibss.privacy = params->privacy;  	sdata->u.ibss.control_port = params->control_port; +	sdata->u.ibss.userspace_handles_dfs = params->userspace_handles_dfs;  	sdata->u.ibss.basic_rates = params->basic_rates;  	/* fix basic_rates if channel does not support these rates */ | 
