Commit 2f301ab2 authored by Simon Wunderlich's avatar Simon Wunderlich Committed by Johannes Berg

nl80211/cfg80211: add 5 and 10 MHz defines and wiphy flag

Add defines for 5 and 10 MHz channel width and fix channel
handling functions accordingly.

Also check for and report the WIPHY_FLAG_SUPPORTS_5_10_MHZ
capability.
Signed-off-by: default avatarSimon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: default avatarMathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de>
[fix spelling in comment]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent f81a9ded
...@@ -2342,6 +2342,7 @@ struct cfg80211_ops { ...@@ -2342,6 +2342,7 @@ struct cfg80211_ops {
* responds to probe-requests in hardware. * responds to probe-requests in hardware.
* @WIPHY_FLAG_OFFCHAN_TX: Device supports direct off-channel TX. * @WIPHY_FLAG_OFFCHAN_TX: Device supports direct off-channel TX.
* @WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL: Device supports remain-on-channel call. * @WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL: Device supports remain-on-channel call.
* @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels.
*/ */
enum wiphy_flags { enum wiphy_flags {
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
...@@ -2365,6 +2366,7 @@ enum wiphy_flags { ...@@ -2365,6 +2366,7 @@ enum wiphy_flags {
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD = BIT(19), WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD = BIT(19),
WIPHY_FLAG_OFFCHAN_TX = BIT(20), WIPHY_FLAG_OFFCHAN_TX = BIT(20),
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL = BIT(21), WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL = BIT(21),
WIPHY_FLAG_SUPPORTS_5_10_MHZ = BIT(22),
}; };
/** /**
......
...@@ -2758,6 +2758,8 @@ enum nl80211_channel_type { ...@@ -2758,6 +2758,8 @@ enum nl80211_channel_type {
* and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well * and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well
* @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
* attribute must be provided as well * attribute must be provided as well
* @NL80211_CHAN_WIDTH_5: 5 MHz OFDM channel
* @NL80211_CHAN_WIDTH_10: 10 MHz OFDM channel
*/ */
enum nl80211_chan_width { enum nl80211_chan_width {
NL80211_CHAN_WIDTH_20_NOHT, NL80211_CHAN_WIDTH_20_NOHT,
...@@ -2766,6 +2768,8 @@ enum nl80211_chan_width { ...@@ -2766,6 +2768,8 @@ enum nl80211_chan_width {
NL80211_CHAN_WIDTH_80, NL80211_CHAN_WIDTH_80,
NL80211_CHAN_WIDTH_80P80, NL80211_CHAN_WIDTH_80P80,
NL80211_CHAN_WIDTH_160, NL80211_CHAN_WIDTH_160,
NL80211_CHAN_WIDTH_5,
NL80211_CHAN_WIDTH_10,
}; };
/** /**
......
...@@ -54,6 +54,8 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) ...@@ -54,6 +54,8 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
control_freq = chandef->chan->center_freq; control_freq = chandef->chan->center_freq;
switch (chandef->width) { switch (chandef->width) {
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_20: case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_20_NOHT: case NL80211_CHAN_WIDTH_20_NOHT:
if (chandef->center_freq1 != control_freq) if (chandef->center_freq1 != control_freq)
...@@ -152,6 +154,12 @@ static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c) ...@@ -152,6 +154,12 @@ static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
int width; int width;
switch (c->width) { switch (c->width) {
case NL80211_CHAN_WIDTH_5:
width = 5;
break;
case NL80211_CHAN_WIDTH_10:
width = 10;
break;
case NL80211_CHAN_WIDTH_20: case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_20_NOHT: case NL80211_CHAN_WIDTH_20_NOHT:
width = 20; width = 20;
...@@ -194,6 +202,16 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, ...@@ -194,6 +202,16 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
if (c1->width == c2->width) if (c1->width == c2->width)
return NULL; return NULL;
/*
* can't be compatible if one of them is 5 or 10 MHz,
* but they don't have the same width.
*/
if (c1->width == NL80211_CHAN_WIDTH_5 ||
c1->width == NL80211_CHAN_WIDTH_10 ||
c2->width == NL80211_CHAN_WIDTH_5 ||
c2->width == NL80211_CHAN_WIDTH_10)
return NULL;
if (c1->width == NL80211_CHAN_WIDTH_20_NOHT || if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
c1->width == NL80211_CHAN_WIDTH_20) c1->width == NL80211_CHAN_WIDTH_20)
return c2; return c2;
...@@ -264,11 +282,17 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy, ...@@ -264,11 +282,17 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
u32 bandwidth) u32 bandwidth)
{ {
struct ieee80211_channel *c; struct ieee80211_channel *c;
u32 freq; u32 freq, start_freq, end_freq;
if (bandwidth <= 20) {
start_freq = center_freq;
end_freq = center_freq;
} else {
start_freq = center_freq - bandwidth/2 + 10;
end_freq = center_freq + bandwidth/2 - 10;
}
for (freq = center_freq - bandwidth/2 + 10; for (freq = start_freq; freq <= end_freq; freq += 20) {
freq <= center_freq + bandwidth/2 - 10;
freq += 20) {
c = ieee80211_get_channel(wiphy, freq); c = ieee80211_get_channel(wiphy, freq);
if (!c) if (!c)
return -EINVAL; return -EINVAL;
...@@ -310,11 +334,17 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, ...@@ -310,11 +334,17 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
u32 prohibited_flags) u32 prohibited_flags)
{ {
struct ieee80211_channel *c; struct ieee80211_channel *c;
u32 freq; u32 freq, start_freq, end_freq;
if (bandwidth <= 20) {
start_freq = center_freq;
end_freq = center_freq;
} else {
start_freq = center_freq - bandwidth/2 + 10;
end_freq = center_freq + bandwidth/2 - 10;
}
for (freq = center_freq - bandwidth/2 + 10; for (freq = start_freq; freq <= end_freq; freq += 20) {
freq <= center_freq + bandwidth/2 - 10;
freq += 20) {
c = ieee80211_get_channel(wiphy, freq); c = ieee80211_get_channel(wiphy, freq);
if (!c) if (!c)
return false; return false;
...@@ -349,6 +379,12 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, ...@@ -349,6 +379,12 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
control_freq = chandef->chan->center_freq; control_freq = chandef->chan->center_freq;
switch (chandef->width) { switch (chandef->width) {
case NL80211_CHAN_WIDTH_5:
width = 5;
break;
case NL80211_CHAN_WIDTH_10:
width = 10;
break;
case NL80211_CHAN_WIDTH_20: case NL80211_CHAN_WIDTH_20:
if (!ht_cap->ht_supported) if (!ht_cap->ht_supported)
return false; return false;
...@@ -405,6 +441,11 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy, ...@@ -405,6 +441,11 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
if (width > 20) if (width > 20)
prohibited_flags |= IEEE80211_CHAN_NO_OFDM; prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
/* 5 and 10 MHz are only defined for the OFDM PHY */
if (width < 20)
prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1, if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
width, prohibited_flags)) width, prohibited_flags))
return false; return false;
......
...@@ -1188,6 +1188,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, ...@@ -1188,6 +1188,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
goto nla_put_failure; goto nla_put_failure;
if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ))
goto nla_put_failure;
(*split_start)++; (*split_start)++;
if (split) if (split)
...@@ -1731,6 +1734,11 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, ...@@ -1731,6 +1734,11 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
IEEE80211_CHAN_DISABLED)) IEEE80211_CHAN_DISABLED))
return -EINVAL; return -EINVAL;
if ((chandef->width == NL80211_CHAN_WIDTH_5 ||
chandef->width == NL80211_CHAN_WIDTH_10) &&
!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ))
return -EINVAL;
return 0; return 0;
} }
...@@ -6280,11 +6288,16 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) ...@@ -6280,11 +6288,16 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef)) if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef))
return -EINVAL; return -EINVAL;
if (ibss.chandef.width > NL80211_CHAN_WIDTH_40) switch (ibss.chandef.width) {
return -EINVAL; case NL80211_CHAN_WIDTH_20_NOHT:
if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT && break;
!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)) case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_40:
if (rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)
break;
default:
return -EINVAL; return -EINVAL;
}
ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment