aboutsummaryrefslogtreecommitdiff
path: root/net/wireless/wext-sme.c
diff options
context:
space:
mode:
authorJohannes Berg2009-08-07 17:22:35 +0200
committerJohn W. Linville2009-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,
int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
struct iw_request_info *info,
- struct iw_freq *freq, char *extra)
+ struct iw_freq *wextfreq, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
- struct ieee80211_channel *chan;
- int err;
+ struct ieee80211_channel *chan = NULL;
+ int err, freq;
/* call only for station! */
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
return -EINVAL;
- chan = cfg80211_wext_freq(wdev->wiphy, freq);
- if (chan && IS_ERR(chan))
- return PTR_ERR(chan);
+ freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
+ if (freq < 0)
+ return freq;
- if (chan && (chan->flags & IEEE80211_CHAN_DISABLED))
- return -EINVAL;
+ if (freq) {
+ chan = ieee80211_get_channel(wdev->wiphy, freq);
+ if (!chan)
+ return -EINVAL;
+ if (chan->flags & IEEE80211_CHAN_DISABLED)
+ return -EINVAL;
+ }
cfg80211_lock_rdev(rdev);
+ mutex_lock(&rdev->devlist_mtx);
wdev_lock(wdev);
if (wdev->sme_state != CFG80211_SME_IDLE) {
@@ -84,9 +90,8 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
/* if SSID set, we'll try right again, avoid event */
if (wdev->wext.connect.ssid_len)
event = false;
- err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
- dev, WLAN_REASON_DEAUTH_LEAVING,
- event);
+ err = __cfg80211_disconnect(rdev, dev,
+ WLAN_REASON_DEAUTH_LEAVING, event);
if (err)
goto out;
}
@@ -95,17 +100,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
wdev->wext.connect.channel = chan;
/* SSID is not set, we just want to switch channel */
- if (wdev->wext.connect.ssid_len && chan) {
- err = -EOPNOTSUPP;
- if (rdev->ops->set_channel)
- err = rdev->ops->set_channel(wdev->wiphy, chan,
- NL80211_CHAN_NO_HT);
+ if (chan && !wdev->wext.connect.ssid_len) {
+ err = rdev_set_freq(rdev, freq, NL80211_CHAN_NO_HT);
goto out;
}
- err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
+ err = cfg80211_mgd_wext_connect(rdev, wdev);
out:
wdev_unlock(wdev);
+ mutex_unlock(&rdev->devlist_mtx);
cfg80211_unlock_rdev(rdev);
return err;
}
@@ -143,6 +146,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
struct iw_point *data, char *ssid)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
size_t len = data->length;
int err;
@@ -157,7 +161,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
if (len > 0 && ssid[len - 1] == '\0')
len--;
- cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy));
+ cfg80211_lock_rdev(rdev);
+ mutex_lock(&rdev->devlist_mtx);
wdev_lock(wdev);
err = 0;
@@ -173,9 +178,8 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
/* if SSID set now, we'll try to connect, avoid event */
if (len)
event = false;
- err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
- dev, WLAN_REASON_DEAUTH_LEAVING,
- event);
+ err = __cfg80211_disconnect(rdev, dev,
+ WLAN_REASON_DEAUTH_LEAVING, event);
if (err)
goto out;
}
@@ -186,10 +190,11 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
wdev->wext.connect.crypto.control_port = false;
- err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
+ err = cfg80211_mgd_wext_connect(rdev, wdev);
out:
wdev_unlock(wdev);
- cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy));
+ mutex_unlock(&rdev->devlist_mtx);
+ cfg80211_unlock_rdev(rdev);
return err;
}
@@ -230,6 +235,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
struct sockaddr *ap_addr, char *extra)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
u8 *bssid = ap_addr->sa_data;
int err;
@@ -244,7 +250,8 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
bssid = NULL;
- cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy));
+ cfg80211_lock_rdev(rdev);
+ mutex_lock(&rdev->devlist_mtx);
wdev_lock(wdev);
if (wdev->sme_state != CFG80211_SME_IDLE) {
@@ -258,9 +265,8 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
goto out;
- err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
- dev, WLAN_REASON_DEAUTH_LEAVING,
- false);
+ err = __cfg80211_disconnect(rdev, dev,
+ WLAN_REASON_DEAUTH_LEAVING, false);
if (err)
goto out;
}
@@ -271,10 +277,11 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
} else
wdev->wext.connect.bssid = NULL;
- err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
+ err = cfg80211_mgd_wext_connect(rdev, wdev);
out:
wdev_unlock(wdev);
- cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy));
+ mutex_unlock(&rdev->devlist_mtx);
+ cfg80211_unlock_rdev(rdev);
return err;
}