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: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
fe94f3a4ff
commit
9e0e29615a
9 changed files with 35 additions and 19 deletions
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
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:
|
||||||
|
|
|
@ -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,
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
@ -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,
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
*/
|
*/
|
||||||
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) {
|
||||||
|
|
Loading…
Reference in a new issue