aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorJouni Malinen <jouni@qca.qualcomm.com>2014-04-28 04:22:08 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-04-28 12:09:59 -0400
commite16821bcfb364b0c41142db275dc74b39fa42c30 (patch)
tree238b98e192130cd99cee979cf9e540b217f878c8 /net/wireless/nl80211.c
parentb205786e38b156d1ccaccd4f4ee780345a69cfeb (diff)
cfg80211: Dynamic channel bandwidth changes in AP mode
This extends NL80211_CMD_SET_CHANNEL to allow dynamic channel bandwidth changes in AP mode (including P2P GO) during a lifetime of the BSS. This can be used to implement, e.g., HT 20/40 MHz co-existence rules on the 2.4 GHz band. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c40
1 files changed, 28 insertions, 12 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ca75f60041d2..0f1b18f209d6 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1928,18 +1928,20 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
1928} 1928}
1929 1929
1930static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, 1930static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
1931 struct wireless_dev *wdev, 1931 struct net_device *dev,
1932 struct genl_info *info) 1932 struct genl_info *info)
1933{ 1933{
1934 struct cfg80211_chan_def chandef; 1934 struct cfg80211_chan_def chandef;
1935 int result; 1935 int result;
1936 enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR; 1936 enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
1937 struct wireless_dev *wdev = NULL;
1937 1938
1938 if (wdev) 1939 if (dev)
1939 iftype = wdev->iftype; 1940 wdev = dev->ieee80211_ptr;
1940
1941 if (!nl80211_can_set_dev_channel(wdev)) 1941 if (!nl80211_can_set_dev_channel(wdev))
1942 return -EOPNOTSUPP; 1942 return -EOPNOTSUPP;
1943 if (wdev)
1944 iftype = wdev->iftype;
1943 1945
1944 result = nl80211_parse_chandef(rdev, info, &chandef); 1946 result = nl80211_parse_chandef(rdev, info, &chandef);
1945 if (result) 1947 if (result)
@@ -1948,14 +1950,27 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
1948 switch (iftype) { 1950 switch (iftype) {
1949 case NL80211_IFTYPE_AP: 1951 case NL80211_IFTYPE_AP:
1950 case NL80211_IFTYPE_P2P_GO: 1952 case NL80211_IFTYPE_P2P_GO:
1951 if (wdev->beacon_interval) {
1952 result = -EBUSY;
1953 break;
1954 }
1955 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) { 1953 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) {
1956 result = -EINVAL; 1954 result = -EINVAL;
1957 break; 1955 break;
1958 } 1956 }
1957 if (wdev->beacon_interval) {
1958 if (!dev || !rdev->ops->set_ap_chanwidth ||
1959 !(rdev->wiphy.features &
1960 NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)) {
1961 result = -EBUSY;
1962 break;
1963 }
1964
1965 /* Only allow dynamic channel width changes */
1966 if (chandef.chan != wdev->preset_chandef.chan) {
1967 result = -EBUSY;
1968 break;
1969 }
1970 result = rdev_set_ap_chanwidth(rdev, dev, &chandef);
1971 if (result)
1972 break;
1973 }
1959 wdev->preset_chandef = chandef; 1974 wdev->preset_chandef = chandef;
1960 result = 0; 1975 result = 0;
1961 break; 1976 break;
@@ -1977,7 +1992,7 @@ static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
1977 struct cfg80211_registered_device *rdev = info->user_ptr[0]; 1992 struct cfg80211_registered_device *rdev = info->user_ptr[0];
1978 struct net_device *netdev = info->user_ptr[1]; 1993 struct net_device *netdev = info->user_ptr[1];
1979 1994
1980 return __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); 1995 return __nl80211_set_channel(rdev, netdev, info);
1981} 1996}
1982 1997
1983static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info) 1998static int nl80211_set_wds_peer(struct sk_buff *skb, struct genl_info *info)
@@ -2099,9 +2114,10 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
2099 } 2114 }
2100 2115
2101 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { 2116 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
2102 result = __nl80211_set_channel(rdev, 2117 result = __nl80211_set_channel(
2103 nl80211_can_set_dev_channel(wdev) ? wdev : NULL, 2118 rdev,
2104 info); 2119 nl80211_can_set_dev_channel(wdev) ? netdev : NULL,
2120 info);
2105 if (result) 2121 if (result)
2106 return result; 2122 return result;
2107 } 2123 }