diff options
author | David S. Miller <davem@davemloft.net> | 2010-01-19 14:43:42 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-01-19 14:43:42 -0500 |
commit | 6373464288cab09bc641be301d8d30fc9f64ba71 (patch) | |
tree | c1bc92dc630aa15da2e12bc0d09c92169817a702 /net/wireless | |
parent | 6d955180b2f9ccff444df06265160868cabb289a (diff) | |
parent | 730dd70549e0ec755dd55615ba5cfc38a482a947 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Conflicts:
drivers/net/wireless/iwlwifi/iwl-core.h
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.c | 1 | ||||
-rw-r--r-- | net/wireless/core.h | 3 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 130 | ||||
-rw-r--r-- | net/wireless/reg.c | 319 | ||||
-rw-r--r-- | net/wireless/reg.h | 11 | ||||
-rw-r--r-- | net/wireless/scan.c | 120 | ||||
-rw-r--r-- | net/wireless/sme.c | 1 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 34 |
8 files changed, 556 insertions, 63 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index c2a2c563d21a..0a545bb6ed05 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -402,6 +402,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
402 | rdev->wiphy.retry_long = 4; | 402 | rdev->wiphy.retry_long = 4; |
403 | rdev->wiphy.frag_threshold = (u32) -1; | 403 | rdev->wiphy.frag_threshold = (u32) -1; |
404 | rdev->wiphy.rts_threshold = (u32) -1; | 404 | rdev->wiphy.rts_threshold = (u32) -1; |
405 | rdev->wiphy.coverage_class = 0; | ||
405 | 406 | ||
406 | return &rdev->wiphy; | 407 | return &rdev->wiphy; |
407 | } | 408 | } |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 30ec95f05b52..2d6a6b9c0c43 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -111,7 +111,8 @@ struct cfg80211_internal_bss { | |||
111 | unsigned long ts; | 111 | unsigned long ts; |
112 | struct kref ref; | 112 | struct kref ref; |
113 | atomic_t hold; | 113 | atomic_t hold; |
114 | bool ies_allocated; | 114 | bool beacon_ies_allocated; |
115 | bool proberesp_ies_allocated; | ||
115 | 116 | ||
116 | /* must be last because of priv member */ | 117 | /* must be last because of priv member */ |
117 | struct cfg80211_bss pub; | 118 | struct cfg80211_bss pub; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e3bee3cecdfa..4af7991a9ec8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -69,6 +69,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
69 | [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, | 69 | [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, |
70 | [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, | 70 | [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, |
71 | [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, | 71 | [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, |
72 | [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 }, | ||
72 | 73 | ||
73 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, | 74 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, |
74 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 75 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
@@ -143,6 +144,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
143 | .len = WLAN_PMKID_LEN }, | 144 | .len = WLAN_PMKID_LEN }, |
144 | [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, | 145 | [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, |
145 | [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, | 146 | [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, |
147 | [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED }, | ||
146 | }; | 148 | }; |
147 | 149 | ||
148 | /* policy for the attributes */ | 150 | /* policy for the attributes */ |
@@ -444,6 +446,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
444 | dev->wiphy.frag_threshold); | 446 | dev->wiphy.frag_threshold); |
445 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, | 447 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, |
446 | dev->wiphy.rts_threshold); | 448 | dev->wiphy.rts_threshold); |
449 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, | ||
450 | dev->wiphy.coverage_class); | ||
447 | 451 | ||
448 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | 452 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, |
449 | dev->wiphy.max_scan_ssids); | 453 | dev->wiphy.max_scan_ssids); |
@@ -572,6 +576,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
572 | CMD(del_pmksa, DEL_PMKSA); | 576 | CMD(del_pmksa, DEL_PMKSA); |
573 | CMD(flush_pmksa, FLUSH_PMKSA); | 577 | CMD(flush_pmksa, FLUSH_PMKSA); |
574 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | 578 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); |
579 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); | ||
575 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | 580 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { |
576 | i++; | 581 | i++; |
577 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | 582 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); |
@@ -684,6 +689,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
684 | u32 changed; | 689 | u32 changed; |
685 | u8 retry_short = 0, retry_long = 0; | 690 | u8 retry_short = 0, retry_long = 0; |
686 | u32 frag_threshold = 0, rts_threshold = 0; | 691 | u32 frag_threshold = 0, rts_threshold = 0; |
692 | u8 coverage_class = 0; | ||
687 | 693 | ||
688 | rtnl_lock(); | 694 | rtnl_lock(); |
689 | 695 | ||
@@ -806,9 +812,16 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
806 | changed |= WIPHY_PARAM_RTS_THRESHOLD; | 812 | changed |= WIPHY_PARAM_RTS_THRESHOLD; |
807 | } | 813 | } |
808 | 814 | ||
815 | if (info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]) { | ||
816 | coverage_class = nla_get_u8( | ||
817 | info->attrs[NL80211_ATTR_WIPHY_COVERAGE_CLASS]); | ||
818 | changed |= WIPHY_PARAM_COVERAGE_CLASS; | ||
819 | } | ||
820 | |||
809 | if (changed) { | 821 | if (changed) { |
810 | u8 old_retry_short, old_retry_long; | 822 | u8 old_retry_short, old_retry_long; |
811 | u32 old_frag_threshold, old_rts_threshold; | 823 | u32 old_frag_threshold, old_rts_threshold; |
824 | u8 old_coverage_class; | ||
812 | 825 | ||
813 | if (!rdev->ops->set_wiphy_params) { | 826 | if (!rdev->ops->set_wiphy_params) { |
814 | result = -EOPNOTSUPP; | 827 | result = -EOPNOTSUPP; |
@@ -819,6 +832,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
819 | old_retry_long = rdev->wiphy.retry_long; | 832 | old_retry_long = rdev->wiphy.retry_long; |
820 | old_frag_threshold = rdev->wiphy.frag_threshold; | 833 | old_frag_threshold = rdev->wiphy.frag_threshold; |
821 | old_rts_threshold = rdev->wiphy.rts_threshold; | 834 | old_rts_threshold = rdev->wiphy.rts_threshold; |
835 | old_coverage_class = rdev->wiphy.coverage_class; | ||
822 | 836 | ||
823 | if (changed & WIPHY_PARAM_RETRY_SHORT) | 837 | if (changed & WIPHY_PARAM_RETRY_SHORT) |
824 | rdev->wiphy.retry_short = retry_short; | 838 | rdev->wiphy.retry_short = retry_short; |
@@ -828,6 +842,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
828 | rdev->wiphy.frag_threshold = frag_threshold; | 842 | rdev->wiphy.frag_threshold = frag_threshold; |
829 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) | 843 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) |
830 | rdev->wiphy.rts_threshold = rts_threshold; | 844 | rdev->wiphy.rts_threshold = rts_threshold; |
845 | if (changed & WIPHY_PARAM_COVERAGE_CLASS) | ||
846 | rdev->wiphy.coverage_class = coverage_class; | ||
831 | 847 | ||
832 | result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); | 848 | result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); |
833 | if (result) { | 849 | if (result) { |
@@ -835,6 +851,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
835 | rdev->wiphy.retry_long = old_retry_long; | 851 | rdev->wiphy.retry_long = old_retry_long; |
836 | rdev->wiphy.frag_threshold = old_frag_threshold; | 852 | rdev->wiphy.frag_threshold = old_frag_threshold; |
837 | rdev->wiphy.rts_threshold = old_rts_threshold; | 853 | rdev->wiphy.rts_threshold = old_rts_threshold; |
854 | rdev->wiphy.coverage_class = old_coverage_class; | ||
838 | } | 855 | } |
839 | } | 856 | } |
840 | 857 | ||
@@ -3146,6 +3163,10 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
3146 | NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS, | 3163 | NLA_PUT(msg, NL80211_BSS_INFORMATION_ELEMENTS, |
3147 | res->len_information_elements, | 3164 | res->len_information_elements, |
3148 | res->information_elements); | 3165 | res->information_elements); |
3166 | if (res->beacon_ies && res->len_beacon_ies && | ||
3167 | res->beacon_ies != res->information_elements) | ||
3168 | NLA_PUT(msg, NL80211_BSS_BEACON_IES, | ||
3169 | res->len_beacon_ies, res->beacon_ies); | ||
3149 | if (res->tsf) | 3170 | if (res->tsf) |
3150 | NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf); | 3171 | NLA_PUT_U64(msg, NL80211_BSS_TSF, res->tsf); |
3151 | if (res->beacon_interval) | 3172 | if (res->beacon_interval) |
@@ -4423,6 +4444,109 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | |||
4423 | return err; | 4444 | return err; |
4424 | } | 4445 | } |
4425 | 4446 | ||
4447 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, | ||
4448 | u8 *rates, u8 rates_len) | ||
4449 | { | ||
4450 | u8 i; | ||
4451 | u32 mask = 0; | ||
4452 | |||
4453 | for (i = 0; i < rates_len; i++) { | ||
4454 | int rate = (rates[i] & 0x7f) * 5; | ||
4455 | int ridx; | ||
4456 | for (ridx = 0; ridx < sband->n_bitrates; ridx++) { | ||
4457 | struct ieee80211_rate *srate = | ||
4458 | &sband->bitrates[ridx]; | ||
4459 | if (rate == srate->bitrate) { | ||
4460 | mask |= 1 << ridx; | ||
4461 | break; | ||
4462 | } | ||
4463 | } | ||
4464 | if (ridx == sband->n_bitrates) | ||
4465 | return 0; /* rate not found */ | ||
4466 | } | ||
4467 | |||
4468 | return mask; | ||
4469 | } | ||
4470 | |||
4471 | static struct nla_policy | ||
4472 | nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] __read_mostly = { | ||
4473 | [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, | ||
4474 | .len = NL80211_MAX_SUPP_RATES }, | ||
4475 | }; | ||
4476 | |||
4477 | static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | ||
4478 | struct genl_info *info) | ||
4479 | { | ||
4480 | struct nlattr *tb[NL80211_TXRATE_MAX + 1]; | ||
4481 | struct cfg80211_registered_device *rdev; | ||
4482 | struct cfg80211_bitrate_mask mask; | ||
4483 | int err, rem, i; | ||
4484 | struct net_device *dev; | ||
4485 | struct nlattr *tx_rates; | ||
4486 | struct ieee80211_supported_band *sband; | ||
4487 | |||
4488 | if (info->attrs[NL80211_ATTR_TX_RATES] == NULL) | ||
4489 | return -EINVAL; | ||
4490 | |||
4491 | rtnl_lock(); | ||
4492 | |||
4493 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||
4494 | if (err) | ||
4495 | goto unlock_rtnl; | ||
4496 | |||
4497 | if (!rdev->ops->set_bitrate_mask) { | ||
4498 | err = -EOPNOTSUPP; | ||
4499 | goto unlock; | ||
4500 | } | ||
4501 | |||
4502 | memset(&mask, 0, sizeof(mask)); | ||
4503 | /* Default to all rates enabled */ | ||
4504 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { | ||
4505 | sband = rdev->wiphy.bands[i]; | ||
4506 | mask.control[i].legacy = | ||
4507 | sband ? (1 << sband->n_bitrates) - 1 : 0; | ||
4508 | } | ||
4509 | |||
4510 | /* | ||
4511 | * The nested attribute uses enum nl80211_band as the index. This maps | ||
4512 | * directly to the enum ieee80211_band values used in cfg80211. | ||
4513 | */ | ||
4514 | nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) | ||
4515 | { | ||
4516 | enum ieee80211_band band = nla_type(tx_rates); | ||
4517 | if (band < 0 || band >= IEEE80211_NUM_BANDS) { | ||
4518 | err = -EINVAL; | ||
4519 | goto unlock; | ||
4520 | } | ||
4521 | sband = rdev->wiphy.bands[band]; | ||
4522 | if (sband == NULL) { | ||
4523 | err = -EINVAL; | ||
4524 | goto unlock; | ||
4525 | } | ||
4526 | nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), | ||
4527 | nla_len(tx_rates), nl80211_txattr_policy); | ||
4528 | if (tb[NL80211_TXRATE_LEGACY]) { | ||
4529 | mask.control[band].legacy = rateset_to_mask( | ||
4530 | sband, | ||
4531 | nla_data(tb[NL80211_TXRATE_LEGACY]), | ||
4532 | nla_len(tb[NL80211_TXRATE_LEGACY])); | ||
4533 | if (mask.control[band].legacy == 0) { | ||
4534 | err = -EINVAL; | ||
4535 | goto unlock; | ||
4536 | } | ||
4537 | } | ||
4538 | } | ||
4539 | |||
4540 | err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask); | ||
4541 | |||
4542 | unlock: | ||
4543 | dev_put(dev); | ||
4544 | cfg80211_unlock_rdev(rdev); | ||
4545 | unlock_rtnl: | ||
4546 | rtnl_unlock(); | ||
4547 | return err; | ||
4548 | } | ||
4549 | |||
4426 | static struct genl_ops nl80211_ops[] = { | 4550 | static struct genl_ops nl80211_ops[] = { |
4427 | { | 4551 | { |
4428 | .cmd = NL80211_CMD_GET_WIPHY, | 4552 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -4697,6 +4821,12 @@ static struct genl_ops nl80211_ops[] = { | |||
4697 | .policy = nl80211_policy, | 4821 | .policy = nl80211_policy, |
4698 | .flags = GENL_ADMIN_PERM, | 4822 | .flags = GENL_ADMIN_PERM, |
4699 | }, | 4823 | }, |
4824 | { | ||
4825 | .cmd = NL80211_CMD_SET_TX_BITRATE_MASK, | ||
4826 | .doit = nl80211_set_tx_bitrate_mask, | ||
4827 | .policy = nl80211_policy, | ||
4828 | .flags = GENL_ADMIN_PERM, | ||
4829 | }, | ||
4700 | }; | 4830 | }; |
4701 | 4831 | ||
4702 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 4832 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 87ea60d84c3c..5f8071de7950 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -43,6 +43,15 @@ | |||
43 | #include "regdb.h" | 43 | #include "regdb.h" |
44 | #include "nl80211.h" | 44 | #include "nl80211.h" |
45 | 45 | ||
46 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
47 | #define REG_DBG_PRINT(format, args...) \ | ||
48 | do { \ | ||
49 | printk(KERN_DEBUG format , ## args); \ | ||
50 | } while (0) | ||
51 | #else | ||
52 | #define REG_DBG_PRINT(args...) | ||
53 | #endif | ||
54 | |||
46 | /* Receipt of information from last regulatory request */ | 55 | /* Receipt of information from last regulatory request */ |
47 | static struct regulatory_request *last_request; | 56 | static struct regulatory_request *last_request; |
48 | 57 | ||
@@ -476,12 +485,212 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, | |||
476 | } | 485 | } |
477 | 486 | ||
478 | /* | 487 | /* |
488 | * This is a work around for sanity checking ieee80211_channel_to_frequency()'s | ||
489 | * work. ieee80211_channel_to_frequency() can for example currently provide a | ||
490 | * 2 GHz channel when in fact a 5 GHz channel was desired. An example would be | ||
491 | * an AP providing channel 8 on a country IE triplet when it sent this on the | ||
492 | * 5 GHz band, that channel is designed to be channel 8 on 5 GHz, not a 2 GHz | ||
493 | * channel. | ||
494 | * | ||
495 | * This can be removed once ieee80211_channel_to_frequency() takes in a band. | ||
496 | */ | ||
497 | static bool chan_in_band(int chan, enum ieee80211_band band) | ||
498 | { | ||
499 | int center_freq = ieee80211_channel_to_frequency(chan); | ||
500 | |||
501 | switch (band) { | ||
502 | case IEEE80211_BAND_2GHZ: | ||
503 | if (center_freq <= 2484) | ||
504 | return true; | ||
505 | return false; | ||
506 | case IEEE80211_BAND_5GHZ: | ||
507 | if (center_freq >= 5005) | ||
508 | return true; | ||
509 | return false; | ||
510 | default: | ||
511 | return false; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | /* | ||
516 | * Some APs may send a country IE triplet for each channel they | ||
517 | * support and while this is completely overkill and silly we still | ||
518 | * need to support it. We avoid making a single rule for each channel | ||
519 | * though and to help us with this we use this helper to find the | ||
520 | * actual subband end channel. These type of country IE triplet | ||
521 | * scenerios are handled then, all yielding two regulaotry rules from | ||
522 | * parsing a country IE: | ||
523 | * | ||
524 | * [1] | ||
525 | * [2] | ||
526 | * [36] | ||
527 | * [40] | ||
528 | * | ||
529 | * [1] | ||
530 | * [2-4] | ||
531 | * [5-12] | ||
532 | * [36] | ||
533 | * [40-44] | ||
534 | * | ||
535 | * [1-4] | ||
536 | * [5-7] | ||
537 | * [36-44] | ||
538 | * [48-64] | ||
539 | * | ||
540 | * [36-36] | ||
541 | * [40-40] | ||
542 | * [44-44] | ||
543 | * [48-48] | ||
544 | * [52-52] | ||
545 | * [56-56] | ||
546 | * [60-60] | ||
547 | * [64-64] | ||
548 | * [100-100] | ||
549 | * [104-104] | ||
550 | * [108-108] | ||
551 | * [112-112] | ||
552 | * [116-116] | ||
553 | * [120-120] | ||
554 | * [124-124] | ||
555 | * [128-128] | ||
556 | * [132-132] | ||
557 | * [136-136] | ||
558 | * [140-140] | ||
559 | * | ||
560 | * Returns 0 if the IE has been found to be invalid in the middle | ||
561 | * somewhere. | ||
562 | */ | ||
563 | static int max_subband_chan(enum ieee80211_band band, | ||
564 | int orig_cur_chan, | ||
565 | int orig_end_channel, | ||
566 | s8 orig_max_power, | ||
567 | u8 **country_ie, | ||
568 | u8 *country_ie_len) | ||
569 | { | ||
570 | u8 *triplets_start = *country_ie; | ||
571 | u8 len_at_triplet = *country_ie_len; | ||
572 | int end_subband_chan = orig_end_channel; | ||
573 | |||
574 | /* | ||
575 | * We'll deal with padding for the caller unless | ||
576 | * its not immediate and we don't process any channels | ||
577 | */ | ||
578 | if (*country_ie_len == 1) { | ||
579 | *country_ie += 1; | ||
580 | *country_ie_len -= 1; | ||
581 | return orig_end_channel; | ||
582 | } | ||
583 | |||
584 | /* Move to the next triplet and then start search */ | ||
585 | *country_ie += 3; | ||
586 | *country_ie_len -= 3; | ||
587 | |||
588 | if (!chan_in_band(orig_cur_chan, band)) | ||
589 | return 0; | ||
590 | |||
591 | while (*country_ie_len >= 3) { | ||
592 | int end_channel = 0; | ||
593 | struct ieee80211_country_ie_triplet *triplet = | ||
594 | (struct ieee80211_country_ie_triplet *) *country_ie; | ||
595 | int cur_channel = 0, next_expected_chan; | ||
596 | |||
597 | /* means last triplet is completely unrelated to this one */ | ||
598 | if (triplet->ext.reg_extension_id >= | ||
599 | IEEE80211_COUNTRY_EXTENSION_ID) { | ||
600 | *country_ie -= 3; | ||
601 | *country_ie_len += 3; | ||
602 | break; | ||
603 | } | ||
604 | |||
605 | if (triplet->chans.first_channel == 0) { | ||
606 | *country_ie += 1; | ||
607 | *country_ie_len -= 1; | ||
608 | if (*country_ie_len != 0) | ||
609 | return 0; | ||
610 | break; | ||
611 | } | ||
612 | |||
613 | if (triplet->chans.num_channels == 0) | ||
614 | return 0; | ||
615 | |||
616 | /* Monitonically increasing channel order */ | ||
617 | if (triplet->chans.first_channel <= end_subband_chan) | ||
618 | return 0; | ||
619 | |||
620 | if (!chan_in_band(triplet->chans.first_channel, band)) | ||
621 | return 0; | ||
622 | |||
623 | /* 2 GHz */ | ||
624 | if (triplet->chans.first_channel <= 14) { | ||
625 | end_channel = triplet->chans.first_channel + | ||
626 | triplet->chans.num_channels - 1; | ||
627 | } | ||
628 | else { | ||
629 | end_channel = triplet->chans.first_channel + | ||
630 | (4 * (triplet->chans.num_channels - 1)); | ||
631 | } | ||
632 | |||
633 | if (!chan_in_band(end_channel, band)) | ||
634 | return 0; | ||
635 | |||
636 | if (orig_max_power != triplet->chans.max_power) { | ||
637 | *country_ie -= 3; | ||
638 | *country_ie_len += 3; | ||
639 | break; | ||
640 | } | ||
641 | |||
642 | cur_channel = triplet->chans.first_channel; | ||
643 | |||
644 | /* The key is finding the right next expected channel */ | ||
645 | if (band == IEEE80211_BAND_2GHZ) | ||
646 | next_expected_chan = end_subband_chan + 1; | ||
647 | else | ||
648 | next_expected_chan = end_subband_chan + 4; | ||
649 | |||
650 | if (cur_channel != next_expected_chan) { | ||
651 | *country_ie -= 3; | ||
652 | *country_ie_len += 3; | ||
653 | break; | ||
654 | } | ||
655 | |||
656 | end_subband_chan = end_channel; | ||
657 | |||
658 | /* Move to the next one */ | ||
659 | *country_ie += 3; | ||
660 | *country_ie_len -= 3; | ||
661 | |||
662 | /* | ||
663 | * Padding needs to be dealt with if we processed | ||
664 | * some channels. | ||
665 | */ | ||
666 | if (*country_ie_len == 1) { | ||
667 | *country_ie += 1; | ||
668 | *country_ie_len -= 1; | ||
669 | break; | ||
670 | } | ||
671 | |||
672 | /* If seen, the IE is invalid */ | ||
673 | if (*country_ie_len == 2) | ||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | if (end_subband_chan == orig_end_channel) { | ||
678 | *country_ie = triplets_start; | ||
679 | *country_ie_len = len_at_triplet; | ||
680 | return orig_end_channel; | ||
681 | } | ||
682 | |||
683 | return end_subband_chan; | ||
684 | } | ||
685 | |||
686 | /* | ||
479 | * Converts a country IE to a regulatory domain. A regulatory domain | 687 | * Converts a country IE to a regulatory domain. A regulatory domain |
480 | * structure has a lot of information which the IE doesn't yet have, | 688 | * structure has a lot of information which the IE doesn't yet have, |
481 | * so for the other values we use upper max values as we will intersect | 689 | * so for the other values we use upper max values as we will intersect |
482 | * with our userspace regulatory agent to get lower bounds. | 690 | * with our userspace regulatory agent to get lower bounds. |
483 | */ | 691 | */ |
484 | static struct ieee80211_regdomain *country_ie_2_rd( | 692 | static struct ieee80211_regdomain *country_ie_2_rd( |
693 | enum ieee80211_band band, | ||
485 | u8 *country_ie, | 694 | u8 *country_ie, |
486 | u8 country_ie_len, | 695 | u8 country_ie_len, |
487 | u32 *checksum) | 696 | u32 *checksum) |
@@ -543,10 +752,29 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
543 | continue; | 752 | continue; |
544 | } | 753 | } |
545 | 754 | ||
755 | /* | ||
756 | * APs can add padding to make length divisible | ||
757 | * by two, required by the spec. | ||
758 | */ | ||
759 | if (triplet->chans.first_channel == 0) { | ||
760 | country_ie++; | ||
761 | country_ie_len--; | ||
762 | /* This is expected to be at the very end only */ | ||
763 | if (country_ie_len != 0) | ||
764 | return NULL; | ||
765 | break; | ||
766 | } | ||
767 | |||
768 | if (triplet->chans.num_channels == 0) | ||
769 | return NULL; | ||
770 | |||
771 | if (!chan_in_band(triplet->chans.first_channel, band)) | ||
772 | return NULL; | ||
773 | |||
546 | /* 2 GHz */ | 774 | /* 2 GHz */ |
547 | if (triplet->chans.first_channel <= 14) | 775 | if (band == IEEE80211_BAND_2GHZ) |
548 | end_channel = triplet->chans.first_channel + | 776 | end_channel = triplet->chans.first_channel + |
549 | triplet->chans.num_channels; | 777 | triplet->chans.num_channels - 1; |
550 | else | 778 | else |
551 | /* | 779 | /* |
552 | * 5 GHz -- For example in country IEs if the first | 780 | * 5 GHz -- For example in country IEs if the first |
@@ -561,6 +789,24 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
561 | (4 * (triplet->chans.num_channels - 1)); | 789 | (4 * (triplet->chans.num_channels - 1)); |
562 | 790 | ||
563 | cur_channel = triplet->chans.first_channel; | 791 | cur_channel = triplet->chans.first_channel; |
792 | |||
793 | /* | ||
794 | * Enhancement for APs that send a triplet for every channel | ||
795 | * or for whatever reason sends triplets with multiple channels | ||
796 | * separated when in fact they should be together. | ||
797 | */ | ||
798 | end_channel = max_subband_chan(band, | ||
799 | cur_channel, | ||
800 | end_channel, | ||
801 | triplet->chans.max_power, | ||
802 | &country_ie, | ||
803 | &country_ie_len); | ||
804 | if (!end_channel) | ||
805 | return NULL; | ||
806 | |||
807 | if (!chan_in_band(end_channel, band)) | ||
808 | return NULL; | ||
809 | |||
564 | cur_sub_max_channel = end_channel; | 810 | cur_sub_max_channel = end_channel; |
565 | 811 | ||
566 | /* Basic sanity check */ | 812 | /* Basic sanity check */ |
@@ -591,10 +837,13 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
591 | 837 | ||
592 | last_sub_max_channel = cur_sub_max_channel; | 838 | last_sub_max_channel = cur_sub_max_channel; |
593 | 839 | ||
594 | country_ie += 3; | ||
595 | country_ie_len -= 3; | ||
596 | num_rules++; | 840 | num_rules++; |
597 | 841 | ||
842 | if (country_ie_len >= 3) { | ||
843 | country_ie += 3; | ||
844 | country_ie_len -= 3; | ||
845 | } | ||
846 | |||
598 | /* | 847 | /* |
599 | * Note: this is not a IEEE requirement but | 848 | * Note: this is not a IEEE requirement but |
600 | * simply a memory requirement | 849 | * simply a memory requirement |
@@ -637,6 +886,12 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
637 | continue; | 886 | continue; |
638 | } | 887 | } |
639 | 888 | ||
889 | if (triplet->chans.first_channel == 0) { | ||
890 | country_ie++; | ||
891 | country_ie_len--; | ||
892 | break; | ||
893 | } | ||
894 | |||
640 | reg_rule = &rd->reg_rules[i]; | 895 | reg_rule = &rd->reg_rules[i]; |
641 | freq_range = ®_rule->freq_range; | 896 | freq_range = ®_rule->freq_range; |
642 | power_rule = ®_rule->power_rule; | 897 | power_rule = ®_rule->power_rule; |
@@ -644,13 +899,20 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
644 | reg_rule->flags = flags; | 899 | reg_rule->flags = flags; |
645 | 900 | ||
646 | /* 2 GHz */ | 901 | /* 2 GHz */ |
647 | if (triplet->chans.first_channel <= 14) | 902 | if (band == IEEE80211_BAND_2GHZ) |
648 | end_channel = triplet->chans.first_channel + | 903 | end_channel = triplet->chans.first_channel + |
649 | triplet->chans.num_channels; | 904 | triplet->chans.num_channels -1; |
650 | else | 905 | else |
651 | end_channel = triplet->chans.first_channel + | 906 | end_channel = triplet->chans.first_channel + |
652 | (4 * (triplet->chans.num_channels - 1)); | 907 | (4 * (triplet->chans.num_channels - 1)); |
653 | 908 | ||
909 | end_channel = max_subband_chan(band, | ||
910 | triplet->chans.first_channel, | ||
911 | end_channel, | ||
912 | triplet->chans.max_power, | ||
913 | &country_ie, | ||
914 | &country_ie_len); | ||
915 | |||
654 | /* | 916 | /* |
655 | * The +10 is since the regulatory domain expects | 917 | * The +10 is since the regulatory domain expects |
656 | * the actual band edge, not the center of freq for | 918 | * the actual band edge, not the center of freq for |
@@ -671,12 +933,15 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
671 | */ | 933 | */ |
672 | freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); | 934 | freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); |
673 | power_rule->max_antenna_gain = DBI_TO_MBI(100); | 935 | power_rule->max_antenna_gain = DBI_TO_MBI(100); |
674 | power_rule->max_eirp = DBM_TO_MBM(100); | 936 | power_rule->max_eirp = DBM_TO_MBM(triplet->chans.max_power); |
675 | 937 | ||
676 | country_ie += 3; | ||
677 | country_ie_len -= 3; | ||
678 | i++; | 938 | i++; |
679 | 939 | ||
940 | if (country_ie_len >= 3) { | ||
941 | country_ie += 3; | ||
942 | country_ie_len -= 3; | ||
943 | } | ||
944 | |||
680 | BUG_ON(i > NL80211_MAX_SUPP_REG_RULES); | 945 | BUG_ON(i > NL80211_MAX_SUPP_REG_RULES); |
681 | } | 946 | } |
682 | 947 | ||
@@ -972,25 +1237,21 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
972 | if (r == -ERANGE && | 1237 | if (r == -ERANGE && |
973 | last_request->initiator == | 1238 | last_request->initiator == |
974 | NL80211_REGDOM_SET_BY_COUNTRY_IE) { | 1239 | NL80211_REGDOM_SET_BY_COUNTRY_IE) { |
975 | #ifdef CONFIG_CFG80211_REG_DEBUG | 1240 | REG_DBG_PRINT("cfg80211: Leaving channel %d MHz " |
976 | printk(KERN_DEBUG "cfg80211: Leaving channel %d MHz " | ||
977 | "intact on %s - no rule found in band on " | 1241 | "intact on %s - no rule found in band on " |
978 | "Country IE\n", | 1242 | "Country IE\n", |
979 | chan->center_freq, wiphy_name(wiphy)); | 1243 | chan->center_freq, wiphy_name(wiphy)); |
980 | #endif | ||
981 | } else { | 1244 | } else { |
982 | /* | 1245 | /* |
983 | * In this case we know the country IE has at least one reg rule | 1246 | * In this case we know the country IE has at least one reg rule |
984 | * for the band so we respect its band definitions | 1247 | * for the band so we respect its band definitions |
985 | */ | 1248 | */ |
986 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
987 | if (last_request->initiator == | 1249 | if (last_request->initiator == |
988 | NL80211_REGDOM_SET_BY_COUNTRY_IE) | 1250 | NL80211_REGDOM_SET_BY_COUNTRY_IE) |
989 | printk(KERN_DEBUG "cfg80211: Disabling " | 1251 | REG_DBG_PRINT("cfg80211: Disabling " |
990 | "channel %d MHz on %s due to " | 1252 | "channel %d MHz on %s due to " |
991 | "Country IE\n", | 1253 | "Country IE\n", |
992 | chan->center_freq, wiphy_name(wiphy)); | 1254 | chan->center_freq, wiphy_name(wiphy)); |
993 | #endif | ||
994 | flags |= IEEE80211_CHAN_DISABLED; | 1255 | flags |= IEEE80211_CHAN_DISABLED; |
995 | chan->flags = flags; | 1256 | chan->flags = flags; |
996 | } | 1257 | } |
@@ -1685,7 +1946,7 @@ int regulatory_hint_user(const char *alpha2) | |||
1685 | request->wiphy_idx = WIPHY_IDX_STALE; | 1946 | request->wiphy_idx = WIPHY_IDX_STALE; |
1686 | request->alpha2[0] = alpha2[0]; | 1947 | request->alpha2[0] = alpha2[0]; |
1687 | request->alpha2[1] = alpha2[1]; | 1948 | request->alpha2[1] = alpha2[1]; |
1688 | request->initiator = NL80211_REGDOM_SET_BY_USER, | 1949 | request->initiator = NL80211_REGDOM_SET_BY_USER; |
1689 | 1950 | ||
1690 | queue_regulatory_request(request); | 1951 | queue_regulatory_request(request); |
1691 | 1952 | ||
@@ -1753,8 +2014,9 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy, | |||
1753 | * therefore cannot iterate over the rdev list here. | 2014 | * therefore cannot iterate over the rdev list here. |
1754 | */ | 2015 | */ |
1755 | void regulatory_hint_11d(struct wiphy *wiphy, | 2016 | void regulatory_hint_11d(struct wiphy *wiphy, |
1756 | u8 *country_ie, | 2017 | enum ieee80211_band band, |
1757 | u8 country_ie_len) | 2018 | u8 *country_ie, |
2019 | u8 country_ie_len) | ||
1758 | { | 2020 | { |
1759 | struct ieee80211_regdomain *rd = NULL; | 2021 | struct ieee80211_regdomain *rd = NULL; |
1760 | char alpha2[2]; | 2022 | char alpha2[2]; |
@@ -1800,9 +2062,11 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1800 | wiphy_idx_valid(last_request->wiphy_idx))) | 2062 | wiphy_idx_valid(last_request->wiphy_idx))) |
1801 | goto out; | 2063 | goto out; |
1802 | 2064 | ||
1803 | rd = country_ie_2_rd(country_ie, country_ie_len, &checksum); | 2065 | rd = country_ie_2_rd(band, country_ie, country_ie_len, &checksum); |
1804 | if (!rd) | 2066 | if (!rd) { |
2067 | REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n"); | ||
1805 | goto out; | 2068 | goto out; |
2069 | } | ||
1806 | 2070 | ||
1807 | /* | 2071 | /* |
1808 | * This will not happen right now but we leave it here for the | 2072 | * This will not happen right now but we leave it here for the |
@@ -1870,13 +2134,12 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, | |||
1870 | if (!reg_beacon) | 2134 | if (!reg_beacon) |
1871 | return -ENOMEM; | 2135 | return -ENOMEM; |
1872 | 2136 | ||
1873 | #ifdef CONFIG_CFG80211_REG_DEBUG | 2137 | REG_DBG_PRINT("cfg80211: Found new beacon on " |
1874 | printk(KERN_DEBUG "cfg80211: Found new beacon on " | 2138 | "frequency: %d MHz (Ch %d) on %s\n", |
1875 | "frequency: %d MHz (Ch %d) on %s\n", | 2139 | beacon_chan->center_freq, |
1876 | beacon_chan->center_freq, | 2140 | ieee80211_frequency_to_channel(beacon_chan->center_freq), |
1877 | ieee80211_frequency_to_channel(beacon_chan->center_freq), | 2141 | wiphy_name(wiphy)); |
1878 | wiphy_name(wiphy)); | 2142 | |
1879 | #endif | ||
1880 | memcpy(®_beacon->chan, beacon_chan, | 2143 | memcpy(®_beacon->chan, beacon_chan, |
1881 | sizeof(struct ieee80211_channel)); | 2144 | sizeof(struct ieee80211_channel)); |
1882 | 2145 | ||
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 3362c7c069b2..3018508226ab 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -41,14 +41,25 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, | |||
41 | * regulatory_hint_11d - hints a country IE as a regulatory domain | 41 | * regulatory_hint_11d - hints a country IE as a regulatory domain |
42 | * @wiphy: the wireless device giving the hint (used only for reporting | 42 | * @wiphy: the wireless device giving the hint (used only for reporting |
43 | * conflicts) | 43 | * conflicts) |
44 | * @band: the band on which the country IE was received on. This determines | ||
45 | * the band we'll process the country IE channel triplets for. | ||
44 | * @country_ie: pointer to the country IE | 46 | * @country_ie: pointer to the country IE |
45 | * @country_ie_len: length of the country IE | 47 | * @country_ie_len: length of the country IE |
46 | * | 48 | * |
47 | * We will intersect the rd with the what CRDA tells us should apply | 49 | * We will intersect the rd with the what CRDA tells us should apply |
48 | * for the alpha2 this country IE belongs to, this prevents APs from | 50 | * for the alpha2 this country IE belongs to, this prevents APs from |
49 | * sending us incorrect or outdated information against a country. | 51 | * sending us incorrect or outdated information against a country. |
52 | * | ||
53 | * The AP is expected to provide Country IE channel triplets for the | ||
54 | * band it is on. It is technically possible for APs to send channel | ||
55 | * country IE triplets even for channels outside of the band they are | ||
56 | * in but for that they would have to use the regulatory extension | ||
57 | * in combination with a triplet but this behaviour is currently | ||
58 | * not observed. For this reason if a triplet is seen with channel | ||
59 | * information for a band the BSS is not present in it will be ignored. | ||
50 | */ | 60 | */ |
51 | void regulatory_hint_11d(struct wiphy *wiphy, | 61 | void regulatory_hint_11d(struct wiphy *wiphy, |
62 | enum ieee80211_band band, | ||
52 | u8 *country_ie, | 63 | u8 *country_ie, |
53 | u8 country_ie_len); | 64 | u8 country_ie_len); |
54 | 65 | ||
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0c2cbbebca95..06b0231ee5e3 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -100,8 +100,10 @@ static void bss_release(struct kref *ref) | |||
100 | if (bss->pub.free_priv) | 100 | if (bss->pub.free_priv) |
101 | bss->pub.free_priv(&bss->pub); | 101 | bss->pub.free_priv(&bss->pub); |
102 | 102 | ||
103 | if (bss->ies_allocated) | 103 | if (bss->beacon_ies_allocated) |
104 | kfree(bss->pub.information_elements); | 104 | kfree(bss->pub.beacon_ies); |
105 | if (bss->proberesp_ies_allocated) | ||
106 | kfree(bss->pub.proberesp_ies); | ||
105 | 107 | ||
106 | BUG_ON(atomic_read(&bss->hold)); | 108 | BUG_ON(atomic_read(&bss->hold)); |
107 | 109 | ||
@@ -375,8 +377,7 @@ rb_find_bss(struct cfg80211_registered_device *dev, | |||
375 | 377 | ||
376 | static struct cfg80211_internal_bss * | 378 | static struct cfg80211_internal_bss * |
377 | cfg80211_bss_update(struct cfg80211_registered_device *dev, | 379 | cfg80211_bss_update(struct cfg80211_registered_device *dev, |
378 | struct cfg80211_internal_bss *res, | 380 | struct cfg80211_internal_bss *res) |
379 | bool overwrite) | ||
380 | { | 381 | { |
381 | struct cfg80211_internal_bss *found = NULL; | 382 | struct cfg80211_internal_bss *found = NULL; |
382 | const u8 *meshid, *meshcfg; | 383 | const u8 *meshid, *meshcfg; |
@@ -418,28 +419,64 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
418 | found->pub.capability = res->pub.capability; | 419 | found->pub.capability = res->pub.capability; |
419 | found->ts = res->ts; | 420 | found->ts = res->ts; |
420 | 421 | ||
421 | /* overwrite IEs */ | 422 | /* Update IEs */ |
422 | if (overwrite) { | 423 | if (res->pub.proberesp_ies) { |
423 | size_t used = dev->wiphy.bss_priv_size + sizeof(*res); | 424 | size_t used = dev->wiphy.bss_priv_size + sizeof(*res); |
424 | size_t ielen = res->pub.len_information_elements; | 425 | size_t ielen = res->pub.len_proberesp_ies; |
426 | |||
427 | if (found->pub.proberesp_ies && | ||
428 | !found->proberesp_ies_allocated && | ||
429 | ksize(found) >= used + ielen) { | ||
430 | memcpy(found->pub.proberesp_ies, | ||
431 | res->pub.proberesp_ies, ielen); | ||
432 | found->pub.len_proberesp_ies = ielen; | ||
433 | } else { | ||
434 | u8 *ies = found->pub.proberesp_ies; | ||
435 | |||
436 | if (found->proberesp_ies_allocated) | ||
437 | ies = krealloc(ies, ielen, GFP_ATOMIC); | ||
438 | else | ||
439 | ies = kmalloc(ielen, GFP_ATOMIC); | ||
440 | |||
441 | if (ies) { | ||
442 | memcpy(ies, res->pub.proberesp_ies, | ||
443 | ielen); | ||
444 | found->proberesp_ies_allocated = true; | ||
445 | found->pub.proberesp_ies = ies; | ||
446 | found->pub.len_proberesp_ies = ielen; | ||
447 | } | ||
448 | } | ||
425 | 449 | ||
426 | if (!found->ies_allocated && ksize(found) >= used + ielen) { | 450 | /* Override possible earlier Beacon frame IEs */ |
427 | memcpy(found->pub.information_elements, | 451 | found->pub.information_elements = |
428 | res->pub.information_elements, ielen); | 452 | found->pub.proberesp_ies; |
429 | found->pub.len_information_elements = ielen; | 453 | found->pub.len_information_elements = |
454 | found->pub.len_proberesp_ies; | ||
455 | } | ||
456 | if (res->pub.beacon_ies) { | ||
457 | size_t used = dev->wiphy.bss_priv_size + sizeof(*res); | ||
458 | size_t ielen = res->pub.len_beacon_ies; | ||
459 | |||
460 | if (found->pub.beacon_ies && | ||
461 | !found->beacon_ies_allocated && | ||
462 | ksize(found) >= used + ielen) { | ||
463 | memcpy(found->pub.beacon_ies, | ||
464 | res->pub.beacon_ies, ielen); | ||
465 | found->pub.len_beacon_ies = ielen; | ||
430 | } else { | 466 | } else { |
431 | u8 *ies = found->pub.information_elements; | 467 | u8 *ies = found->pub.beacon_ies; |
432 | 468 | ||
433 | if (found->ies_allocated) | 469 | if (found->beacon_ies_allocated) |
434 | ies = krealloc(ies, ielen, GFP_ATOMIC); | 470 | ies = krealloc(ies, ielen, GFP_ATOMIC); |
435 | else | 471 | else |
436 | ies = kmalloc(ielen, GFP_ATOMIC); | 472 | ies = kmalloc(ielen, GFP_ATOMIC); |
437 | 473 | ||
438 | if (ies) { | 474 | if (ies) { |
439 | memcpy(ies, res->pub.information_elements, ielen); | 475 | memcpy(ies, res->pub.beacon_ies, |
440 | found->ies_allocated = true; | 476 | ielen); |
441 | found->pub.information_elements = ies; | 477 | found->beacon_ies_allocated = true; |
442 | found->pub.len_information_elements = ielen; | 478 | found->pub.beacon_ies = ies; |
479 | found->pub.len_beacon_ies = ielen; | ||
443 | } | 480 | } |
444 | } | 481 | } |
445 | } | 482 | } |
@@ -489,14 +526,26 @@ cfg80211_inform_bss(struct wiphy *wiphy, | |||
489 | res->pub.tsf = timestamp; | 526 | res->pub.tsf = timestamp; |
490 | res->pub.beacon_interval = beacon_interval; | 527 | res->pub.beacon_interval = beacon_interval; |
491 | res->pub.capability = capability; | 528 | res->pub.capability = capability; |
492 | /* point to after the private area */ | 529 | /* |
493 | res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz; | 530 | * Since we do not know here whether the IEs are from a Beacon or Probe |
494 | memcpy(res->pub.information_elements, ie, ielen); | 531 | * Response frame, we need to pick one of the options and only use it |
495 | res->pub.len_information_elements = ielen; | 532 | * with the driver that does not provide the full Beacon/Probe Response |
533 | * frame. Use Beacon frame pointer to avoid indicating that this should | ||
534 | * override the information_elements pointer should we have received an | ||
535 | * earlier indication of Probe Response data. | ||
536 | * | ||
537 | * The initial buffer for the IEs is allocated with the BSS entry and | ||
538 | * is located after the private area. | ||
539 | */ | ||
540 | res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz; | ||
541 | memcpy(res->pub.beacon_ies, ie, ielen); | ||
542 | res->pub.len_beacon_ies = ielen; | ||
543 | res->pub.information_elements = res->pub.beacon_ies; | ||
544 | res->pub.len_information_elements = res->pub.len_beacon_ies; | ||
496 | 545 | ||
497 | kref_init(&res->ref); | 546 | kref_init(&res->ref); |
498 | 547 | ||
499 | res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, 0); | 548 | res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); |
500 | if (!res) | 549 | if (!res) |
501 | return NULL; | 550 | return NULL; |
502 | 551 | ||
@@ -517,7 +566,6 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
517 | struct cfg80211_internal_bss *res; | 566 | struct cfg80211_internal_bss *res; |
518 | size_t ielen = len - offsetof(struct ieee80211_mgmt, | 567 | size_t ielen = len - offsetof(struct ieee80211_mgmt, |
519 | u.probe_resp.variable); | 568 | u.probe_resp.variable); |
520 | bool overwrite; | ||
521 | size_t privsz = wiphy->bss_priv_size; | 569 | size_t privsz = wiphy->bss_priv_size; |
522 | 570 | ||
523 | if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC && | 571 | if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC && |
@@ -538,16 +586,28 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
538 | res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); | 586 | res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); |
539 | res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); | 587 | res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); |
540 | res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); | 588 | res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); |
541 | /* point to after the private area */ | 589 | /* |
542 | res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz; | 590 | * The initial buffer for the IEs is allocated with the BSS entry and |
543 | memcpy(res->pub.information_elements, mgmt->u.probe_resp.variable, ielen); | 591 | * is located after the private area. |
544 | res->pub.len_information_elements = ielen; | 592 | */ |
593 | if (ieee80211_is_probe_resp(mgmt->frame_control)) { | ||
594 | res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz; | ||
595 | memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable, | ||
596 | ielen); | ||
597 | res->pub.len_proberesp_ies = ielen; | ||
598 | res->pub.information_elements = res->pub.proberesp_ies; | ||
599 | res->pub.len_information_elements = res->pub.len_proberesp_ies; | ||
600 | } else { | ||
601 | res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz; | ||
602 | memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen); | ||
603 | res->pub.len_beacon_ies = ielen; | ||
604 | res->pub.information_elements = res->pub.beacon_ies; | ||
605 | res->pub.len_information_elements = res->pub.len_beacon_ies; | ||
606 | } | ||
545 | 607 | ||
546 | kref_init(&res->ref); | 608 | kref_init(&res->ref); |
547 | 609 | ||
548 | overwrite = ieee80211_is_probe_resp(mgmt->frame_control); | 610 | res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); |
549 | |||
550 | res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, overwrite); | ||
551 | if (!res) | 611 | if (!res) |
552 | return NULL; | 612 | return NULL; |
553 | 613 | ||
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 2333d78187e4..2ce5e1609a3d 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -454,6 +454,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
454 | * - and country_ie[1] which is the IE length | 454 | * - and country_ie[1] which is the IE length |
455 | */ | 455 | */ |
456 | regulatory_hint_11d(wdev->wiphy, | 456 | regulatory_hint_11d(wdev->wiphy, |
457 | bss->channel->band, | ||
457 | country_ie + 2, | 458 | country_ie + 2, |
458 | country_ie[1]); | 459 | country_ie[1]); |
459 | } | 460 | } |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 4198243a3dff..966d2f01beac 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -1204,21 +1204,47 @@ int cfg80211_wext_siwrate(struct net_device *dev, | |||
1204 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 1204 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
1205 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 1205 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
1206 | struct cfg80211_bitrate_mask mask; | 1206 | struct cfg80211_bitrate_mask mask; |
1207 | u32 fixed, maxrate; | ||
1208 | struct ieee80211_supported_band *sband; | ||
1209 | int band, ridx; | ||
1210 | bool match = false; | ||
1207 | 1211 | ||
1208 | if (!rdev->ops->set_bitrate_mask) | 1212 | if (!rdev->ops->set_bitrate_mask) |
1209 | return -EOPNOTSUPP; | 1213 | return -EOPNOTSUPP; |
1210 | 1214 | ||
1211 | mask.fixed = 0; | 1215 | memset(&mask, 0, sizeof(mask)); |
1212 | mask.maxrate = 0; | 1216 | fixed = 0; |
1217 | maxrate = 0; | ||
1213 | 1218 | ||
1214 | if (rate->value < 0) { | 1219 | if (rate->value < 0) { |
1215 | /* nothing */ | 1220 | /* nothing */ |
1216 | } else if (rate->fixed) { | 1221 | } else if (rate->fixed) { |
1217 | mask.fixed = rate->value / 1000; /* kbps */ | 1222 | fixed = rate->value / 100000; |
1218 | } else { | 1223 | } else { |
1219 | mask.maxrate = rate->value / 1000; /* kbps */ | 1224 | maxrate = rate->value / 100000; |
1225 | } | ||
1226 | |||
1227 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
1228 | sband = wdev->wiphy->bands[band]; | ||
1229 | if (sband == NULL) | ||
1230 | continue; | ||
1231 | for (ridx = 0; ridx < sband->n_bitrates; ridx++) { | ||
1232 | struct ieee80211_rate *srate = &sband->bitrates[ridx]; | ||
1233 | if (fixed == srate->bitrate) { | ||
1234 | mask.control[band].legacy = 1 << ridx; | ||
1235 | match = true; | ||
1236 | break; | ||
1237 | } | ||
1238 | if (srate->bitrate <= maxrate) { | ||
1239 | mask.control[band].legacy |= 1 << ridx; | ||
1240 | match = true; | ||
1241 | } | ||
1242 | } | ||
1220 | } | 1243 | } |
1221 | 1244 | ||
1245 | if (!match) | ||
1246 | return -EINVAL; | ||
1247 | |||
1222 | return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); | 1248 | return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); |
1223 | } | 1249 | } |
1224 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate); | 1250 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate); |