From 683b6d3b31a51956ea540df00abb0b78894924c1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Nov 2012 21:25:48 +0100 Subject: cfg80211: pass a channel definition struct Instead of passing a channel pointer and channel type to all functions and driver methods, pass a new channel definition struct. Right now, this struct contains just the control channel and channel type, but for VHT this will change. Also, add a small inline cfg80211_get_chandef_type() so that drivers don't need to use the _type field of the new structure all the time, which will change. Signed-off-by: Johannes Berg --- net/wireless/chan.c | 59 ++--------- net/wireless/core.h | 11 +- net/wireless/ibss.c | 27 ++--- net/wireless/mesh.c | 49 ++++----- net/wireless/mlme.c | 15 +-- net/wireless/nl80211.c | 253 +++++++++++++++++++++++---------------------- net/wireless/nl80211.h | 4 +- net/wireless/rdev-ops.h | 22 ++-- net/wireless/trace.h | 100 ++++++++++-------- net/wireless/wext-compat.c | 26 +++-- net/wireless/wext-sme.c | 10 +- 11 files changed, 276 insertions(+), 300 deletions(-) (limited to 'net/wireless') diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 48febd2160ba..e834422de40a 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -11,51 +11,15 @@ #include "core.h" #include "rdev-ops.h" -struct ieee80211_channel * -rdev_freq_to_chan(struct cfg80211_registered_device *rdev, - int freq, enum nl80211_channel_type channel_type) -{ - struct ieee80211_channel *chan; - struct ieee80211_sta_ht_cap *ht_cap; - - chan = ieee80211_get_channel(&rdev->wiphy, freq); - - /* Primary channel not allowed */ - if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) - return NULL; - - if (channel_type == NL80211_CHAN_HT40MINUS && - chan->flags & IEEE80211_CHAN_NO_HT40MINUS) - return NULL; - else if (channel_type == NL80211_CHAN_HT40PLUS && - chan->flags & IEEE80211_CHAN_NO_HT40PLUS) - return NULL; - - ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; - - if (channel_type != NL80211_CHAN_NO_HT) { - if (!ht_cap->ht_supported) - return NULL; - - if (channel_type != NL80211_CHAN_HT20 && - (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || - ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) - return NULL; - } - - return chan; -} - -bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) +bool cfg80211_reg_can_beacon(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) { struct ieee80211_channel *sec_chan; int diff; - trace_cfg80211_can_beacon_sec_chan(wiphy, chan, channel_type); + trace_cfg80211_reg_can_beacon(wiphy, chandef); - switch (channel_type) { + switch (chandef->_type) { case NL80211_CHAN_HT40PLUS: diff = 20; break; @@ -67,7 +31,8 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, return true; } - sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff); + sec_chan = ieee80211_get_channel(wiphy, + chandef->chan->center_freq + diff); if (!sec_chan) { trace_cfg80211_return_bool(false); return false; @@ -84,23 +49,17 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, trace_cfg80211_return_bool(true); return true; } -EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan); +EXPORT_SYMBOL(cfg80211_reg_can_beacon); int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, - int freq, enum nl80211_channel_type chantype) + struct cfg80211_chan_def *chandef) { - struct ieee80211_channel *chan; - if (!rdev->ops->set_monitor_channel) return -EOPNOTSUPP; if (!cfg80211_has_monitors_only(rdev)) return -EBUSY; - chan = rdev_freq_to_chan(rdev, freq, chantype); - if (!chan) - return -EINVAL; - - return rdev_set_monitor_channel(rdev, chan, chantype); + return rdev_set_monitor_channel(rdev, chandef); } void diff --git a/net/wireless/core.h b/net/wireless/core.h index b0a09cf56e06..6183a0d25b8b 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -309,9 +309,9 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, const struct mesh_config *conf); int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, struct net_device *dev); -int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, int freq, - enum nl80211_channel_type channel_type); +int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef); /* AP */ int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, @@ -470,11 +470,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, struct ieee80211_channel **chan, enum cfg80211_chan_mode *chanmode); -struct ieee80211_channel * -rdev_freq_to_chan(struct cfg80211_registered_device *rdev, - int freq, enum nl80211_channel_type channel_type); int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, - int freq, enum nl80211_channel_type chantype); + struct cfg80211_chan_def *chandef); int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, const u8 *rates, unsigned int n_rates, diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 27941d5db72b..ccc8865dfadb 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -100,9 +100,9 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, * 11a for maximum compatibility. */ struct ieee80211_supported_band *sband = - rdev->wiphy.bands[params->channel->band]; + rdev->wiphy.bands[params->chandef.chan->band]; int j; - u32 flag = params->channel->band == IEEE80211_BAND_5GHZ ? + u32 flag = params->chandef.chan->band == IEEE80211_BAND_5GHZ ? IEEE80211_RATE_MANDATORY_A : IEEE80211_RATE_MANDATORY_B; @@ -118,11 +118,11 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, wdev->ibss_fixed = params->channel_fixed; #ifdef CONFIG_CFG80211_WEXT - wdev->wext.ibss.channel = params->channel; + wdev->wext.ibss.chandef = params->chandef; #endif wdev->sme_state = CFG80211_SME_CONNECTING; - err = cfg80211_can_use_chan(rdev, wdev, params->channel, + err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan, params->channel_fixed ? CHAN_MODE_SHARED : CHAN_MODE_EXCLUSIVE); @@ -251,7 +251,9 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, wdev->wext.ibss.beacon_interval = 100; /* try to find an IBSS channel if none requested ... */ - if (!wdev->wext.ibss.channel) { + if (!wdev->wext.ibss.chandef.chan) { + wdev->wext.ibss.chandef._type = NL80211_CHAN_NO_HT; + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; @@ -266,15 +268,15 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, continue; if (chan->flags & IEEE80211_CHAN_DISABLED) continue; - wdev->wext.ibss.channel = chan; + wdev->wext.ibss.chandef.chan = chan; break; } - if (wdev->wext.ibss.channel) + if (wdev->wext.ibss.chandef.chan) break; } - if (!wdev->wext.ibss.channel) + if (!wdev->wext.ibss.chandef.chan) return -EINVAL; } @@ -336,7 +338,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, return -EINVAL; } - if (wdev->wext.ibss.channel == chan) + if (wdev->wext.ibss.chandef.chan == chan) return 0; wdev_lock(wdev); @@ -349,7 +351,8 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, return err; if (chan) { - wdev->wext.ibss.channel = chan; + wdev->wext.ibss.chandef.chan = chan; + wdev->wext.ibss.chandef._type = NL80211_CHAN_NO_HT; wdev->wext.ibss.channel_fixed = true; } else { /* cfg80211_ibss_wext_join will pick one if needed */ @@ -379,8 +382,8 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev, wdev_lock(wdev); if (wdev->current_bss) chan = wdev->current_bss->pub.channel; - else if (wdev->wext.ibss.channel) - chan = wdev->wext.ibss.channel; + else if (wdev->wext.ibss.chandef.chan) + chan = wdev->wext.ibss.chandef.chan; wdev_unlock(wdev); if (chan) { diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 966cfc4cd79d..12b5a570a306 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -73,8 +73,6 @@ const struct mesh_config default_mesh_config = { const struct mesh_setup default_mesh_setup = { /* cfg80211_join_mesh() will pick a channel if needed */ - .channel = NULL, - .channel_type = NL80211_CHAN_NO_HT, .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP, .path_metric = IEEE80211_PATH_METRIC_AIRTIME, @@ -111,13 +109,12 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, if (!rdev->ops->join_mesh) return -EOPNOTSUPP; - if (!setup->channel) { + if (!setup->chandef.chan) { /* if no channel explicitly given, use preset channel */ - setup->channel = wdev->preset_chan; - setup->channel_type = wdev->preset_chantype; + setup->chandef = wdev->preset_chandef; } - if (!setup->channel) { + if (!setup->chandef.chan) { /* if we don't have that either, use the first usable channel */ enum ieee80211_band band; @@ -137,26 +134,25 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_RADAR)) continue; - setup->channel = chan; + setup->chandef.chan = chan; break; } - if (setup->channel) + if (setup->chandef.chan) break; } /* no usable channel ... */ - if (!setup->channel) + if (!setup->chandef.chan) return -EINVAL; - setup->channel_type = NL80211_CHAN_NO_HT; + setup->chandef._type = NL80211_CHAN_NO_HT; } - if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, setup->channel, - setup->channel_type)) + if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) return -EINVAL; - err = cfg80211_can_use_chan(rdev, wdev, setup->channel, + err = cfg80211_can_use_chan(rdev, wdev, setup->chandef.chan, CHAN_MODE_SHARED); if (err) return err; @@ -165,7 +161,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, if (!err) { memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); wdev->mesh_id_len = setup->mesh_id_len; - wdev->channel = setup->channel; + wdev->channel = setup->chandef.chan; } return err; @@ -188,20 +184,12 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, return err; } -int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, int freq, - enum nl80211_channel_type channel_type) +int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef) { - struct ieee80211_channel *channel; int err; - channel = rdev_freq_to_chan(rdev, freq, channel_type); - if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, - channel, - channel_type)) { - return -EINVAL; - } - /* * Workaround for libertas (only!), it puts the interface * into mesh mode but doesn't implement join_mesh. Instead, @@ -210,21 +198,21 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, * compatible with 802.11 mesh. */ if (rdev->ops->libertas_set_mesh_channel) { - if (channel_type != NL80211_CHAN_NO_HT) + if (chandef->_type != NL80211_CHAN_NO_HT) return -EINVAL; if (!netif_running(wdev->netdev)) return -ENETDOWN; - err = cfg80211_can_use_chan(rdev, wdev, channel, + err = cfg80211_can_use_chan(rdev, wdev, chandef->chan, CHAN_MODE_SHARED); if (err) return err; err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, - channel); + chandef->chan); if (!err) - wdev->channel = channel; + wdev->channel = chandef->chan; return err; } @@ -232,8 +220,7 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, if (wdev->mesh_id_len) return -EBUSY; - wdev->preset_chan = channel; - wdev->preset_chantype = channel_type; + wdev->preset_chandef = *chandef; return 0; } diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index a9646b53a095..5e8123ee63fd 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -988,15 +988,14 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, } EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); -void cfg80211_ch_switch_notify(struct net_device *dev, int freq, - enum nl80211_channel_type type) +void cfg80211_ch_switch_notify(struct net_device *dev, + struct cfg80211_chan_def *chandef) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - struct ieee80211_channel *chan; - trace_cfg80211_ch_switch_notify(dev, freq, type); + trace_cfg80211_ch_switch_notify(dev, chandef); wdev_lock(wdev); @@ -1004,12 +1003,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq, wdev->iftype != NL80211_IFTYPE_P2P_GO)) goto out; - chan = rdev_freq_to_chan(rdev, freq, type); - if (WARN_ON(!chan)) - goto out; - - wdev->channel = chan; - nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL); + wdev->channel = chandef->chan; + nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL); out: wdev_unlock(wdev); return; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e880f4494950..999108cd947c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1381,30 +1381,82 @@ static bool nl80211_valid_channel_type(struct genl_info *info, 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; + + if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) + return -EINVAL; + + 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; + + /* Primary channel not allowed */ + if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED) + return -EINVAL; + + ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap; + + switch (chandef->_type) { + case NL80211_CHAN_NO_HT: + break; + case NL80211_CHAN_HT40MINUS: + if (chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS) + 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) + return -EINVAL; + /* fall through */ + case NL80211_CHAN_HT20: + if (!ht_cap->ht_supported) + return -EINVAL; + break; + } + + return 0; +} + static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, struct genl_info *info) { - struct ieee80211_channel *channel; - enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; - u32 freq; + struct cfg80211_chan_def chandef; int result; enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR; if (wdev) iftype = wdev->iftype; - if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) - return -EINVAL; - if (!nl80211_can_set_dev_channel(wdev)) return -EOPNOTSUPP; - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && - !nl80211_valid_channel_type(info, &channel_type)) - return -EINVAL; - - freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); + result = nl80211_parse_chandef(rdev, info, &chandef); + if (result) + return result; mutex_lock(&rdev->devlist_mtx); switch (iftype) { @@ -1414,22 +1466,18 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, result = -EBUSY; break; } - channel = rdev_freq_to_chan(rdev, freq, channel_type); - if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, - channel, - channel_type)) { + if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef)) { result = -EINVAL; break; } - wdev->preset_chan = channel; - wdev->preset_chantype = channel_type; + wdev->preset_chandef = chandef; result = 0; break; case NL80211_IFTYPE_MESH_POINT: - result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type); + result = cfg80211_set_mesh_channel(rdev, wdev, &chandef); break; case NL80211_IFTYPE_MONITOR: - result = cfg80211_set_monitor_channel(rdev, freq, channel_type); + result = cfg80211_set_monitor_channel(rdev, &chandef); break; default: result = -EINVAL; @@ -1749,6 +1797,17 @@ static inline u64 wdev_id(struct wireless_dev *wdev) ((u64)wiphy_to_dev(wdev->wiphy)->wiphy_idx << 32); } +static int nl80211_send_chandef(struct sk_buff *msg, + struct cfg80211_chan_def *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)) + return -ENOBUFS; + return 0; +} + static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags, struct cfg80211_registered_device *rdev, struct wireless_dev *wdev) @@ -1775,16 +1834,14 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag goto nla_put_failure; if (rdev->ops->get_channel) { - struct ieee80211_channel *chan; - enum nl80211_channel_type channel_type; - - chan = rdev_get_channel(rdev, wdev, &channel_type); - if (chan && - (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, - chan->center_freq) || - nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - channel_type))) - goto nla_put_failure; + int ret; + struct cfg80211_chan_def chandef; + + ret = rdev_get_channel(rdev, wdev, &chandef); + if (ret == 0) { + if (nl80211_send_chandef(msg, &chandef)) + goto nla_put_failure; + } } if (wdev->ssid_len) { @@ -2492,11 +2549,10 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, wdev->iftype != NL80211_IFTYPE_P2P_GO) continue; - if (!wdev->preset_chan) + if (!wdev->preset_chandef.chan) continue; - params->channel = wdev->preset_chan; - params->channel_type = wdev->preset_chantype; + params->chandef = wdev->preset_chandef; ret = true; break; } @@ -2618,30 +2674,19 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) } if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { - enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; - - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && - !nl80211_valid_channel_type(info, &channel_type)) - return -EINVAL; - - params.channel = rdev_freq_to_chan(rdev, - nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), - channel_type); - if (!params.channel) - return -EINVAL; - params.channel_type = channel_type; - } else if (wdev->preset_chan) { - params.channel = wdev->preset_chan; - params.channel_type = wdev->preset_chantype; + err = nl80211_parse_chandef(rdev, info, ¶ms.chandef); + if (err) + return err; + } else if (wdev->preset_chandef.chan) { + params.chandef = wdev->preset_chandef; } else if (!nl80211_get_ap_channel(rdev, ¶ms)) return -EINVAL; - if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel, - params.channel_type)) + if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) return -EINVAL; mutex_lock(&rdev->devlist_mtx); - err = cfg80211_can_use_chan(rdev, wdev, params.channel, + err = cfg80211_can_use_chan(rdev, wdev, params.chandef.chan, CHAN_MODE_SHARED); mutex_unlock(&rdev->devlist_mtx); @@ -2650,10 +2695,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) err = rdev_start_ap(rdev, dev, ¶ms); if (!err) { - wdev->preset_chan = params.channel; - wdev->preset_chantype = params.channel_type; + wdev->preset_chandef = params.chandef; wdev->beacon_interval = params.beacon_interval; - wdev->channel = params.channel; + wdev->channel = params.chandef.chan; wdev->ssid_len = params.ssid_len; memcpy(wdev->ssid, params.ssid, wdev->ssid_len); } @@ -5330,8 +5374,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) return -EINVAL; - if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || - !info->attrs[NL80211_ATTR_SSID] || + if (!info->attrs[NL80211_ATTR_SSID] || !nla_len(info->attrs[NL80211_ATTR_SSID])) return -EINVAL; @@ -5366,34 +5409,11 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); } - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { - enum nl80211_channel_type channel_type; - - if (!nl80211_valid_channel_type(info, &channel_type)) - return -EINVAL; - - if (channel_type != NL80211_CHAN_NO_HT && - !(wiphy->features & NL80211_FEATURE_HT_IBSS)) - return -EINVAL; - - ibss.channel_type = channel_type; - } else { - ibss.channel_type = NL80211_CHAN_NO_HT; - } - - ibss.channel = rdev_freq_to_chan(rdev, - nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), - ibss.channel_type); - if (!ibss.channel || - ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || - ibss.channel->flags & IEEE80211_CHAN_DISABLED) - return -EINVAL; + err = nl80211_parse_chandef(rdev, info, &ibss.chandef); + if (err) + return err; - /* Both channels should be able to initiate communication */ - if ((ibss.channel_type == NL80211_CHAN_HT40PLUS || - ibss.channel_type == NL80211_CHAN_HT40MINUS) && - !cfg80211_can_beacon_sec_chan(&rdev->wiphy, ibss.channel, - ibss.channel_type)) + if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef)) return -EINVAL; ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; @@ -5405,7 +5425,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) int n_rates = nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); struct ieee80211_supported_band *sband = - wiphy->bands[ibss.channel->band]; + wiphy->bands[ibss.chandef.chan->band]; err = ieee80211_get_ratemask(sband, rates, n_rates, &ibss.basic_rates); @@ -5427,7 +5447,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) if (IS_ERR(connkeys)) return PTR_ERR(connkeys); - if ((ibss.channel_type != NL80211_CHAN_NO_HT) && no_ht) { + if ((ibss.chandef._type != NL80211_CHAN_NO_HT) && no_ht) { kfree(connkeys); return -EINVAL; } @@ -5948,11 +5968,11 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct wireless_dev *wdev = info->user_ptr[1]; - struct ieee80211_channel *chan; + struct cfg80211_chan_def chandef; struct sk_buff *msg; void *hdr; u64 cookie; - u32 freq, duration; + u32 duration; int err; if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || @@ -5973,14 +5993,9 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, duration > rdev->wiphy.max_remain_on_channel_duration) return -EINVAL; - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && - !nl80211_valid_channel_type(info, NULL)) - return -EINVAL; - - freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); - chan = rdev_freq_to_chan(rdev, freq, NL80211_CHAN_NO_HT); - if (chan == NULL) - return -EINVAL; + err = nl80211_parse_chandef(rdev, info, &chandef); + if (err) + return err; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) @@ -5994,7 +6009,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, goto free_msg; } - err = rdev_remain_on_channel(rdev, wdev, chan, duration, &cookie); + err = rdev_remain_on_channel(rdev, wdev, chandef.chan, + duration, &cookie); if (err) goto free_msg; @@ -6213,8 +6229,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct wireless_dev *wdev = info->user_ptr[1]; - struct ieee80211_channel *chan; - u32 freq; + struct cfg80211_chan_def chandef; int err; void *hdr = NULL; u64 cookie; @@ -6224,8 +6239,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK]; - if (!info->attrs[NL80211_ATTR_FRAME] || - !info->attrs[NL80211_ATTR_WIPHY_FREQ]) + if (!info->attrs[NL80211_ATTR_FRAME]) return -EINVAL; if (!rdev->ops->mgmt_tx) @@ -6260,10 +6274,6 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) } - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && - !nl80211_valid_channel_type(info, NULL)) - return -EINVAL; - offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) @@ -6271,10 +6281,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); - freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); - chan = rdev_freq_to_chan(rdev, freq, NL80211_CHAN_NO_HT); - if (chan == NULL) - return -EINVAL; + err = nl80211_parse_chandef(rdev, info, &chandef); + if (err) + return err; if (!dont_wait_for_ack) { msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); @@ -6290,7 +6299,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) } } - err = cfg80211_mlme_mgmt_tx(rdev, wdev, chan, offchan, wait, + err = cfg80211_mlme_mgmt_tx(rdev, wdev, chandef.chan, offchan, wait, nla_data(info->attrs[NL80211_ATTR_FRAME]), nla_len(info->attrs[NL80211_ATTR_FRAME]), no_cck, dont_wait_for_ack, &cookie); @@ -6554,21 +6563,12 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) } if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { - enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; - - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && - !nl80211_valid_channel_type(info, &channel_type)) - return -EINVAL; - - setup.channel = rdev_freq_to_chan(rdev, - nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), - channel_type); - if (!setup.channel) - return -EINVAL; - setup.channel_type = channel_type; + err = nl80211_parse_chandef(rdev, info, &setup.chandef); + if (err) + return err; } else { /* cfg80211_join_mesh() will sort it out */ - setup.channel = NULL; + setup.chandef.chan = NULL; } return cfg80211_join_mesh(rdev, dev, &setup, &cfg); @@ -8800,8 +8800,8 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, } void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, - struct net_device *netdev, int freq, - enum nl80211_channel_type type, gfp_t gfp) + struct net_device *netdev, + struct cfg80211_chan_def *chandef, gfp_t gfp) { struct sk_buff *msg; void *hdr; @@ -8816,9 +8816,10 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, return; } - if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || - nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || - nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, type)) + if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex)) + goto nla_put_failure; + + if (nl80211_send_chandef(msg, chandef)) goto nla_put_failure; genlmsg_end(msg, hdr); diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 7adbd767dbfd..2acba8477e9d 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -127,8 +127,8 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, const u8 *bssid, bool preauth, gfp_t gfp); void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, - struct net_device *dev, int freq, - enum nl80211_channel_type type, gfp_t gfp); + struct net_device *dev, + struct cfg80211_chan_def *chandef, gfp_t gfp); bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp); diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index ee54a5aa4381..6c0c8191f837 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -359,12 +359,11 @@ rdev_libertas_set_mesh_channel(struct cfg80211_registered_device *rdev, static inline int rdev_set_monitor_channel(struct cfg80211_registered_device *rdev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) + struct cfg80211_chan_def *chandef) { int ret; - trace_rdev_set_monitor_channel(&rdev->wiphy, chan, channel_type); - ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, channel_type); + trace_rdev_set_monitor_channel(&rdev->wiphy, chandef); + ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chandef); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } @@ -844,14 +843,17 @@ static inline void rdev_get_et_strings(struct cfg80211_registered_device *rdev, trace_rdev_return_void(&rdev->wiphy); } -static inline struct ieee80211_channel -*rdev_get_channel(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, enum nl80211_channel_type *type) +static inline int +rdev_get_channel(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef) { - struct ieee80211_channel *ret; + int ret; + trace_rdev_get_channel(&rdev->wiphy, wdev); - ret = rdev->ops->get_channel(&rdev->wiphy, wdev, type); - trace_rdev_return_channel(&rdev->wiphy, ret, *type); + ret = rdev->ops->get_channel(&rdev->wiphy, wdev, chandef); + trace_rdev_return_chandef(&rdev->wiphy, ret, chandef); + return ret; } diff --git a/net/wireless/trace.h b/net/wireless/trace.h index ed10833f9a3a..1370d52b1393 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -126,6 +126,26 @@ #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_ASSIGN(chandef) \ + do { \ + if ((chandef) && (chandef)->chan) { \ + __entry->band = (chandef)->chan->band; \ + __entry->center_freq = \ + (chandef)->chan->center_freq; \ + __entry->channel_type = (chandef)->_type; \ + } else { \ + __entry->band = 0; \ + __entry->center_freq = 0; \ + __entry->channel_type = 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 SINFO_ENTRY __field(int, generation) \ __field(u32, connected_time) \ __field(u32, inactive_time) \ @@ -433,7 +453,7 @@ TRACE_EVENT(rdev_start_ap, TP_STRUCT__entry( WIPHY_ENTRY NETDEV_ENTRY - CHAN_ENTRY + CHAN_DEF_ENTRY __field(int, beacon_interval) __field(int, dtim_period) __array(char, ssid, IEEE80211_MAX_SSID_LEN + 1) @@ -446,7 +466,7 @@ TRACE_EVENT(rdev_start_ap, TP_fast_assign( WIPHY_ASSIGN; NETDEV_ASSIGN; - CHAN_ASSIGN(settings->channel); + CHAN_DEF_ASSIGN(&settings->chandef); __entry->beacon_interval = settings->beacon_interval; __entry->dtim_period = settings->dtim_period; __entry->hidden_ssid = settings->hidden_ssid; @@ -458,10 +478,10 @@ TRACE_EVENT(rdev_start_ap, memcpy(__entry->ssid, settings->ssid, settings->ssid_len); ), TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", AP settings - ssid: %s, " - CHAN_PR_FMT ", beacon interval: %d, dtim period: %d, " + CHAN_DEF_PR_FMT ", beacon interval: %d, dtim period: %d, " "hidden ssid: %d, wpa versions: %u, privacy: %s, " "auth type: %d, inactivity timeout: %d", - WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_PR_ARG, + WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_DEF_PR_ARG, __entry->beacon_interval, __entry->dtim_period, __entry->hidden_ssid, __entry->wpa_ver, BOOL_TO_STR(__entry->privacy), __entry->auth_type, @@ -933,21 +953,19 @@ TRACE_EVENT(rdev_libertas_set_mesh_channel, ); TRACE_EVENT(rdev_set_monitor_channel, - TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *chan, - enum nl80211_channel_type chan_type), - TP_ARGS(wiphy, chan, chan_type), + TP_PROTO(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef), + TP_ARGS(wiphy, chandef), TP_STRUCT__entry( WIPHY_ENTRY - CHAN_ENTRY - __field(enum nl80211_channel_type, chan_type) + CHAN_DEF_ENTRY ), TP_fast_assign( WIPHY_ASSIGN; - CHAN_ASSIGN(chan); - __entry->chan_type = chan_type; + CHAN_DEF_ASSIGN(chandef); ), - TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel type : %d", - WIPHY_PR_ARG, CHAN_PR_ARG, __entry->chan_type) + TP_printk(WIPHY_PR_FMT CHAN_DEF_PR_FMT, + WIPHY_PR_ARG, CHAN_DEF_PR_ARG) ); TRACE_EVENT(rdev_auth, @@ -1713,22 +1731,25 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel, TP_ARGS(wiphy, wdev) ); -TRACE_EVENT(rdev_return_channel, - TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *chan, - enum nl80211_channel_type type), - TP_ARGS(wiphy, chan, type), +TRACE_EVENT(rdev_return_chandef, + TP_PROTO(struct wiphy *wiphy, int ret, + struct cfg80211_chan_def *chandef), + TP_ARGS(wiphy, ret, chandef), TP_STRUCT__entry( WIPHY_ENTRY - CHAN_ENTRY - __field(enum nl80211_channel_type, type) + __field(int, ret) + CHAN_DEF_ENTRY ), TP_fast_assign( WIPHY_ASSIGN; - CHAN_ASSIGN(chan); - __entry->type = type; + if (ret == 0) + CHAN_DEF_ASSIGN(chandef); + else + CHAN_DEF_ASSIGN((struct cfg80211_chan_def *)NULL); + __entry->ret = ret; ), - TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel type: %d", - WIPHY_PR_ARG, CHAN_PR_ARG, __entry->type) + TP_printk(WIPHY_PR_FMT CHAN_DEF_PR_FMT ", ret: %d", + WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->ret) ); DEFINE_EVENT(wiphy_wdev_evt, rdev_start_p2p_device, @@ -1992,40 +2013,35 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify, NETDEV_PR_ARG, __entry->rssi_event) ); -TRACE_EVENT(cfg80211_can_beacon_sec_chan, - TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel, - enum nl80211_channel_type channel_type), - TP_ARGS(wiphy, channel, channel_type), +TRACE_EVENT(cfg80211_reg_can_beacon, + TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), + TP_ARGS(wiphy, chandef), TP_STRUCT__entry( WIPHY_ENTRY - CHAN_ENTRY - __field(enum nl80211_channel_type, channel_type) + CHAN_DEF_ENTRY ), TP_fast_assign( WIPHY_ASSIGN; - CHAN_ASSIGN(channel); - __entry->channel_type = channel_type; + CHAN_DEF_ASSIGN(chandef); ), - TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel_type: %d", - WIPHY_PR_ARG, CHAN_PR_ARG, __entry->channel_type) + TP_printk(WIPHY_PR_FMT CHAN_DEF_PR_FMT, + WIPHY_PR_ARG, CHAN_DEF_PR_ARG) ); TRACE_EVENT(cfg80211_ch_switch_notify, - TP_PROTO(struct net_device *netdev, int freq, - enum nl80211_channel_type type), - TP_ARGS(netdev, freq, type), + TP_PROTO(struct net_device *netdev, + struct cfg80211_chan_def *chandef), + TP_ARGS(netdev, chandef), TP_STRUCT__entry( NETDEV_ENTRY - __field(int, freq) - __field(enum nl80211_channel_type, type) + CHAN_DEF_ENTRY ), TP_fast_assign( NETDEV_ASSIGN; - __entry->freq = freq; - __entry->type = type; + CHAN_DEF_ASSIGN(chandef); ), - TP_printk(NETDEV_PR_FMT ", freq: %d, type: %d", NETDEV_PR_ARG, - __entry->freq, __entry->type) + TP_printk(NETDEV_PR_FMT CHAN_DEF_PR_FMT, + NETDEV_PR_ARG, CHAN_DEF_PR_ARG) ); DECLARE_EVENT_CLASS(cfg80211_rx_evt, diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 742ab6ec4c9d..da3307f32362 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -784,6 +784,9 @@ 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, + }; int freq, err; switch (wdev->iftype) { @@ -797,8 +800,11 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, return freq; if (freq == 0) return -EINVAL; + chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); + if (!chandef.chan) + return -EINVAL; mutex_lock(&rdev->devlist_mtx); - err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT); + err = cfg80211_set_monitor_channel(rdev, &chandef); mutex_unlock(&rdev->devlist_mtx); return err; case NL80211_IFTYPE_MESH_POINT: @@ -807,9 +813,11 @@ static int cfg80211_wext_siwfreq(struct net_device *dev, return freq; if (freq == 0) return -EINVAL; + chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); + if (!chandef.chan) + return -EINVAL; mutex_lock(&rdev->devlist_mtx); - err = cfg80211_set_mesh_freq(rdev, wdev, freq, - NL80211_CHAN_NO_HT); + err = cfg80211_set_mesh_channel(rdev, wdev, &chandef); mutex_unlock(&rdev->devlist_mtx); return err; default: @@ -823,8 +831,8 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); - struct ieee80211_channel *chan; - enum nl80211_channel_type channel_type; + struct cfg80211_chan_def chandef; + int ret; switch (wdev->iftype) { case NL80211_IFTYPE_STATION: @@ -835,10 +843,10 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, if (!rdev->ops->get_channel) return -EINVAL; - chan = rdev_get_channel(rdev, wdev, &channel_type); - if (!chan) - return -EINVAL; - freq->m = chan->center_freq; + ret = rdev_get_channel(rdev, wdev, &chandef); + if (ret) + return ret; + freq->m = chandef.chan->center_freq; freq->e = 6; return 0; default: diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 1f773f668d1a..e6e5dbf2f616 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -119,7 +119,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev, * channel we disconnected above and reconnect below. */ if (chan && !wdev->wext.connect.ssid_len) { - err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT); + struct cfg80211_chan_def chandef = { + ._type = NL80211_CHAN_NO_HT, + }; + + chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); + if (chandef.chan) + err = cfg80211_set_monitor_channel(rdev, &chandef); + else + err = -EINVAL; goto out; } -- cgit v1.2.3