Skip to content

Commit

Permalink
nl80211/cfg80211: support VHT channel configuration
Browse files Browse the repository at this point in the history
Change nl80211 to support specifying a VHT (or HT)
using the control channel frequency (as before) and
new attributes for the channel width and first and
second center frequency. The old channel type is of
course still supported for HT.

Also change the cfg80211 channel definition struct
to support these by adding the relevant fields to
it (and removing the _type field.)

This also adds new helper functions:
 - cfg80211_chandef_create to create a channel def
   struct given the control channel and channel type,
 - cfg80211_chandef_identical to check if two channel
   definitions are identical
 - cfg80211_chandef_compatible to check if the given
   channel definitions are compatible, and return the
   wider of the two

This isn't entirely complete, but that doesn't matter
until we have a driver using it. In particular, it's
missing
 - regulatory checks on the usable bandwidth (if that
   even makes sense)
 - regulatory TX power (database can't deal with it)
 - a proper channel compatibility calculation for the
   new channel types

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
  • Loading branch information
jmberg-intel committed Nov 26, 2012
1 parent 683b6d3 commit 3d9d1d6
Show file tree
Hide file tree
Showing 13 changed files with 507 additions and 113 deletions.
10 changes: 4 additions & 6 deletions drivers/net/wireless/ath/ath6kl/cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -1099,12 +1099,10 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
"channel switch notify nw_type %d freq %d mode %d\n",
vif->nw_type, freq, mode);

chandef.chan = ieee80211_get_channel(vif->ar->wiphy, freq);
if (WARN_ON(!chandef.chan))
return;

chandef._type = (mode == WMI_11G_HT20) ?
NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT;
cfg80211_chandef_create(&chandef,
ieee80211_get_channel(vif->ar->wiphy, freq),
(mode == WMI_11G_HT20) ?
NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);

cfg80211_ch_switch_notify(vif->ndev, &chandef);
}
Expand Down
73 changes: 69 additions & 4 deletions include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,20 +308,85 @@ struct key_params {
/**
* struct cfg80211_chan_def - channel definition
* @chan: the (control) channel
* @_type: the channel type, don't use this field,
* use cfg80211_get_chandef_type() if needed.
* @width: channel width
* @center_freq1: center frequency of first segment
* @center_freq2: center frequency of second segment
* (only with 80+80 MHz)
*/
struct cfg80211_chan_def {
struct ieee80211_channel *chan;
enum nl80211_channel_type _type;
enum nl80211_chan_width width;
u32 center_freq1;
u32 center_freq2;
};

/**
* cfg80211_get_chandef_type - return old channel type from chandef
* @chandef: the channel definition
*
* Returns the old channel type (NOHT, HT20, HT40+/-) from a given
* chandef, which must have a bandwidth allowing this conversion.
*/
static inline enum nl80211_channel_type
cfg80211_get_chandef_type(const struct cfg80211_chan_def *chandef)
{
return chandef->_type;
switch (chandef->width) {
case NL80211_CHAN_WIDTH_20_NOHT:
return NL80211_CHAN_NO_HT;
case NL80211_CHAN_WIDTH_20:
return NL80211_CHAN_HT20;
case NL80211_CHAN_WIDTH_40:
if (chandef->center_freq1 > chandef->chan->center_freq)
return NL80211_CHAN_HT40PLUS;
return NL80211_CHAN_HT40MINUS;
default:
WARN_ON(1);
return NL80211_CHAN_NO_HT;
}
}

/**
* cfg80211_chandef_create - create channel definition using channel type
* @chandef: the channel definition struct to fill
* @channel: the control channel
* @chantype: the channel type
*
* Given a channel type, create a channel definition.
*/
void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
struct ieee80211_channel *channel,
enum nl80211_channel_type chantype);

/**
* cfg80211_chandef_identical - check if two channel definitions are identical
* @chandef1: first channel definition
* @chandef2: second channel definition
*
* Returns %true if the channels defined by the channel definitions are
* identical, %false otherwise.
*/
static inline bool
cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
const struct cfg80211_chan_def *chandef2)
{
return (chandef1->chan == chandef2->chan &&
chandef1->width == chandef2->width &&
chandef1->center_freq1 == chandef2->center_freq1 &&
chandef1->center_freq2 == chandef2->center_freq2);
}

/**
* cfg80211_chandef_compatible - check if two channel definitions are compatible
* @chandef1: first channel definition
* @chandef2: second channel definition
*
* Returns %NULL if the given channel definitions are incompatible,
* chandef1 or chandef2 otherwise.
*/
const struct cfg80211_chan_def *
cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1,
const struct cfg80211_chan_def *chandef2);

