aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.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/nl80211.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/nl80211.c')
-rw-r--r--net/wireless/nl80211.c54
1 files changed, 13 insertions, 41 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0cd548267d4a..2ff7376f35a3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -701,15 +701,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
701 701
702 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { 702 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
703 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; 703 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
704 struct ieee80211_channel *chan;
705 struct ieee80211_sta_ht_cap *ht_cap;
706 u32 freq; 704 u32 freq;
707 705
708 if (!rdev->ops->set_channel) {
709 result = -EOPNOTSUPP;
710 goto bad_res;
711 }
712
713 result = -EINVAL; 706 result = -EINVAL;
714 707
715 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { 708 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
@@ -723,42 +716,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
723 } 716 }
724 717
725 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); 718 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
726 chan = ieee80211_get_channel(&rdev->wiphy, freq);
727
728 /* Primary channel not allowed */
729 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
730 goto bad_res;
731
732 if (channel_type == NL80211_CHAN_HT40MINUS &&
733 (chan->flags & IEEE80211_CHAN_NO_HT40MINUS))
734 goto bad_res;
735 else if (channel_type == NL80211_CHAN_HT40PLUS &&
736 (chan->flags & IEEE80211_CHAN_NO_HT40PLUS))
737 goto bad_res;
738
739 /*
740 * At this point we know if that if HT40 was requested
741 * we are allowed to use it and the extension channel
742 * exists.
743 */
744 719
745 ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; 720 mutex_lock(&rdev->devlist_mtx);
746 721 result = rdev_set_freq(rdev, freq, channel_type);
747 /* no HT capabilities or intolerant */ 722 mutex_unlock(&rdev->devlist_mtx);
748 if (channel_type != NL80211_CHAN_NO_HT) {
749 if (!ht_cap->ht_supported)
750 goto bad_res;
751 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
752 (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT))
753 goto bad_res;
754 }
755
756 result = rdev->ops->set_channel(&rdev->wiphy, chan,
757 channel_type);
758 if (result) 723 if (result)
759 goto bad_res; 724 goto bad_res;
760
761 rdev->channel = chan;
762 } 725 }
763 726
764 changed = 0; 727 changed = 0;
@@ -3453,7 +3416,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3453 struct cfg80211_registered_device *rdev; 3416 struct cfg80211_registered_device *rdev;
3454 struct net_device *dev; 3417 struct net_device *dev;
3455 struct cfg80211_crypto_settings crypto; 3418 struct cfg80211_crypto_settings crypto;
3456 struct ieee80211_channel *chan; 3419 struct ieee80211_channel *chan, *fixedchan;
3457 const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; 3420 const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
3458 int err, ssid_len, ie_len = 0; 3421 int err, ssid_len, ie_len = 0;
3459 bool use_mfp = false; 3422 bool use_mfp = false;
@@ -3496,6 +3459,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3496 goto out; 3459 goto out;
3497 } 3460 }
3498 3461
3462 mutex_lock(&rdev->devlist_mtx);
3463 fixedchan = rdev_fixed_channel(rdev, NULL);
3464 if (fixedchan && chan != fixedchan) {
3465 err = -EBUSY;
3466 mutex_unlock(&rdev->devlist_mtx);
3467 goto out;
3468 }
3469 mutex_unlock(&rdev->devlist_mtx);
3470
3499 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); 3471 ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
3500 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); 3472 ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
3501 3473