aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c66
1 files changed, 36 insertions, 30 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a3a152f55dd0..56d729c43b31 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -77,6 +77,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
77 [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, 77 [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
78 [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, 78 [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
79 [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, 79 [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
80 [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
80 81
81 [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, 82 [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
82 [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, 83 [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
@@ -492,7 +493,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
492 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; 493 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
493 struct ieee80211_channel *chan; 494 struct ieee80211_channel *chan;
494 struct ieee80211_sta_ht_cap *ht_cap; 495 struct ieee80211_sta_ht_cap *ht_cap;
495 u32 freq, sec_freq; 496 u32 freq;
496 497
497 if (!rdev->ops->set_channel) { 498 if (!rdev->ops->set_channel) {
498 result = -EOPNOTSUPP; 499 result = -EOPNOTSUPP;
@@ -518,33 +519,28 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
518 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) 519 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
519 goto bad_res; 520 goto bad_res;
520 521
521 if (channel_type == NL80211_CHAN_HT40MINUS) 522 if (channel_type == NL80211_CHAN_HT40MINUS &&
522 sec_freq = freq - 20; 523 (chan->flags & IEEE80211_CHAN_NO_HT40MINUS))
523 else if (channel_type == NL80211_CHAN_HT40PLUS) 524 goto bad_res;
524 sec_freq = freq + 20; 525 else if (channel_type == NL80211_CHAN_HT40PLUS &&
525 else 526 (chan->flags & IEEE80211_CHAN_NO_HT40PLUS))
526 sec_freq = 0;
527
528 ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
529
530 /* no HT capabilities */
531 if (channel_type != NL80211_CHAN_NO_HT &&
532 !ht_cap->ht_supported)
533 goto bad_res; 527 goto bad_res;
534 528
535 if (sec_freq) { 529 /*
536 struct ieee80211_channel *schan; 530 * At this point we know if that if HT40 was requested
531 * we are allowed to use it and the extension channel
532 * exists.
533 */
534
535 ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
537 536
538 /* no 40 MHz capabilities */ 537 /* no HT capabilities or intolerant */
538 if (channel_type != NL80211_CHAN_NO_HT) {
539 if (!ht_cap->ht_supported)
540 goto bad_res;
539 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || 541 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
540 (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) 542 (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT))
541 goto bad_res; 543 goto bad_res;
542
543 schan = ieee80211_get_channel(&rdev->wiphy, sec_freq);
544
545 /* Secondary channel not allowed */
546 if (!schan || schan->flags & IEEE80211_CHAN_DISABLED)
547 goto bad_res;
548 } 544 }
549 545
550 result = rdev->ops->set_channel(&rdev->wiphy, chan, 546 result = rdev->ops->set_channel(&rdev->wiphy, chan,
@@ -2571,18 +2567,24 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
2571 rem_reg_rules) { 2567 rem_reg_rules) {
2572 num_rules++; 2568 num_rules++;
2573 if (num_rules > NL80211_MAX_SUPP_REG_RULES) 2569 if (num_rules > NL80211_MAX_SUPP_REG_RULES)
2574 goto bad_reg; 2570 return -EINVAL;
2575 } 2571 }
2576 2572
2577 if (!reg_is_valid_request(alpha2)) 2573 mutex_lock(&cfg80211_mutex);
2578 return -EINVAL; 2574
2575 if (!reg_is_valid_request(alpha2)) {
2576 r = -EINVAL;
2577 goto bad_reg;
2578 }
2579 2579
2580 size_of_regd = sizeof(struct ieee80211_regdomain) + 2580 size_of_regd = sizeof(struct ieee80211_regdomain) +
2581 (num_rules * sizeof(struct ieee80211_reg_rule)); 2581 (num_rules * sizeof(struct ieee80211_reg_rule));
2582 2582
2583 rd = kzalloc(size_of_regd, GFP_KERNEL); 2583 rd = kzalloc(size_of_regd, GFP_KERNEL);
2584 if (!rd) 2584 if (!rd) {
2585 return -ENOMEM; 2585 r = -ENOMEM;
2586 goto bad_reg;
2587 }
2586 2588
2587 rd->n_reg_rules = num_rules; 2589 rd->n_reg_rules = num_rules;
2588 rd->alpha2[0] = alpha2[0]; 2590 rd->alpha2[0] = alpha2[0];
@@ -2599,20 +2601,24 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
2599 2601
2600 rule_idx++; 2602 rule_idx++;
2601 2603
2602 if (rule_idx > NL80211_MAX_SUPP_REG_RULES) 2604 if (rule_idx > NL80211_MAX_SUPP_REG_RULES) {
2605 r = -EINVAL;
2603 goto bad_reg; 2606 goto bad_reg;
2607 }
2604 } 2608 }
2605 2609
2606 BUG_ON(rule_idx != num_rules); 2610 BUG_ON(rule_idx != num_rules);
2607 2611
2608 mutex_lock(&cfg80211_mutex);
2609 r = set_regdom(rd); 2612 r = set_regdom(rd);
2613
2610 mutex_unlock(&cfg80211_mutex); 2614 mutex_unlock(&cfg80211_mutex);
2615
2611 return r; 2616 return r;
2612 2617
2613 bad_reg: 2618 bad_reg:
2619 mutex_unlock(&cfg80211_mutex);
2614 kfree(rd); 2620 kfree(rd);
2615 return -EINVAL; 2621 return r;
2616} 2622}
2617 2623
2618static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) 2624static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)