/**
* enum survey_info_flags - survey information flags
*
Expand Down
61 changes: 52 additions & 9 deletions include/uapi/linux/nl80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,9 @@
* to get a list of all present wiphys.
* @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
* %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
* %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
* %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT,
* %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ (and the
* attributes determining the channel width; this is used for setting
* monitor mode channel), %NL80211_ATTR_WIPHY_RETRY_SHORT,
* %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
* and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
* However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
Expand Down Expand Up @@ -171,7 +172,7 @@
* %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
* %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT.
* The channel to use can be set on the interface or be given using the
* %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_CHANNEL_TYPE attrs.
* %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width.
* @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
* @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
* @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
Expand Down Expand Up @@ -471,8 +472,8 @@
* command is used as an event to indicate the that a trigger level was
* reached.
* @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ
* and %NL80211_ATTR_WIPHY_CHANNEL_TYPE) the given interface (identifed
* by %NL80211_ATTR_IFINDEX) shall operate on.
* and the attributes determining channel width) the given interface
* (identifed by %NL80211_ATTR_IFINDEX) shall operate on.
* In case multiple channels are supported by the device, the mechanism
* with which it switches channels is implementation-defined.
* When a monitor interface is given, it can only switch channel while
Expand Down Expand Up @@ -566,8 +567,8 @@
*
* @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels
* independently of the userspace SME, send this event indicating
* %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with
* %NL80211_ATTR_WIPHY_CHANNEL_TYPE.
* %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the
* attributes determining channel width.
*
* @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by
* its %NL80211_ATTR_WDEV identifier. It must have been created with
Expand Down Expand Up @@ -771,14 +772,26 @@ enum nl80211_commands {
* /sys/class/ieee80211/<phyname>/index
* @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
* @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
* @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
* @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz,
* defines the channel together with the (deprecated)
* %NL80211_ATTR_WIPHY_CHANNEL_TYPE attribute or the attributes
* %NL80211_ATTR_CHANNEL_WIDTH and if needed %NL80211_ATTR_CENTER_FREQ1
* and %NL80211_ATTR_CENTER_FREQ2
* @NL80211_ATTR_CHANNEL_WIDTH: u32 attribute containing one of the values
* of &enum nl80211_chan_width, describing the channel width. See the
* documentation of the enum for more information.
* @NL80211_ATTR_CENTER_FREQ1: Center frequency of the first part of the
* channel, used for anything but 20 MHz bandwidth
* @NL80211_ATTR_CENTER_FREQ2: Center frequency of the second part of the
* channel, used only for 80+80 MHz bandwidth
* @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
* if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
* if HT20 or HT40 are to be used (i.e., HT disabled if not included):
* NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
* this attribute)
* NL80211_CHAN_HT20 = HT20 only
* NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
* NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
* This attribute is now deprecated.
* @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is
* less than or equal to the RTS threshold; allowed range: 1..255;
* dot11ShortRetryLimit; u8
Expand Down Expand Up @@ -1553,6 +1566,10 @@ enum nl80211_attrs {

NL80211_ATTR_SCAN_FLAGS,

NL80211_ATTR_CHANNEL_WIDTH,
NL80211_ATTR_CENTER_FREQ1,
NL80211_ATTR_CENTER_FREQ2,

/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
Expand Down Expand Up @@ -2454,6 +2471,32 @@ enum nl80211_channel_type {
NL80211_CHAN_HT40PLUS
};

/**
* enum nl80211_chan_width - channel width definitions
*
* These values are used with the %NL80211_ATTR_CHANNEL_WIDTH
* attribute.
*
* @NL80211_CHAN_WIDTH_20_NOHT: 20 MHz, non-HT channel
* @NL80211_CHAN_WIDTH_20: 20 MHz HT channel
* @NL80211_CHAN_WIDTH_40: 40 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
* attribute must be provided as well
* @NL80211_CHAN_WIDTH_80: 80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
* attribute must be provided as well
* @NL80211_CHAN_WIDTH_80P80: 80+80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
* and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well
* @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
* attribute must be provided as well
*/
enum nl80211_chan_width {
NL80211_CHAN_WIDTH_20_NOHT,
NL80211_CHAN_WIDTH_20,
NL80211_CHAN_WIDTH_40,
NL80211_CHAN_WIDTH_80,
NL80211_CHAN_WIDTH_80P80,
NL80211_CHAN_WIDTH_160,
};

/**
* enum nl80211_bss - netlink attributes for a BSS
*
Expand Down
5 changes: 3 additions & 2 deletions net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
13 changes: 7 additions & 6 deletions net/mac80211/ibss.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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) +
Expand All @@ -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) {
Expand Down
Loading

0 comments on commit 3d9d1d6

Please sign in to comment.