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

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
...@@ -3146,8 +3146,8 @@ struct cfg80211_cached_keys; ...@@ -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 { ...@@ -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;
......
...@@ -27,7 +27,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, ...@@ -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);
......
...@@ -642,7 +642,8 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, ...@@ -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, ...@@ -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, ...@@ -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:
......
...@@ -443,7 +443,8 @@ static inline unsigned int elapsed_jiffies_msecs(unsigned long start) ...@@ -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);
......
...@@ -122,6 +122,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, ...@@ -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) ...@@ -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;
......
...@@ -195,7 +195,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, ...@@ -195,7 +195,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
if (!err) { if (!err) {
memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
wdev->mesh_id_len = setup->mesh_id_len; wdev->mesh_id_len = setup->mesh_id_len;
wdev->channel = setup->chandef.chan; wdev->chandef = setup->chandef;
} }
return err; return err;
...@@ -244,7 +244,7 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, ...@@ -244,7 +244,7 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
chandef->chan); chandef->chan);
if (!err) if (!err)
wdev->channel = chandef->chan; wdev->chandef = *chandef;
return err; return err;
} }
...@@ -276,7 +276,7 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, ...@@ -276,7 +276,7 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
err = rdev_leave_mesh(rdev, dev); err = rdev_leave_mesh(rdev, dev);
if (!err) { if (!err) {
wdev->mesh_id_len = 0; wdev->mesh_id_len = 0;
wdev->channel = NULL; memset(&wdev->chandef, 0, sizeof(wdev->chandef));
rdev_set_qos_map(rdev, dev, NULL); rdev_set_qos_map(rdev, dev, NULL);
} }
......
...@@ -772,7 +772,7 @@ void cfg80211_cac_event(struct net_device *netdev, ...@@ -772,7 +772,7 @@ void cfg80211_cac_event(struct net_device *netdev,
if (WARN_ON(!wdev->cac_started)) if (WARN_ON(!wdev->cac_started))
return; return;
if (WARN_ON(!wdev->channel)) if (WARN_ON(!wdev->chandef.chan))
return; return;
switch (event) { switch (event) {
......
...@@ -3281,7 +3281,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) ...@@ -3281,7 +3281,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
if (!err) { if (!err) {
wdev->preset_chandef = params.chandef; wdev->preset_chandef = params.chandef;
wdev->beacon_interval = params.beacon_interval; wdev->beacon_interval = params.beacon_interval;
wdev->channel = params.chandef.chan; wdev->chandef = params.chandef;
wdev->ssid_len = params.ssid_len; wdev->ssid_len = params.ssid_len;
memcpy(wdev->ssid, params.ssid, wdev->ssid_len); memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
} }
...@@ -5797,7 +5797,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, ...@@ -5797,7 +5797,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef);
if (!err) { if (!err) {
wdev->channel = chandef.chan; wdev->chandef = chandef;
wdev->cac_started = true; wdev->cac_started = true;
wdev->cac_start_time = jiffies; wdev->cac_start_time = jiffies;
} }
...@@ -11215,7 +11215,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, ...@@ -11215,7 +11215,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
wdev->iftype != NL80211_IFTYPE_MESH_POINT)) wdev->iftype != NL80211_IFTYPE_MESH_POINT))
return; return;
wdev->channel = chandef->chan; wdev->chandef = *chandef;
wdev->preset_chandef = *chandef; wdev->preset_chandef = *chandef;
nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
} }
......
...@@ -1357,7 +1357,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, ...@@ -1357,7 +1357,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
*/ */
mutex_lock_nested(&wdev_iter->mtx, 1); mutex_lock_nested(&wdev_iter->mtx, 1);
__acquire(wdev_iter->mtx); __acquire(wdev_iter->mtx);
cfg80211_get_chan_state(wdev_iter, &ch, &chmode); cfg80211_get_chan_state(wdev_iter, &ch, &chmode, &radar_detect);
wdev_unlock(wdev_iter); wdev_unlock(wdev_iter);
switch (chmode) { switch (chmode) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment