aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/wext-sme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-08-07 11:22:35 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-14 09:13:42 -0400
commit59bbb6f7574bc693ed8313b98eac641116c95b94 (patch)
treeda24ed15c5e375782e79b3dab7022d2100a7987a /net/wireless/wext-sme.c
parentf26b32ed4bd5780855a79bb17fb1a431fa867dad (diff)
cfg80211: validate channel settings across interfaces
Currently, there's a problem that affects regulatory enforcement and connection stability, in that it is possible to switch the channel while connected to a network or joined to an IBSS. The problem comes from the fact that we only validate the channel against the current interface's type, not against any other interface. Thus, you have any type of interface up, additionally bring up a monitor mode interface and switch the channel on the monitor. This will obviously also switch the channel on the other interface. The problem now is that if you do that while sending beacons for IBSS mode, you can switch to a disabled channel or a channel that doesn't allow beaconing. Combined with a managed mode interface connected to an AP instead of an IBSS interface, you can easily break the connection that way. To fix this, this patch validates any channel change with all available interfaces, and disallows such changes on secondary interfaces if another interface is connected to an AP or joined to an IBSS. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/wext-sme.c')
-rw-r--r--net/wireless/wext-sme.c65
1 files changed, 36 insertions, 29 deletions
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index e4a054aceb5a..fe1a53639122 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -52,25 +52,31 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
52 52
53int cfg80211_mgd_wext_siwfreq(struct net_device *dev, 53int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
54 struct iw_request_info *info, 54 struct iw_request_info *info,
55 struct iw_freq *freq, char *extra) 55 struct iw_freq *wextfreq, char *extra)
56{ 56{
57 struct wireless_dev *wdev = dev->ieee80211_ptr; 57 struct wireless_dev *wdev = dev->ieee80211_ptr;
58 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 58 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
59 struct ieee80211_channel *chan; 59 struct ieee80211_channel *chan = NULL;
60 int err; 60 int err, freq;
61 61
62 /* call only for station! */ 62 /* call only for station! */
63 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) 63 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
64 return -EINVAL; 64 return -EINVAL;
65 65
66 chan = cfg80211_wext_freq(wdev->wiphy, freq); 66 freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
67 if (chan && IS_ERR(chan)) 67 if (freq < 0)
68 return PTR_ERR(chan); 68 return freq;
69 69
70 if (chan && (chan->flags & IEEE80211_CHAN_DISABLED)) 70 if (freq) {
71 return -EINVAL; 71 chan = ieee80211_get_channel(wdev->wiphy, freq);
72 if (!chan)
73 return -EINVAL;
74 if (chan->flags & IEEE80211_CHAN_DISABLED)
75 return -EINVAL;
76 }
72 77
73 cfg80211_lock_rdev(rdev); 78 cfg80211_lock_rdev(rdev);
79 mutex_lock(&rdev->devlist_mtx);
74 wdev_lock(wdev); 80 wdev_lock(wdev);
75 81
76 if (wdev->sme_state != CFG80211_SME_IDLE) { 82 if (wdev->sme_state != CFG80211_SME_IDLE) {
@@ -84,9 +90,8 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
84 /* if SSID set, we'll try right again, avoid event */ 90 /* if SSID set, we'll try right again, avoid event */
85 if (wdev->wext.connect.ssid_len) 91 if (wdev->wext.connect.ssid_len)
86 event = false; 92 event = false;
87 err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), 93 err = __cfg80211_disconnect(rdev, dev,
88 dev, WLAN_REASON_DEAUTH_LEAVING, 94 WLAN_REASON_DEAUTH_LEAVING, event);
89 event);
90 if (err) 95 if (err)
91 goto out; 96 goto out;
92 } 97 }
@@ -95,17 +100,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
95 wdev->wext.connect.channel = chan; 100 wdev->wext.connect.channel = chan;
96 101
97 /* SSID is not set, we just want to switch channel */ 102 /* SSID is not set, we just want to switch channel */
98 if (wdev->wext.connect.ssid_len && chan) { 103 if (chan && !wdev->wext.connect.ssid_len) {
99 err = -EOPNOTSUPP; 104 err = rdev_set_freq(rdev, freq, NL80211_CHAN_NO_HT);
100 if (rdev->ops->set_channel)
101 err = rdev->ops->set_channel(wdev->wiphy, chan,
102 NL80211_CHAN_NO_HT);
103 goto out; 105 goto out;
104 } 106 }
105 107
106 err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); 108 err = cfg80211_mgd_wext_connect(rdev, wdev);
107 out: 109 out:
108 wdev_unlock(wdev); 110 wdev_unlock(wdev);
111 mutex_unlock(&rdev->devlist_mtx);
109 cfg80211_unlock_rdev(rdev); 112 cfg80211_unlock_rdev(rdev);
110 return err; 113 return err;
111} 114}
@@ -143,6 +146,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
143 struct iw_point *data, char *ssid) 146 struct iw_point *data, char *ssid)
144{ 147{
145 struct wireless_dev *wdev = dev->ieee80211_ptr; 148 struct wireless_dev *wdev = dev->ieee80211_ptr;
149 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
146 size_t len = data->length; 150 size_t len = data->length;
147 int err; 151 int err;
148 152
@@ -157,7 +161,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
157 if (len > 0 && ssid[len - 1] == '\0') 161 if (len > 0 && ssid[len - 1] == '\0')
158 len--; 162 len--;
159 163
160 cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy)); 164 cfg80211_lock_rdev(rdev);
165 mutex_lock(&rdev->devlist_mtx);
161 wdev_lock(wdev); 166 wdev_lock(wdev);
162 167
163 err = 0; 168 err = 0;
@@ -173,9 +178,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
173 /* if SSID set now, we'll try to connect, avoid event */ 178 /* if SSID set now, we'll try to connect, avoid event */
174 if (len) 179 if (len)
175 event = false; 180 event = false;
176 err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), 181 err = __cfg80211_disconnect(rdev, dev,
177 dev, WLAN_REASON_DEAUTH_LEAVING, 182 WLAN_REASON_DEAUTH_LEAVING, event);
178 event);
179 if (err) 183 if (err)
180 goto out; 184 goto out;
181 } 185 }
@@ -186,10 +190,11 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
186 190
187 wdev->wext.connect.crypto.control_port = false; 191 wdev->wext.connect.crypto.control_port = false;
188 192
189 err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); 193 err = cfg80211_mgd_wext_connect(rdev, wdev);
190 out: 194 out:
191 wdev_unlock(wdev); 195 wdev_unlock(wdev);
192 cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); 196 mutex_unlock(&rdev->devlist_mtx);
197 cfg80211_unlock_rdev(rdev);
193 return err; 198 return err;
194} 199}
195 200
@@ -230,6 +235,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
230 struct sockaddr *ap_addr, char *extra) 235 struct sockaddr *ap_addr, char *extra)
231{ 236{
232 struct wireless_dev *wdev = dev->ieee80211_ptr; 237 struct wireless_dev *wdev = dev->ieee80211_ptr;
238 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
233 u8 *bssid = ap_addr->sa_data; 239 u8 *bssid = ap_addr->sa_data;
234 int err; 240 int err;
235 241
@@ -244,7 +250,8 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
244 if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) 250 if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
245 bssid = NULL; 251 bssid = NULL;
246 252
247 cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy)); 253 cfg80211_lock_rdev(rdev);
254 mutex_lock(&rdev->devlist_mtx);
248 wdev_lock(wdev); 255 wdev_lock(wdev);
249 256
250 if (wdev->sme_state != CFG80211_SME_IDLE) { 257 if (wdev->sme_state != CFG80211_SME_IDLE) {
@@ -258,9 +265,8 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
258 compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) 265 compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
259 goto out; 266 goto out;
260 267
261 err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), 268 err = __cfg80211_disconnect(rdev, dev,
262 dev, WLAN_REASON_DEAUTH_LEAVING, 269 WLAN_REASON_DEAUTH_LEAVING, false);
263 false);
264 if (err) 270 if (err)
265 goto out; 271 goto out;
266 } 272 }
@@ -271,10 +277,11 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
271 } else 277 } else
272 wdev->wext.connect.bssid = NULL; 278 wdev->wext.connect.bssid = NULL;
273 279
274 err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); 280 err = cfg80211_mgd_wext_connect(rdev, wdev);
275 out: 281 out:
276 wdev_unlock(wdev); 282 wdev_unlock(wdev);
277 cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy)); 283 mutex_unlock(&rdev->devlist_mtx);
284 cfg80211_unlock_rdev(rdev);
278 return err; 285 return err;
279} 286}
280 287