Commit 9e0e2961 authored by Michal Kazior's avatar Michal Kazior Committed by Johannes Berg
Browse files

cfg80211: consider existing DFS interfaces



It was possible to break interface combinations in
the following way:

 combo 1: iftype = AP, num_ifaces = 2, num_chans = 2,
 combo 2: iftype = AP, num_ifaces = 1, num_chans = 1, radar = HT20

With the above interface combinations it was
possible to:

 step 1. start AP on DFS channel by matching combo 2
 step 2. start AP on non-DFS channel by matching combo 1

This was possible beacuse (step 2) did not consider
if other interfaces require radar detection.

The patch changes how cfg80211 tracks channels -
instead of channel itself now a complete chandef
is stored.

Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent fe94f3a4
Loading
Loading
Loading
Loading
+3 −5
Original line number Original line Diff line number Diff line
@@ -3146,8 +3146,8 @@ struct cfg80211_cached_keys;
 * @identifier: (private) Identifier used in nl80211 to identify this
 * @identifier: (private) Identifier used in nl80211 to identify this
 *	wireless device if it has no netdev
 *	wireless device if it has no netdev
 * @current_bss: (private) Used by the internal configuration code
 * @current_bss: (private) Used by the internal configuration code
 * @channel: (private) Used by the internal configuration code to track
 * @chandef: (private) Used by the internal configuration code to track
 *	the user-set AP, monitor and WDS channel
 *	the user-set channel definition.
 * @preset_chandef: (private) Used by the internal configuration code to
 * @preset_chandef: (private) Used by the internal configuration code to
 *	track the channel to be used for AP later
 *	track the channel to be used for AP later
 * @bssid: (private) Used by the internal configuration code
 * @bssid: (private) Used by the internal configuration code
@@ -3211,9 +3211,7 @@ struct wireless_dev {


	struct cfg80211_internal_bss *current_bss; /* associated / joined */
	struct cfg80211_internal_bss *current_bss; /* associated / joined */
	struct cfg80211_chan_def preset_chandef;
	struct cfg80211_chan_def preset_chandef;

	struct cfg80211_chan_def chandef;
	/* for AP and mesh channel tracking */
	struct ieee80211_channel *channel;


	bool ibss_fixed;
	bool ibss_fixed;
	bool ibss_dfs_possible;
	bool ibss_dfs_possible;
+1 −1
Original line number Original line Diff line number Diff line
@@ -27,7 +27,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
	err = rdev_stop_ap(rdev, dev);
	err = rdev_stop_ap(rdev, dev);
	if (!err) {
	if (!err) {
		wdev->beacon_interval = 0;
		wdev->beacon_interval = 0;
		wdev->channel = NULL;
		memset(&wdev->chandef, 0, sizeof(wdev->chandef));
		wdev->ssid_len = 0;
		wdev->ssid_len = 0;
		rdev_set_qos_map(rdev, dev, NULL);
		rdev_set_qos_map(rdev, dev, NULL);
		nl80211_send_ap_stopped(wdev);
		nl80211_send_ap_stopped(wdev);
+19 −4
Original line number Original line Diff line number Diff line
@@ -642,7 +642,8 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
void
void
cfg80211_get_chan_state(struct wireless_dev *wdev,
cfg80211_get_chan_state(struct wireless_dev *wdev,
		        struct ieee80211_channel **chan,
		        struct ieee80211_channel **chan,
		        enum cfg80211_chan_mode *chanmode)
		        enum cfg80211_chan_mode *chanmode,
		        u8 *radar_detect)
{
{
	*chan = NULL;
	*chan = NULL;
	*chanmode = CHAN_MODE_UNDEFINED;
	*chanmode = CHAN_MODE_UNDEFINED;
@@ -660,6 +661,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
				     !wdev->ibss_dfs_possible)
				     !wdev->ibss_dfs_possible)
				  ? CHAN_MODE_SHARED
				  ? CHAN_MODE_SHARED
				  : CHAN_MODE_EXCLUSIVE;
				  : CHAN_MODE_EXCLUSIVE;

			/* consider worst-case - IBSS can try to return to the
			 * original user-specified channel as creator */
			if (wdev->ibss_dfs_possible)
				*radar_detect |= BIT(wdev->chandef.width);
			return;
			return;
		}
		}
		break;
		break;
@@ -674,17 +680,26 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_AP:
	case NL80211_IFTYPE_P2P_GO:
	case NL80211_IFTYPE_P2P_GO:
		if (wdev->cac_started) {
		if (wdev->cac_started) {
			*chan = wdev->channel;
			*chan = wdev->chandef.chan;
			*chanmode = CHAN_MODE_SHARED;
			*chanmode = CHAN_MODE_SHARED;
			*radar_detect |= BIT(wdev->chandef.width);
		} else if (wdev->beacon_interval) {
		} else if (wdev->beacon_interval) {
			*chan = wdev->channel;
			*chan = wdev->chandef.chan;
			*chanmode = CHAN_MODE_SHARED;
			*chanmode = CHAN_MODE_SHARED;

			if (cfg80211_chandef_dfs_required(wdev->wiphy,
							  &wdev->chandef))
				*radar_detect |= BIT(wdev->chandef.width);
		}
		}
		return;
		return;
	case NL80211_IFTYPE_MESH_POINT:
	case NL80211_IFTYPE_MESH_POINT:
		if (wdev->mesh_id_len) {
		if (wdev->mesh_id_len) {
			*chan = wdev->channel;
			*chan = wdev->chandef.chan;
			*chanmode = CHAN_MODE_SHARED;
			*chanmode = CHAN_MODE_SHARED;

			if (cfg80211_chandef_dfs_required(wdev->wiphy,
							  &wdev->chandef))
				*radar_detect |= BIT(wdev->chandef.width);
		}
		}
		return;
		return;
	case NL80211_IFTYPE_MONITOR:
	case NL80211_IFTYPE_MONITOR:
+2 −1
Original line number Original line Diff line number Diff line
@@ -443,7 +443,8 @@ static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
void
void
cfg80211_get_chan_state(struct wireless_dev *wdev,
cfg80211_get_chan_state(struct wireless_dev *wdev,
		        struct ieee80211_channel **chan,
		        struct ieee80211_channel **chan,
		        enum cfg80211_chan_mode *chanmode);
		        enum cfg80211_chan_mode *chanmode,
		        u8 *radar_detect);


int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
				 struct cfg80211_chan_def *chandef);
				 struct cfg80211_chan_def *chandef);
+2 −0
Original line number Original line Diff line number Diff line
@@ -122,6 +122,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,


	wdev->ibss_fixed = params->channel_fixed;
	wdev->ibss_fixed = params->channel_fixed;
	wdev->ibss_dfs_possible = params->userspace_handles_dfs;
	wdev->ibss_dfs_possible = params->userspace_handles_dfs;
	wdev->chandef = params->chandef;
#ifdef CONFIG_CFG80211_WEXT
#ifdef CONFIG_CFG80211_WEXT
	wdev->wext.ibss.chandef = params->chandef;
	wdev->wext.ibss.chandef = params->chandef;
#endif
#endif
@@ -205,6 +206,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)


	wdev->current_bss = NULL;
	wdev->current_bss = NULL;
	wdev->ssid_len = 0;
	wdev->ssid_len = 0;
	memset(&wdev->chandef, 0, sizeof(wdev->chandef));
#ifdef CONFIG_CFG80211_WEXT
#ifdef CONFIG_CFG80211_WEXT
	if (!nowext)
	if (!nowext)
		wdev->wext.ibss.ssid_len = 0;
		wdev->wext.ibss.ssid_len = 0;
Loading