diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2014-01-29 14:22:27 +0100 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2014-02-04 21:58:17 +0100 |
commit | 9e0e29615a2077be852b1245b57c5b00fa609522 (patch) | |
tree | 73d899373e01efe1fd72a895d8e2fe2f6bc8fcb2 | |
parent | fe94f3a4ffaa20c7470038c69ffc8e545ef5f90a (diff) | |
download | linux-9e0e29615a2077be852b1245b57c5b00fa609522.tar.bz2 |
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>
-rw-r--r-- | include/net/cfg80211.h | 8 | ||||
-rw-r--r-- | net/wireless/ap.c | 2 | ||||
-rw-r--r-- | net/wireless/chan.c | 23 | ||||
-rw-r--r-- | net/wireless/core.h | 3 | ||||
-rw-r--r-- | net/wireless/ibss.c | 2 | ||||
-rw-r--r-- | net/wireless/mesh.c | 6 | ||||
-rw-r--r-- | net/wireless/mlme.c | 2 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 6 | ||||
-rw-r--r-- | net/wireless/util.c | 2 |
9 files changed, 35 insertions, 19 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index c68201d78b90..9f90554e88c4 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3146,8 +3146,8 @@ struct cfg80211_cached_keys; * @identifier: (private) Identifier used in nl80211 to identify this * wireless device if it has no netdev * @current_bss: (private) Used by the internal configuration code - * @channel: (private) Used by the internal configuration code to track - * the user-set AP, monitor and WDS channel + * @chandef: (private) Used by the internal configuration code to track + * the user-set channel definition. * @preset_chandef: (private) Used by the internal configuration code to * track the channel to be used for AP later * @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_chan_def preset_chandef; - - /* for AP and mesh channel tracking */ - struct ieee80211_channel *channel; + struct cfg80211_chan_def chandef; bool ibss_fixed; bool ibss_dfs_possible; diff --git a/net/wireless/ap.c b/net/wireless/ap.c index 4760d6554e62..68602be07cc1 100644 --- a/net/wireless/ap.c +++ b/net/wireless/ap.c @@ -27,7 +27,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, err = rdev_stop_ap(rdev, dev); if (!err) { wdev->beacon_interval = 0; - wdev->channel = NULL; + memset(&wdev->chandef, 0, sizeof(wdev->chandef)); wdev->ssid_len = 0; rdev_set_qos_map(rdev, dev, NULL); nl80211_send_ap_stopped(wdev); diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 78559b5bbd1f..f8ab7df1ab0d 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -642,7 +642,8 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, void cfg80211_get_chan_state(struct wireless_dev *wdev, struct ieee80211_channel **chan, - enum cfg80211_chan_mode *chanmode) + enum cfg80211_chan_mode *chanmode, + u8 *radar_detect) { *chan = NULL; *chanmode = CHAN_MODE_UNDEFINED; @@ -660,6 +661,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, !wdev->ibss_dfs_possible) ? CHAN_MODE_SHARED : 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; } break; @@ -674,17 +680,26 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: if (wdev->cac_started) { - *chan = wdev->channel; + *chan = wdev->chandef.chan; *chanmode = CHAN_MODE_SHARED; + *radar_detect |= BIT(wdev->chandef.width); } else if (wdev->beacon_interval) { - *chan = wdev->channel; + *chan = wdev->chandef.chan; *chanmode = CHAN_MODE_SHARED; + + if (cfg80211_chandef_dfs_required(wdev->wiphy, + &wdev->chandef)) + *radar_detect |= BIT(wdev->chandef.width); } return; case NL80211_IFTYPE_MESH_POINT: if (wdev->mesh_id_len) { - *chan = wdev->channel; + *chan = wdev->chandef.chan; *chanmode = CHAN_MODE_SHARED; + + if (cfg80211_chandef_dfs_required(wdev->wiphy, + &wdev->chandef)) + *radar_detect |= BIT(wdev->chandef.width); } return; case NL80211_IFTYPE_MONITOR: diff --git a/net/wireless/core.h b/net/wireless/core.h index 8a820f9c4a76..9895ab16c051 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -443,7 +443,8 @@ static inline unsigned int elapsed_jiffies_msecs(unsigned long start) void cfg80211_get_chan_state(struct wireless_dev *wdev, 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, struct cfg80211_chan_def *chandef); diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index e37e39c29dfb..1470b90e438f 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -122,6 +122,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, wdev->ibss_fixed = params->channel_fixed; wdev->ibss_dfs_possible = params->userspace_handles_dfs; + wdev->chandef = params->chandef; #ifdef CONFIG_CFG80211_WEXT wdev->wext.ibss.chandef = params->chandef; #endif @@ -205,6 +206,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) wdev->current_bss = NULL; wdev->ssid_len = 0; + memset(&wdev->chandef, 0, sizeof(wdev->chandef)); #ifdef CONFIG_CFG80211_WEXT if (!nowext) wdev->wext.ibss.ssid_len = 0; diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 885862447b63..d42a3fcb2f67 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -195,7 +195,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, if (!err) { memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); wdev->mesh_id_len = setup->mesh_id_len; - wdev->channel = setup->chandef.chan; + wdev->chandef = setup->chandef; } 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, chandef->chan); if (!err) - wdev->channel = chandef->chan; + wdev->chandef = *chandef; return err; } @@ -276,7 +276,7 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, err = rdev_leave_mesh(rdev, dev); if (!err) { wdev->mesh_id_len = 0; - wdev->channel = NULL; + memset(&wdev->chandef, 0, sizeof(wdev->chandef)); rdev_set_qos_map(rdev, dev, NULL); } diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 52cca05044a8..d47c9d127b1e 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -772,7 +772,7 @@ void cfg80211_cac_event(struct net_device *netdev, if (WARN_ON(!wdev->cac_started)) return; - if (WARN_ON(!wdev->channel)) + if (WARN_ON(!wdev->chandef.chan)) return; switch (event) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0a186013728c..be091ddd43a4 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3281,7 +3281,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) if (!err) { wdev->preset_chandef = params.chandef; wdev->beacon_interval = params.beacon_interval; - wdev->channel = params.chandef.chan; + wdev->chandef = params.chandef; wdev->ssid_len = params.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); if (!err) { - wdev->channel = chandef.chan; + wdev->chandef = chandef; wdev->cac_started = true; wdev->cac_start_time = jiffies; } @@ -11215,7 +11215,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, wdev->iftype != NL80211_IFTYPE_MESH_POINT)) return; - wdev->channel = chandef->chan; + wdev->chandef = *chandef; wdev->preset_chandef = *chandef; nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); } diff --git a/net/wireless/util.c b/net/wireless/util.c index 7526a4d8aa16..780b4546c9c7 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1357,7 +1357,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, */ mutex_lock_nested(&wdev_iter->mtx, 1); __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); switch (chmode) { |