aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/ibss.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/ibss.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/ibss.c')
-rw-r--r--net/wireless/ibss.c61
1 files changed, 39 insertions, 22 deletions
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 4d7a084b35e2..42840a01be74 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -78,10 +78,15 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
78 struct cfg80211_cached_keys *connkeys) 78 struct cfg80211_cached_keys *connkeys)
79{ 79{
80 struct wireless_dev *wdev = dev->ieee80211_ptr; 80 struct wireless_dev *wdev = dev->ieee80211_ptr;
81 struct ieee80211_channel *chan;
81 int err; 82 int err;
82 83
83 ASSERT_WDEV_LOCK(wdev); 84 ASSERT_WDEV_LOCK(wdev);
84 85
86 chan = rdev_fixed_channel(rdev, wdev);
87 if (chan && chan != params->channel)
88 return -EBUSY;
89
85 if (wdev->ssid_len) 90 if (wdev->ssid_len)
86 return -EALREADY; 91 return -EALREADY;
87 92
@@ -112,9 +117,11 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
112 struct wireless_dev *wdev = dev->ieee80211_ptr; 117 struct wireless_dev *wdev = dev->ieee80211_ptr;
113 int err; 118 int err;
114 119
120 mutex_lock(&rdev->devlist_mtx);
115 wdev_lock(wdev); 121 wdev_lock(wdev);
116 err = __cfg80211_join_ibss(rdev, dev, params, connkeys); 122 err = __cfg80211_join_ibss(rdev, dev, params, connkeys);
117 wdev_unlock(wdev); 123 wdev_unlock(wdev);
124 mutex_unlock(&rdev->devlist_mtx);
118 125
119 return err; 126 return err;
120} 127}
@@ -264,27 +271,32 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
264 271
265int cfg80211_ibss_wext_siwfreq(struct net_device *dev, 272int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
266 struct iw_request_info *info, 273 struct iw_request_info *info,
267 struct iw_freq *freq, char *extra) 274 struct iw_freq *wextfreq, char *extra)
268{ 275{
269 struct wireless_dev *wdev = dev->ieee80211_ptr; 276 struct wireless_dev *wdev = dev->ieee80211_ptr;
270 struct ieee80211_channel *chan; 277 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
271 int err; 278 struct ieee80211_channel *chan = NULL;
279 int err, freq;
272 280
273 /* call only for ibss! */ 281 /* call only for ibss! */
274 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) 282 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
275 return -EINVAL; 283 return -EINVAL;
276 284
277 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) 285 if (!rdev->ops->join_ibss)
278 return -EOPNOTSUPP; 286 return -EOPNOTSUPP;
279 287
280 chan = cfg80211_wext_freq(wdev->wiphy, freq); 288 freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
281 if (chan && IS_ERR(chan)) 289 if (freq < 0)
282 return PTR_ERR(chan); 290 return freq;
283 291
284 if (chan && 292 if (freq) {
285 (chan->flags & IEEE80211_CHAN_NO_IBSS || 293 chan = ieee80211_get_channel(wdev->wiphy, freq);
286 chan->flags & IEEE80211_CHAN_DISABLED)) 294 if (!chan)
287 return -EINVAL; 295 return -EINVAL;
296 if (chan->flags & IEEE80211_CHAN_NO_IBSS ||
297 chan->flags & IEEE80211_CHAN_DISABLED)
298 return -EINVAL;
299 }
288 300
289 if (wdev->wext.ibss.channel == chan) 301 if (wdev->wext.ibss.channel == chan)
290 return 0; 302 return 0;
@@ -292,8 +304,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
292 wdev_lock(wdev); 304 wdev_lock(wdev);
293 err = 0; 305 err = 0;
294 if (wdev->ssid_len) 306 if (wdev->ssid_len)
295 err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), 307 err = __cfg80211_leave_ibss(rdev, dev, true);
296 dev, true);
297 wdev_unlock(wdev); 308 wdev_unlock(wdev);
298 309
299 if (err) 310 if (err)
@@ -307,9 +318,11 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
307 wdev->wext.ibss.channel_fixed = false; 318 wdev->wext.ibss.channel_fixed = false;
308 } 319 }
309 320
321 mutex_lock(&rdev->devlist_mtx);
310 wdev_lock(wdev); 322 wdev_lock(wdev);
311 err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); 323 err = cfg80211_ibss_wext_join(rdev, wdev);
312 wdev_unlock(wdev); 324 wdev_unlock(wdev);
325 mutex_unlock(&rdev->devlist_mtx);
313 326
314 return err; 327 return err;
315} 328}
@@ -347,6 +360,7 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
347 struct iw_point *data, char *ssid) 360 struct iw_point *data, char *ssid)
348{ 361{
349 struct wireless_dev *wdev = dev->ieee80211_ptr; 362 struct wireless_dev *wdev = dev->ieee80211_ptr;
363 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
350 size_t len = data->length; 364 size_t len = data->length;
351 int err; 365 int err;
352 366
@@ -354,14 +368,13 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
354 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) 368 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
355 return -EINVAL; 369 return -EINVAL;
356 370
357 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) 371 if (!rdev->ops->join_ibss)
358 return -EOPNOTSUPP; 372 return -EOPNOTSUPP;
359 373
360 wdev_lock(wdev); 374 wdev_lock(wdev);
361 err = 0; 375 err = 0;
362 if (wdev->ssid_len) 376 if (wdev->ssid_len)
363 err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), 377 err = __cfg80211_leave_ibss(rdev, dev, true);
364 dev, true);
365 wdev_unlock(wdev); 378 wdev_unlock(wdev);
366 379
367 if (err) 380 if (err)
@@ -375,9 +388,11 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
375 memcpy(wdev->wext.ibss.ssid, ssid, len); 388 memcpy(wdev->wext.ibss.ssid, ssid, len);
376 wdev->wext.ibss.ssid_len = len; 389 wdev->wext.ibss.ssid_len = len;
377 390
391 mutex_lock(&rdev->devlist_mtx);
378 wdev_lock(wdev); 392 wdev_lock(wdev);
379 err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); 393 err = cfg80211_ibss_wext_join(rdev, wdev);
380 wdev_unlock(wdev); 394 wdev_unlock(wdev);
395 mutex_unlock(&rdev->devlist_mtx);
381 396
382 return err; 397 return err;
383} 398}
@@ -414,6 +429,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
414 struct sockaddr *ap_addr, char *extra) 429 struct sockaddr *ap_addr, char *extra)
415{ 430{
416 struct wireless_dev *wdev = dev->ieee80211_ptr; 431 struct wireless_dev *wdev = dev->ieee80211_ptr;
432 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
417 u8 *bssid = ap_addr->sa_data; 433 u8 *bssid = ap_addr->sa_data;
418 int err; 434 int err;
419 435
@@ -421,7 +437,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
421 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) 437 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
422 return -EINVAL; 438 return -EINVAL;
423 439
424 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) 440 if (!rdev->ops->join_ibss)
425 return -EOPNOTSUPP; 441 return -EOPNOTSUPP;
426 442
427 if (ap_addr->sa_family != ARPHRD_ETHER) 443 if (ap_addr->sa_family != ARPHRD_ETHER)
@@ -443,8 +459,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
443 wdev_lock(wdev); 459 wdev_lock(wdev);
444 err = 0; 460 err = 0;
445 if (wdev->ssid_len) 461 if (wdev->ssid_len)
446 err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), 462 err = __cfg80211_leave_ibss(rdev, dev, true);
447 dev, true);
448 wdev_unlock(wdev); 463 wdev_unlock(wdev);
449 464
450 if (err) 465 if (err)
@@ -456,9 +471,11 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
456 } else 471 } else
457 wdev->wext.ibss.bssid = NULL; 472 wdev->wext.ibss.bssid = NULL;
458 473
474 mutex_lock(&rdev->devlist_mtx);
459 wdev_lock(wdev); 475 wdev_lock(wdev);
460 err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); 476 err = cfg80211_ibss_wext_join(rdev, wdev);
461 wdev_unlock(wdev); 477 wdev_unlock(wdev);
478 mutex_unlock(&rdev->devlist_mtx);
462 479
463 return err; 480 return err;
464} 481}