diff options
author | Simon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de> | 2013-05-16 07:00:28 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-06-18 10:06:50 -0400 |
commit | 2f301ab29e4656af824592363039d8f6bd5a9f68 (patch) | |
tree | 9f433169001a6d349e7f6b923d278327483cb08a | |
parent | f81a9dedaff434604c7fc3d9c299d277b76db0a8 (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.h | 2 | ||||
-rw-r--r-- | include/uapi/linux/nl80211.h | 4 | ||||
-rw-r--r-- | net/wireless/chan.c | 57 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 21 |
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 | */ |
2346 | enum wiphy_flags { | 2347 | enum 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 | */ |
2762 | enum nl80211_chan_width { | 2764 | enum 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]; |