diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2014-01-29 08:22:27 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2014-02-04 15:58:17 -0500 |
commit | 9e0e29615a2077be852b1245b57c5b00fa609522 (patch) | |
tree | 73d899373e01efe1fd72a895d8e2fe2f6bc8fcb2 /net | |
parent | fe94f3a4ffaa20c7470038c69ffc8e545ef5f90a (diff) |
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>
Diffstat (limited to 'net')
-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 |
8 files changed, 32 insertions, 14 deletions
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, | |||
27 | err = rdev_stop_ap(rdev, dev); | 27 | err = rdev_stop_ap(rdev, dev); |
28 | if (!err) { | 28 | if (!err) { |
29 | wdev->beacon_interval = 0; | 29 | wdev->beacon_interval = 0; |
30 | wdev->channel = NULL; | 30 | memset(&wdev->chandef, 0, sizeof(wdev->chandef)); |
31 | wdev->ssid_len = 0; | 31 | wdev->ssid_len = 0; |
32 | rdev_set_qos_map(rdev, dev, NULL); | 32 | rdev_set_qos_map(rdev, dev, NULL); |
33 | nl80211_send_ap_stopped(wdev); | 33 | 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, | |||
642 | void | 642 | void |
643 | cfg80211_get_chan_state(struct wireless_dev *wdev, | 643 | cfg80211_get_chan_state(struct wireless_dev *wdev, |
644 | struct ieee80211_channel **chan, | 644 | struct ieee80211_channel **chan, |
645 | enum cfg80211_chan_mode *chanmode) | 645 | enum cfg80211_chan_mode *chanmode, |
646 | u8 *radar_detect) | ||
646 | { | 647 | { |
647 | *chan = NULL; | 648 | *chan = NULL; |
648 | *chanmode = CHAN_MODE_UNDEFINED; | 649 | *chanmode = CHAN_MODE_UNDEFINED; |
@@ -660,6 +661,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
660 | !wdev->ibss_dfs_possible) | 661 | !wdev->ibss_dfs_possible) |
661 | ? CHAN_MODE_SHARED | 662 | ? CHAN_MODE_SHARED |
662 | : CHAN_MODE_EXCLUSIVE; | 663 | : CHAN_MODE_EXCLUSIVE; |
664 | |||
665 | /* consider worst-case - IBSS can try to return to the | ||
666 | * original user-specified channel as creator */ | ||
667 | if (wdev->ibss_dfs_possible) | ||
668 | *radar_detect |= BIT(wdev->chandef.width); | ||
663 | return; | 669 | return; |
664 | } | 670 | } |
665 | break; | 671 | break; |
@@ -674,17 +680,26 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
674 | case NL80211_IFTYPE_AP: | 680 | case NL80211_IFTYPE_AP: |
675 | case NL80211_IFTYPE_P2P_GO: | 681 | case NL80211_IFTYPE_P2P_GO: |
676 | if (wdev->cac_started) { | 682 | if (wdev->cac_started) { |
677 | *chan = wdev->channel; | 683 | *chan = wdev->chandef.chan; |
678 | *chanmode = CHAN_MODE_SHARED; | 684 | *chanmode = CHAN_MODE_SHARED; |
685 | *radar_detect |= BIT(wdev->chandef.width); | ||
679 | } else if (wdev->beacon_interval) { | 686 | } else if (wdev->beacon_interval) { |
680 | *chan = wdev->channel; | 687 | *chan = wdev->chandef.chan; |
681 | *chanmode = CHAN_MODE_SHARED; | 688 | *chanmode = CHAN_MODE_SHARED; |
689 | |||
690 | if (cfg80211_chandef_dfs_required(wdev->wiphy, | ||
691 | &wdev->chandef)) | ||
692 | *radar_detect |= BIT(wdev->chandef.width); | ||
682 | } | 693 | } |
683 | return; | 694 | return; |
684 | case NL80211_IFTYPE_MESH_POINT: | 695 | case NL80211_IFTYPE_MESH_POINT: |
685 | if (wdev->mesh_id_len) { | 696 | if (wdev->mesh_id_len) { |
686 | *chan = wdev->channel; | 697 | *chan = wdev->chandef.chan; |
687 | *chanmode = CHAN_MODE_SHARED; | 698 | *chanmode = CHAN_MODE_SHARED; |
699 | |||
700 | if (cfg80211_chandef_dfs_required(wdev->wiphy, | ||
701 | &wdev->chandef)) | ||
702 | *radar_detect |= BIT(wdev->chandef.width); | ||
688 | } | 703 | } |
689 | return; | 704 | return; |
690 | case NL80211_IFTYPE_MONITOR: | 705 | 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) | |||
443 | void | 443 | void |
444 | cfg80211_get_chan_state(struct wireless_dev *wdev, | 444 | cfg80211_get_chan_state(struct wireless_dev *wdev, |
445 | struct ieee80211_channel **chan, | 445 | struct ieee80211_channel **chan, |
446 | enum cfg80211_chan_mode *chanmode); | 446 | enum cfg80211_chan_mode *chanmode, |
447 | u8 *radar_detect); | ||
447 | 448 | ||
448 | int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, | 449 | int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, |
449 | struct cfg80211_chan_def *chandef); | 450 | 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, | |||
122 | 122 | ||
123 | wdev->ibss_fixed = params->channel_fixed; | 123 | wdev->ibss_fixed = params->channel_fixed; |
124 | wdev->ibss_dfs_possible = params->userspace_handles_dfs; | 124 | wdev->ibss_dfs_possible = params->userspace_handles_dfs; |
125 | wdev->chandef = params->chandef; | ||
125 | #ifdef CONFIG_CFG80211_WEXT | 126 | #ifdef CONFIG_CFG80211_WEXT |
126 | wdev->wext.ibss.chandef = params->chandef; | 127 | wdev->wext.ibss.chandef = params->chandef; |
127 | #endif | 128 | #endif |
@@ -205,6 +206,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) | |||
205 | 206 | ||
206 | wdev->current_bss = NULL; | 207 | wdev->current_bss = NULL; |
207 | wdev->ssid_len = 0; | 208 | wdev->ssid_len = 0; |
209 | memset(&wdev->chandef, 0, sizeof(wdev->chandef)); | ||
208 | #ifdef CONFIG_CFG80211_WEXT | 210 | #ifdef CONFIG_CFG80211_WEXT |
209 | if (!nowext) | 211 | if (!nowext) |
210 | wdev->wext.ibss.ssid_len = 0; | 212 | 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, | |||
195 | if (!err) { | 195 | if (!err) { |
196 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); | 196 | memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); |
197 | wdev->mesh_id_len = setup->mesh_id_len; | 197 | wdev->mesh_id_len = setup->mesh_id_len; |
198 | wdev->channel = setup->chandef.chan; | 198 | wdev->chandef = setup->chandef; |
199 | } | 199 | } |
200 | 200 | ||
201 | return err; | 201 | return err; |
@@ -244,7 +244,7 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, | |||
244 | err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, | 244 | err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, |
245 | chandef->chan); | 245 | chandef->chan); |
246 | if (!err) | 246 | if (!err) |
247 | wdev->channel = chandef->chan; | 247 | wdev->chandef = *chandef; |
248 | 248 | ||
249 | return err; | 249 | return err; |
250 | } | 250 | } |
@@ -276,7 +276,7 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, | |||
276 | err = rdev_leave_mesh(rdev, dev); | 276 | err = rdev_leave_mesh(rdev, dev); |
277 | if (!err) { | 277 | if (!err) { |
278 | wdev->mesh_id_len = 0; | 278 | wdev->mesh_id_len = 0; |
279 | wdev->channel = NULL; | 279 | memset(&wdev->chandef, 0, sizeof(wdev->chandef)); |
280 | rdev_set_qos_map(rdev, dev, NULL); | 280 | rdev_set_qos_map(rdev, dev, NULL); |
281 | } | 281 | } |
282 | 282 | ||
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, | |||
772 | if (WARN_ON(!wdev->cac_started)) | 772 | if (WARN_ON(!wdev->cac_started)) |
773 | return; | 773 | return; |
774 | 774 | ||
775 | if (WARN_ON(!wdev->channel)) | 775 | if (WARN_ON(!wdev->chandef.chan)) |
776 | return; | 776 | return; |
777 | 777 | ||
778 | switch (event) { | 778 | 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) | |||
3281 | if (!err) { | 3281 | if (!err) { |
3282 | wdev->preset_chandef = params.chandef; | 3282 | wdev->preset_chandef = params.chandef; |
3283 | wdev->beacon_interval = params.beacon_interval; | 3283 | wdev->beacon_interval = params.beacon_interval; |
3284 | wdev->channel = params.chandef.chan; | 3284 | wdev->chandef = params.chandef; |
3285 | wdev->ssid_len = params.ssid_len; | 3285 | wdev->ssid_len = params.ssid_len; |
3286 | memcpy(wdev->ssid, params.ssid, wdev->ssid_len); | 3286 | memcpy(wdev->ssid, params.ssid, wdev->ssid_len); |
3287 | } | 3287 | } |
@@ -5797,7 +5797,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
5797 | 5797 | ||
5798 | err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); | 5798 | err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); |
5799 | if (!err) { | 5799 | if (!err) { |
5800 | wdev->channel = chandef.chan; | 5800 | wdev->chandef = chandef; |
5801 | wdev->cac_started = true; | 5801 | wdev->cac_started = true; |
5802 | wdev->cac_start_time = jiffies; | 5802 | wdev->cac_start_time = jiffies; |
5803 | } | 5803 | } |
@@ -11215,7 +11215,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, | |||
11215 | wdev->iftype != NL80211_IFTYPE_MESH_POINT)) | 11215 | wdev->iftype != NL80211_IFTYPE_MESH_POINT)) |
11216 | return; | 11216 | return; |
11217 | 11217 | ||
11218 | wdev->channel = chandef->chan; | 11218 | wdev->chandef = *chandef; |
11219 | wdev->preset_chandef = *chandef; | 11219 | wdev->preset_chandef = *chandef; |
11220 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); | 11220 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); |
11221 | } | 11221 | } |
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, | |||
1357 | */ | 1357 | */ |
1358 | mutex_lock_nested(&wdev_iter->mtx, 1); | 1358 | mutex_lock_nested(&wdev_iter->mtx, 1); |
1359 | __acquire(wdev_iter->mtx); | 1359 | __acquire(wdev_iter->mtx); |
1360 | cfg80211_get_chan_state(wdev_iter, &ch, &chmode); | 1360 | cfg80211_get_chan_state(wdev_iter, &ch, &chmode, &radar_detect); |
1361 | wdev_unlock(wdev_iter); | 1361 | wdev_unlock(wdev_iter); |
1362 | 1362 | ||
1363 | switch (chmode) { | 1363 | switch (chmode) { |