diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-12-08 06:39:04 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-12-12 13:48:25 -0500 |
commit | 306d6112f9b396ed237305036f8e889f8aa964b5 (patch) | |
tree | e84748fb374e84bd16d943c2615480a08c96be3d /net | |
parent | 7ba1c04ed727a70df2dc63464232c0ec906ad67d (diff) |
cfg80211: fix nl80211 frequency handling
Fix two small bugs with HT frequency setting:
* HT is accepted even when the driver is incapable
* HT40 is accepted when the driver cannot do 40 MHz
(both on the selected band)
Also simplify the code a little.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/wireless/nl80211.c | 40 |
1 files changed, 26 insertions, 14 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9caee6022e3f..4335f76be71f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -365,6 +365,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
365 | enum nl80211_sec_chan_offset sec_chan_offset = | 365 | enum nl80211_sec_chan_offset sec_chan_offset = |
366 | NL80211_SEC_CHAN_NO_HT; | 366 | NL80211_SEC_CHAN_NO_HT; |
367 | struct ieee80211_channel *chan; | 367 | struct ieee80211_channel *chan; |
368 | struct ieee80211_sta_ht_cap *ht_cap; | ||
368 | u32 freq, sec_freq; | 369 | u32 freq, sec_freq; |
369 | 370 | ||
370 | if (!rdev->ops->set_channel) { | 371 | if (!rdev->ops->set_channel) { |
@@ -372,26 +373,25 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
372 | goto bad_res; | 373 | goto bad_res; |
373 | } | 374 | } |
374 | 375 | ||
376 | result = -EINVAL; | ||
377 | |||
375 | if (info->attrs[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]) { | 378 | if (info->attrs[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]) { |
376 | sec_chan_offset = nla_get_u32( | 379 | sec_chan_offset = nla_get_u32(info->attrs[ |
377 | info->attrs[ | ||
378 | NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]); | 380 | NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]); |
379 | if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT && | 381 | if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT && |
380 | sec_chan_offset != NL80211_SEC_CHAN_DISABLED && | 382 | sec_chan_offset != NL80211_SEC_CHAN_DISABLED && |
381 | sec_chan_offset != NL80211_SEC_CHAN_BELOW && | 383 | sec_chan_offset != NL80211_SEC_CHAN_BELOW && |
382 | sec_chan_offset != NL80211_SEC_CHAN_ABOVE) { | 384 | sec_chan_offset != NL80211_SEC_CHAN_ABOVE) |
383 | result = -EINVAL; | ||
384 | goto bad_res; | 385 | goto bad_res; |
385 | } | ||
386 | } | 386 | } |
387 | 387 | ||
388 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 388 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
389 | chan = ieee80211_get_channel(&rdev->wiphy, freq); | 389 | chan = ieee80211_get_channel(&rdev->wiphy, freq); |
390 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) { | 390 | |
391 | /* Primary channel not allowed */ | 391 | /* Primary channel not allowed */ |
392 | result = -EINVAL; | 392 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) |
393 | goto bad_res; | 393 | goto bad_res; |
394 | } | 394 | |
395 | if (sec_chan_offset == NL80211_SEC_CHAN_BELOW) | 395 | if (sec_chan_offset == NL80211_SEC_CHAN_BELOW) |
396 | sec_freq = freq - 20; | 396 | sec_freq = freq - 20; |
397 | else if (sec_chan_offset == NL80211_SEC_CHAN_ABOVE) | 397 | else if (sec_chan_offset == NL80211_SEC_CHAN_ABOVE) |
@@ -399,14 +399,26 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
399 | else | 399 | else |
400 | sec_freq = 0; | 400 | sec_freq = 0; |
401 | 401 | ||
402 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | ||
403 | |||
404 | /* no HT capabilities */ | ||
405 | if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT && | ||
406 | !ht_cap->ht_supported) | ||
407 | goto bad_res; | ||
408 | |||
402 | if (sec_freq) { | 409 | if (sec_freq) { |
403 | struct ieee80211_channel *schan; | 410 | struct ieee80211_channel *schan; |
411 | |||
412 | /* no 40 MHz capabilities */ | ||
413 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | ||
414 | (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) | ||
415 | goto bad_res; | ||
416 | |||
404 | schan = ieee80211_get_channel(&rdev->wiphy, sec_freq); | 417 | schan = ieee80211_get_channel(&rdev->wiphy, sec_freq); |
405 | if (!schan || schan->flags & IEEE80211_CHAN_DISABLED) { | 418 | |
406 | /* Secondary channel not allowed */ | 419 | /* Secondary channel not allowed */ |
407 | result = -EINVAL; | 420 | if (!schan || schan->flags & IEEE80211_CHAN_DISABLED) |
408 | goto bad_res; | 421 | goto bad_res; |
409 | } | ||
410 | } | 422 | } |
411 | 423 | ||
412 | result = rdev->ops->set_channel(&rdev->wiphy, chan, | 424 | result = rdev->ops->set_channel(&rdev->wiphy, chan, |
@@ -416,7 +428,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
416 | } | 428 | } |
417 | 429 | ||
418 | 430 | ||
419 | bad_res: | 431 | bad_res: |
420 | cfg80211_put_dev(rdev); | 432 | cfg80211_put_dev(rdev); |
421 | return result; | 433 | return result; |
422 | } | 434 | } |