diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/chan.c | 57 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 21 |
2 files changed, 66 insertions, 12 deletions
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]; |