aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de>2013-05-16 07:00:28 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-06-18 10:06:50 -0400
commit2f301ab29e4656af824592363039d8f6bd5a9f68 (patch)
tree9f433169001a6d349e7f6b923d278327483cb08a
parentf81a9dedaff434604c7fc3d9c299d277b76db0a8 (diff)
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: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de> [fix spelling in comment] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/net/cfg80211.h2
-rw-r--r--include/uapi/linux/nl80211.h4
-rw-r--r--net/wireless/chan.c57
-rw-r--r--net/wireless/nl80211.c21
4 files changed, 72 insertions, 12 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 6a43c34ce96f..316f34bb8e6e 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2342,6 +2342,7 @@ struct cfg80211_ops {
2342 * responds to probe-requests in hardware. 2342 * responds to probe-requests in hardware.
2343 * @WIPHY_FLAG_OFFCHAN_TX: Device supports direct off-channel TX. 2343 * @WIPHY_FLAG_OFFCHAN_TX: Device supports direct off-channel TX.
2344 * @WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL: Device supports remain-on-channel call. 2344 * @WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL: Device supports remain-on-channel call.
2345 * @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels.
2345 */ 2346 */
2346enum wiphy_flags { 2347enum wiphy_flags {
2347 WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), 2348 WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
@@ -2365,6 +2366,7 @@ enum wiphy_flags {
2365 WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD = BIT(19), 2366 WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD = BIT(19),
2366 WIPHY_FLAG_OFFCHAN_TX = BIT(20), 2367 WIPHY_FLAG_OFFCHAN_TX = BIT(20),
2367 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL = BIT(21), 2368 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL = BIT(21),
2369 WIPHY_FLAG_SUPPORTS_5_10_MHZ = BIT(22),
2368}; 2370};
2369 2371
2370/** 2372/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index ca6facf4df0c..861e5eba3953 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2758,6 +2758,8 @@ enum nl80211_channel_type {
2758 * and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well 2758 * and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well
2759 * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 2759 * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
2760 * attribute must be provided as well 2760 * attribute must be provided as well
2761 * @NL80211_CHAN_WIDTH_5: 5 MHz OFDM channel
2762 * @NL80211_CHAN_WIDTH_10: 10 MHz OFDM channel
2761 */ 2763 */
2762enum nl80211_chan_width { 2764enum nl80211_chan_width {
2763 NL80211_CHAN_WIDTH_20_NOHT, 2765 NL80211_CHAN_WIDTH_20_NOHT,
@@ -2766,6 +2768,8 @@ enum nl80211_chan_width {
2766 NL80211_CHAN_WIDTH_80, 2768 NL80211_CHAN_WIDTH_80,
2767 NL80211_CHAN_WIDTH_80P80, 2769 NL80211_CHAN_WIDTH_80P80,
2768 NL80211_CHAN_WIDTH_160, 2770 NL80211_CHAN_WIDTH_160,
2771 NL80211_CHAN_WIDTH_5,
2772 NL80211_CHAN_WIDTH_10,
2769}; 2773};
2770 2774
2771/** 2775/**
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index fd556ac05fdb..50f6195c8b70 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -54,6 +54,8 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
54 control_freq = chandef->chan->center_freq; 54 control_freq = chandef->chan->center_freq;
55 55
56 switch (chandef->width) { 56 switch (chandef->width) {
57 case NL80211_CHAN_WIDTH_5:
58 case NL80211_CHAN_WIDTH_10:
57 case NL80211_CHAN_WIDTH_20: 59 case NL80211_CHAN_WIDTH_20:
58 case NL80211_CHAN_WIDTH_20_NOHT: 60 case NL80211_CHAN_WIDTH_20_NOHT:
59 if (chandef->center_freq1 != control_freq) 61 if (chandef->center_freq1 != control_freq)
@@ -152,6 +154,12 @@ static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
152 int width; 154 int width;
153 155
154 switch (c->width) { 156 switch (c->width) {
157 case NL80211_CHAN_WIDTH_5:
158 width = 5;
159 break;
160 case NL80211_CHAN_WIDTH_10:
161 width = 10;
162 break;
155 case NL80211_CHAN_WIDTH_20: 163 case NL80211_CHAN_WIDTH_20:
156 case NL80211_CHAN_WIDTH_20_NOHT: 164 case NL80211_CHAN_WIDTH_20_NOHT:
157 width = 20; 165 width = 20;
@@ -194,6 +202,16 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
194 if (c1->width == c2->width) 202 if (c1->width == c2->width)
195 return NULL; 203 return NULL;
196 204
205 /*
206 * can't be compatible if one of them is 5 or 10 MHz,
207 * but they don't have the same width.
208 */
209 if (c1->width == NL80211_CHAN_WIDTH_5 ||
210 c1->width == NL80211_CHAN_WIDTH_10 ||
211 c2->width == NL80211_CHAN_WIDTH_5 ||
212 c2->width == NL80211_CHAN_WIDTH_10)
213 return NULL;
214
197 if (c1->width == NL80211_CHAN_WIDTH_20_NOHT || 215 if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
198 c1->width == NL80211_CHAN_WIDTH_20) 216 c1->width == NL80211_CHAN_WIDTH_20)
199 return c2; 217 return c2;
@@ -264,11 +282,17 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
264 u32 bandwidth) 282 u32 bandwidth)
265{ 283{
266 struct ieee80211_channel *c; 284 struct ieee80211_channel *c;
267 u32 freq; 285 u32 freq, start_freq, end_freq;
286
287 if (bandwidth <= 20) {
288 start_freq = center_freq;
289 end_freq = center_freq;
290 } else {
291 start_freq = center_freq - bandwidth/2 + 10;
292 end_freq = center_freq + bandwidth/2 - 10;
293 }
268 294
269 for (freq = center_freq - bandwidth/2 + 10; 295 for (freq = start_freq; freq <= end_freq; freq += 20) {
270 freq <= center_freq + bandwidth/2 - 10;
271 freq += 20) {
272 c = ieee80211_get_channel(wiphy, freq); 296 c = ieee80211_get_channel(wiphy, freq);
273 if (!c) 297 if (!c)
274 return -EINVAL; 298 return -EINVAL;
@@ -310,11 +334,17 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
310 u32 prohibited_flags) 334 u32 prohibited_flags)
311{ 335{
312 struct ieee80211_channel *c; 336 struct ieee80211_channel *c;
313 u32 freq; 337 u32 freq, start_freq, end_freq;
338
339 if (bandwidth <= 20) {
340 start_freq = center_freq;
341 end_freq = center_freq;
342 } else {
343 start_freq = center_freq - bandwidth/2 + 10;
344 end_freq = center_freq + bandwidth/2 - 10;
345 }
314 346
315 for (freq = center_freq - bandwidth/2 + 10; 347 for (freq = start_freq; freq <= end_freq; freq += 20) {
316 freq <= center_freq + bandwidth/2 - 10;
317 freq += 20) {
318 c = ieee80211_get_channel(wiphy, freq); 348 c = ieee80211_get_channel(wiphy, freq);
319 if (!c) 349 if (!c)
320 return false; 350 return false;
@@ -349,6 +379,12 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
349 control_freq = chandef->chan->center_freq; 379 control_freq = chandef->chan->center_freq;
350 380
351 switch (chandef->width) { 381 switch (chandef->width) {
382 case NL80211_CHAN_WIDTH_5:
383 width = 5;
384 break;
385 case NL80211_CHAN_WIDTH_10:
386 width = 10;
387 break;
352 case NL80211_CHAN_WIDTH_20: 388 case NL80211_CHAN_WIDTH_20:
353 if (!ht_cap->ht_supported) 389 if (!ht_cap->ht_supported)
354 return false; 390 return false;
@@ -405,6 +441,11 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
405 if (width > 20) 441 if (width > 20)
406 prohibited_flags |= IEEE80211_CHAN_NO_OFDM; 442 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
407 443
444 /* 5 and 10 MHz are only defined for the OFDM PHY */
445 if (width < 20)
446 prohibited_flags |= IEEE80211_CHAN_NO_OFDM;
447
448
408 if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1, 449 if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
409 width, prohibited_flags)) 450 width, prohibited_flags))
410 return false; 451 return false;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1c4f7daea6c7..4ab1ffa9df11 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1188,6 +1188,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
1188 if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) && 1188 if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
1189 nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP)) 1189 nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
1190 goto nla_put_failure; 1190 goto nla_put_failure;
1191 if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ) &&
1192 nla_put_flag(msg, WIPHY_FLAG_SUPPORTS_5_10_MHZ))
1193 goto nla_put_failure;
1191 1194
1192 (*split_start)++; 1195 (*split_start)++;
1193 if (split) 1196 if (split)
@@ -1731,6 +1734,11 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
1731 IEEE80211_CHAN_DISABLED)) 1734 IEEE80211_CHAN_DISABLED))
1732 return -EINVAL; 1735 return -EINVAL;
1733 1736
1737 if ((chandef->width == NL80211_CHAN_WIDTH_5 ||
1738 chandef->width == NL80211_CHAN_WIDTH_10) &&
1739 !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ))
1740 return -EINVAL;
1741
1734 return 0; 1742 return 0;
1735} 1743}
1736 1744
@@ -6280,11 +6288,16 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
6280 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef)) 6288 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef))
6281 return -EINVAL; 6289 return -EINVAL;
6282 6290
6283 if (ibss.chandef.width > NL80211_CHAN_WIDTH_40) 6291 switch (ibss.chandef.width) {
6284 return -EINVAL; 6292 case NL80211_CHAN_WIDTH_20_NOHT:
6285 if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT && 6293 break;
6286 !(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)) 6294 case NL80211_CHAN_WIDTH_20:
6295 case NL80211_CHAN_WIDTH_40:
6296 if (rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)
6297 break;
6298 default:
6287 return -EINVAL; 6299 return -EINVAL;
6300 }
6288 6301
6289 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; 6302 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
6290 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY]; 6303 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];