summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c5
-rw-r--r--net/mac80211/ibss.c13
-rw-r--r--net/wireless/chan.c249
-rw-r--r--net/wireless/core.h6
-rw-r--r--net/wireless/ibss.c4
-rw-r--r--net/wireless/mesh.c4
-rw-r--r--net/wireless/nl80211.c160
-rw-r--r--net/wireless/trace.h28
-rw-r--r--net/wireless/wext-compat.c4
-rw-r--r--net/wireless/wext-sme.c3
10 files changed, 382 insertions, 94 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index fbb2d072cb9e..7136b945798e 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3125,8 +3125,9 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (chanctx_conf) {
- chandef->chan = chanctx_conf->channel;
- chandef->_type = chanctx_conf->channel_type;
+ cfg80211_chandef_create(chandef,
+ chanctx_conf->channel,
+ chanctx_conf->channel_type);
ret = 0;
}
rcu_read_unlock();
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index bed616fd97e9..5648bbed240b 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -52,6 +52,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
u32 bss_change;
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
struct cfg80211_chan_def chandef;
+ enum nl80211_channel_type chan_type;
lockdep_assert_held(&ifibss->mtx);
@@ -79,13 +80,13 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
- chandef.chan = chan;
- chandef._type = ifibss->channel_type;
+ chan_type = ifibss->channel_type;
+ cfg80211_chandef_create(&chandef, chan, chan_type);
if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef))
- chandef._type = NL80211_CHAN_HT20;
+ chan_type = NL80211_CHAN_HT20;
ieee80211_vif_release_channel(sdata);
- if (ieee80211_vif_use_channel(sdata, chan, chandef._type,
+ if (ieee80211_vif_use_channel(sdata, chan, chan_type,
ifibss->fixed_channel ?
IEEE80211_CHANCTX_SHARED :
IEEE80211_CHANCTX_EXCLUSIVE)) {
@@ -159,7 +160,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
ifibss->ie, ifibss->ie_len);
/* add HT capability and information IEs */
- if (chandef._type != NL80211_CHAN_NO_HT &&
+ if (chan_type != NL80211_CHAN_NO_HT &&
sband->ht_cap.ht_supported) {
pos = skb_put(skb, 4 +
sizeof(struct ieee80211_ht_cap) +
@@ -172,7 +173,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
* keep them at 0
*/
pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
- chan, chandef._type, 0);
+ chan, chan_type, 0);
}
if (local->hw.queues >= IEEE80211_NUM_ACS) {
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index e834422de40a..bf2dfd54ff3b 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -11,43 +11,252 @@
#include "core.h"
#include "rdev-ops.h"
-bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
- struct cfg80211_chan_def *chandef)
+void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type chan_type)
{
- struct ieee80211_channel *sec_chan;
- int diff;
+ if (WARN_ON(!chan))
+ return;
- trace_cfg80211_reg_can_beacon(wiphy, chandef);
+ chandef->chan = chan;
+ chandef->center_freq2 = 0;
- switch (chandef->_type) {
+ switch (chan_type) {
+ case NL80211_CHAN_NO_HT:
+ chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
+ chandef->center_freq1 = chan->center_freq;
+ break;
+ case NL80211_CHAN_HT20:
+ chandef->width = NL80211_CHAN_WIDTH_20;
+ chandef->center_freq1 = chan->center_freq;
+ break;
case NL80211_CHAN_HT40PLUS:
- diff = 20;
+ chandef->width = NL80211_CHAN_WIDTH_40;
+ chandef->center_freq1 = chan->center_freq + 10;
break;
case NL80211_CHAN_HT40MINUS:
- diff = -20;
+ chandef->width = NL80211_CHAN_WIDTH_40;
+ chandef->center_freq1 = chan->center_freq - 10;
+ break;
+ default:
+ WARN_ON(1);
+ }
+}
+EXPORT_SYMBOL(cfg80211_chandef_create);
+
+bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef)
+{
+ u32 control_freq;
+
+ if (!chandef->chan)
+ return false;
+
+ control_freq = chandef->chan->center_freq;
+
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20:
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ if (chandef->center_freq1 != control_freq)
+ return false;
+ if (chandef->center_freq2)
+ return false;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ if (chandef->center_freq1 != control_freq + 10 &&
+ chandef->center_freq1 != control_freq - 10)
+ return false;
+ if (chandef->center_freq2)
+ return false;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ if (chandef->center_freq1 != control_freq + 30 &&
+ chandef->center_freq1 != control_freq + 10 &&
+ chandef->center_freq1 != control_freq - 10 &&
+ chandef->center_freq1 != control_freq - 30)
+ return false;
+ if (!chandef->center_freq2)
+ return false;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ if (chandef->center_freq1 != control_freq + 30 &&
+ chandef->center_freq1 != control_freq + 10 &&
+ chandef->center_freq1 != control_freq - 10 &&
+ chandef->center_freq1 != control_freq - 30)
+ return false;
+ if (chandef->center_freq2)
+ return false;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ if (chandef->center_freq1 != control_freq + 70 &&
+ chandef->center_freq1 != control_freq + 50 &&
+ chandef->center_freq1 != control_freq + 30 &&
+ chandef->center_freq1 != control_freq + 10 &&
+ chandef->center_freq1 != control_freq - 10 &&
+ chandef->center_freq1 != control_freq - 30 &&
+ chandef->center_freq1 != control_freq - 50 &&
+ chandef->center_freq1 != control_freq - 70)
+ return false;
+ if (chandef->center_freq2)
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
+ int *pri40, int *pri80)
+{
+ int tmp;
+
+ switch (c->width) {
+ case NL80211_CHAN_WIDTH_40:
+ *pri40 = c->center_freq1;
+ *pri80 = 0;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ case NL80211_CHAN_WIDTH_80P80:
+ *pri80 = c->center_freq1;
+ /* n_P20 */
+ tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
+ /* n_P40 */
+ tmp /= 2;
+ /* freq_P40 */
+ *pri40 = c->center_freq1 - 20 + 40 * tmp;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ /* n_P20 */
+ tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
+ /* n_P40 */
+ tmp /= 2;
+ /* freq_P40 */
+ *pri40 = c->center_freq1 - 60 + 40 * tmp;
+ /* n_P80 */
+ tmp /= 2;
+ *pri80 = c->center_freq1 - 40 + 80 * tmp;
break;
default:
- trace_cfg80211_return_bool(true);
- return true;
+ WARN_ON_ONCE(1);
}
+}
+
+const struct cfg80211_chan_def *
+cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
+ const struct cfg80211_chan_def *c2)
+{
+ u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80;
- sec_chan = ieee80211_get_channel(wiphy,
- chandef->chan->center_freq + diff);
- if (!sec_chan) {
+ /* If they are identical, return */
+ if (cfg80211_chandef_identical(c1, c2))
+ return c1;
+
+ /* otherwise, must have same control channel */
+ if (c1->chan != c2->chan)
+ return NULL;
+
+ /*
+ * If they have the same width, but aren't identical,
+ * then they can't be compatible.
+ */
+ if (c1->width == c2->width)
+ return NULL;
+
+ if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
+ c1->width == NL80211_CHAN_WIDTH_20)
+ return c2;
+
+ if (c2->width == NL80211_CHAN_WIDTH_20_NOHT ||
+ c2->width == NL80211_CHAN_WIDTH_20)
+ return c1;
+
+ chandef_primary_freqs(c1, &c1_pri40, &c1_pri80);
+ chandef_primary_freqs(c2, &c2_pri40, &c2_pri80);
+
+ if (c1_pri40 != c2_pri40)
+ return NULL;
+
+ WARN_ON(!c1_pri80 && !c2_pri80);
+ if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80)
+ return NULL;
+
+ if (c1->width > c2->width)
+ return c1;
+ return c2;
+}
+EXPORT_SYMBOL(cfg80211_chandef_compatible);
+
+bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
+ u32 center_freq, u32 bandwidth,
+ u32 prohibited_flags)
+{
+ struct ieee80211_channel *c;
+ u32 freq;
+
+ for (freq = center_freq - bandwidth/2 + 10;
+ freq <= center_freq + bandwidth/2 - 10;
+ freq += 20) {
+ c = ieee80211_get_channel(wiphy, freq);
+ if (!c || c->flags & prohibited_flags)
+ return false;
+ }
+
+ return true;
+}
+
+static bool cfg80211_check_beacon_chans(struct wiphy *wiphy,
+ u32 center_freq, u32 bw)
+{
+ return cfg80211_secondary_chans_ok(wiphy, center_freq, bw,
+ IEEE80211_CHAN_DISABLED |
+ IEEE80211_CHAN_PASSIVE_SCAN |
+ IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_RADAR);
+}
+
+bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef)
+{
+ u32 width;
+ bool res;
+
+ trace_cfg80211_reg_can_beacon(wiphy, chandef);
+
+ if (WARN_ON(!cfg80211_chan_def_valid(chandef))) {
trace_cfg80211_return_bool(false);
return false;
}
- /* we'll need a DFS capability later */
- if (sec_chan->flags & (IEEE80211_CHAN_DISABLED |
- IEEE80211_CHAN_PASSIVE_SCAN |
- IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_RADAR)) {
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ width = 20;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ width = 40;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ case NL80211_CHAN_WIDTH_80P80:
+ width = 80;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ width = 160;
+ break;
+ default:
+ WARN_ON_ONCE(1);
trace_cfg80211_return_bool(false);
return false;
}
- trace_cfg80211_return_bool(true);
- return true;
+
+ res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq1, width);
+
+ if (res && chandef->center_freq2)
+ res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq2,
+ width);
+
+ trace_cfg80211_return_bool(res);
+ return res;
}
EXPORT_SYMBOL(cfg80211_reg_can_beacon);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 6183a0d25b8b..a0c8decf6a47 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -483,6 +483,12 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, int num);
+bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef);
+
+bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
+ u32 center_freq, u32 bandwidth,
+ u32 prohibited_flags);
+
#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index ccc8865dfadb..9b9551e4a6f9 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -252,7 +252,7 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
/* try to find an IBSS channel if none requested ... */
if (!wdev->wext.ibss.chandef.chan) {
- wdev->wext.ibss.chandef._type = NL80211_CHAN_NO_HT;
+ wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
struct ieee80211_supported_band *sband;
@@ -352,7 +352,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
if (chan) {
wdev->wext.ibss.chandef.chan = chan;
- wdev->wext.ibss.chandef._type = NL80211_CHAN_NO_HT;
+ wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
wdev->wext.ibss.channel_fixed = true;
} else {
/* cfg80211_ibss_wext_join will pick one if needed */
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 12b5a570a306..3ee5a7282283 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -146,7 +146,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
if (!setup->chandef.chan)
return -EINVAL;
- setup->chandef._type = NL80211_CHAN_NO_HT;
+ setup->chandef.width = NL80211_CHAN_WIDTH_20_NOHT;;
}
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
@@ -198,7 +198,7 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
* compatible with 802.11 mesh.
*/
if (rdev->ops->libertas_set_mesh_channel) {
- if (chandef->_type != NL80211_CHAN_NO_HT)
+ if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT)
return -EINVAL;
if (!netif_running(wdev->netdev))
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 999108cd947c..15158a3d64a3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -223,8 +223,13 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
.len = 20-1 },
[NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
+
[NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
[NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
+ [NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
+ [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
+ [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },
+
[NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 },
[NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 },
[NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
@@ -1360,35 +1365,13 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
wdev->iftype == NL80211_IFTYPE_P2P_GO;
}
-static bool nl80211_valid_channel_type(struct genl_info *info,
- enum nl80211_channel_type *channel_type)
-{
- enum nl80211_channel_type tmp;
-
- if (!info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
- return false;
-
- tmp = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
- if (tmp != NL80211_CHAN_NO_HT &&
- tmp != NL80211_CHAN_HT20 &&
- tmp != NL80211_CHAN_HT40PLUS &&
- tmp != NL80211_CHAN_HT40MINUS)
- return false;
-
- if (channel_type)
- *channel_type = tmp;
-
- return true;
-}
-
static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
struct genl_info *info,
struct cfg80211_chan_def *chandef)
{
struct ieee80211_sta_ht_cap *ht_cap;
- struct ieee80211_channel *sc;
- u32 control_freq;
- int offs;
+ struct ieee80211_sta_vht_cap *vht_cap;
+ u32 control_freq, width;
if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
return -EINVAL;
@@ -1396,47 +1379,105 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq);
- chandef->_type = NL80211_CHAN_NO_HT;
-
- if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
- !nl80211_valid_channel_type(info, &chandef->_type))
- return -EINVAL;
+ chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
+ chandef->center_freq1 = control_freq;
+ chandef->center_freq2 = 0;
/* Primary channel not allowed */
if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED)
return -EINVAL;
+ if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+ enum nl80211_channel_type chantype;
+
+ chantype = nla_get_u32(
+ info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+
+ switch (chantype) {
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
+ case NL80211_CHAN_HT40PLUS:
+ case NL80211_CHAN_HT40MINUS:
+ cfg80211_chandef_create(chandef, chandef->chan,
+ chantype);
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else if (info->attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
+ chandef->width =
+ nla_get_u32(info->attrs[NL80211_ATTR_CHANNEL_WIDTH]);
+ if (info->attrs[NL80211_ATTR_CENTER_FREQ1])
+ chandef->center_freq1 =
+ nla_get_u32(
+ info->attrs[NL80211_ATTR_CENTER_FREQ1]);
+ if (info->attrs[NL80211_ATTR_CENTER_FREQ2])
+ chandef->center_freq2 =
+ nla_get_u32(
+ info->attrs[NL80211_ATTR_CENTER_FREQ2]);
+ }
+
ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap;
+ vht_cap = &rdev->wiphy.bands[chandef->chan->band]->vht_cap;
- switch (chandef->_type) {
- case NL80211_CHAN_NO_HT:
+ if (!cfg80211_chan_def_valid(chandef))
+ return -EINVAL;
+
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20:
+ if (!ht_cap->ht_supported)
+ return -EINVAL;
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ width = 20;
break;
- case NL80211_CHAN_HT40MINUS:
- if (chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
+ case NL80211_CHAN_WIDTH_40:
+ width = 40;
+ /* quick early regulatory check */
+ if (chandef->center_freq1 < control_freq &&
+ chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
+ return -EINVAL;
+ if (chandef->center_freq1 > control_freq &&
+ chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
+ return -EINVAL;
+ if (!ht_cap->ht_supported)
return -EINVAL;
- offs = -20;
- /* fall through */
- case NL80211_CHAN_HT40PLUS:
- if (chandef->_type == NL80211_CHAN_HT40PLUS) {
- if (chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
- return -EINVAL;
- offs = 20;
- }
if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
return -EINVAL;
-
- sc = ieee80211_get_channel(&rdev->wiphy,
- chandef->chan->center_freq + offs);
- if (!sc || sc->flags & IEEE80211_CHAN_DISABLED)
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ width = 80;
+ if (!vht_cap->vht_supported)
return -EINVAL;
- /* fall through */
- case NL80211_CHAN_HT20:
- if (!ht_cap->ht_supported)
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ width = 80;
+ if (!vht_cap->vht_supported)
+ return -EINVAL;
+ if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))
+ return -EINVAL;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ width = 160;
+ if (!vht_cap->vht_supported)
+ return -EINVAL;
+ if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ))
return -EINVAL;
break;
+ default:
+ return -EINVAL;
}
+ if (!cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq1,
+ width, IEEE80211_CHAN_DISABLED))
+ return -EINVAL;
+ if (chandef->center_freq2 &&
+ !cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq2,
+ width, IEEE80211_CHAN_DISABLED))
+ return -EINVAL;
+
+ /* TODO: missing regulatory check on bandwidth */
+
return 0;
}
@@ -1800,10 +1841,28 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
static int nl80211_send_chandef(struct sk_buff *msg,
struct cfg80211_chan_def *chandef)
{
+ WARN_ON(!cfg80211_chan_def_valid(chandef));
+
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
chandef->chan->center_freq))
return -ENOBUFS;
- if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, chandef->_type))
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ case NL80211_CHAN_WIDTH_40:
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ cfg80211_get_chandef_type(chandef)))
+ return -ENOBUFS;
+ break;
+ default:
+ break;
+ }
+ if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width))
+ return -ENOBUFS;
+ if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1))
+ return -ENOBUFS;
+ if (chandef->center_freq2 &&
+ nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2))
return -ENOBUFS;
return 0;
}
@@ -5447,7 +5506,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
if (IS_ERR(connkeys))
return PTR_ERR(connkeys);
- if ((ibss.chandef._type != NL80211_CHAN_NO_HT) && no_ht) {
+ if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
+ no_ht) {
kfree(connkeys);
return -EINVAL;
}
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 1370d52b1393..3c7aa1221563 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -126,25 +126,33 @@
#define CHAN_PR_FMT ", band: %d, freq: %u"
#define CHAN_PR_ARG __entry->band, __entry->center_freq
-#define CHAN_DEF_ENTRY __field(enum ieee80211_band, band) \
- __field(u16, center_freq) \
- __field(u32, channel_type)
+#define CHAN_DEF_ENTRY __field(enum ieee80211_band, band) \
+ __field(u32, control_freq) \
+ __field(u32, width) \
+ __field(u32, center_freq1) \
+ __field(u32, center_freq2)
#define CHAN_DEF_ASSIGN(chandef) \
do { \
if ((chandef) && (chandef)->chan) { \
__entry->band = (chandef)->chan->band; \
- __entry->center_freq = \
+ __entry->control_freq = \
(chandef)->chan->center_freq; \
- __entry->channel_type = (chandef)->_type; \
+ __entry->width = (chandef)->width; \
+ __entry->center_freq1 = (chandef)->center_freq1;\
+ __entry->center_freq2 = (chandef)->center_freq2;\
} else { \
__entry->band = 0; \
- __entry->center_freq = 0; \
- __entry->channel_type = 0; \
+ __entry->control_freq = 0; \
+ __entry->width = 0; \
+ __entry->center_freq1 = 0; \
+ __entry->center_freq2 = 0; \
} \
} while (0)
-#define CHAN_DEF_PR_FMT ", band: %d, freq: %u, chantype: %d"
-#define CHAN_DEF_PR_ARG __entry->band, __entry->center_freq, \
- __entry->channel_type
+#define CHAN_DEF_PR_FMT \
+ ", band: %d, control freq: %u, width: %d, cf1: %u, cf2: %u"
+#define CHAN_DEF_PR_ARG __entry->band, __entry->control_freq, \
+ __entry->width, __entry->center_freq1, \
+ __entry->center_freq2
#define SINFO_ENTRY __field(int, generation) \
__field(u32, connected_time) \
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index da3307f32362..f9680c9cf9b3 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -785,7 +785,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_chan_def chandef = {
- ._type = NL80211_CHAN_NO_HT,
+ .width = NL80211_CHAN_WIDTH_20_NOHT,
};
int freq, err;
@@ -800,6 +800,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
return freq;
if (freq == 0)
return -EINVAL;
+ chandef.center_freq1 = freq;
chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
if (!chandef.chan)
return -EINVAL;
@@ -813,6 +814,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
return freq;
if (freq == 0)
return -EINVAL;
+ chandef.center_freq1 = freq;
chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
if (!chandef.chan)
return -EINVAL;
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index e6e5dbf2f616..873af63187c0 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -120,7 +120,8 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
*/
if (chan && !wdev->wext.connect.ssid_len) {
struct cfg80211_chan_def chandef = {
- ._type = NL80211_CHAN_NO_HT,
+ .width = NL80211_CHAN_WIDTH_20_NOHT,
+ .center_freq1 = freq,
};
chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);