cfg80211: consider existing DFS interfaces
authorMichal Kazior <michal.kazior@tieto.com>
Wed, 29 Jan 2014 13:22:27 +0000 (14:22 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 4 Feb 2014 20:58:17 +0000 (21:58 +0100)
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>
include/net/cfg80211.h
net/wireless/ap.c
net/wireless/chan.c
net/wireless/core.h
net/wireless/ibss.c
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/util.c

index c68201d78b9091d746a19849defd64aef1faf340..9f90554e88c48a1342c0d1116e1c47ba0b875d81 100644 (file)
@@ -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;
index 4760d6554e62c88862ddac7670c95359788b4342..68602be07cc10ae1ff0b4356e6e2a95492e34717 100644 (file)
@@ -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);
index 78559b5bbd1fe1d98c533f18dd1cc4fce4087baa..f8ab7df1ab0dc8f0a3bfadf13a6dfd08caa5dd54 100644 (file)
@@ -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:
index 8a820f9c4a766cc0d250b6d4c78be912753b3570..9895ab16c0510d2fcbf631d8120ec535beed7db8 100644 (file)
@@ -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);
index e37e39c29dfb82ada18f68fd3b065c92ff7a1093..1470b90e438f4bf6306be3591fdf6d376676ec5f 100644 (file)
@@ -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;
index 885862447b63c3434c0784924de2b984fcfedc25..d42a3fcb2f67ae0fb7a563f07ee74f96fa17fee7 100644 (file)
@@ -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);
        }
 
index 52cca05044a898b977927f2c9e540b00d6811634..d47c9d127b1eef3bef4e8d00f65dcf1392d70c2d 100644 (file)
@@ -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) {
index 0a186013728c5c454cf60a9ec926c86e1a548005..be091ddd43a4e23cefaa72296f923e9cc80c59b9 100644 (file)
@@ -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);
 }
index 7526a4d8aa16979e0577b1153885bf87afebb97c..780b4546c9c74c133d2de69ddcc352ca0979b8fe 100644 (file)
@@ -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) {
This page took 0.053214 seconds and 5 git commands to generate.