diff options
| author | Chris Metcalf <cmetcalf@tilera.com> | 2010-08-06 10:37:02 -0400 |
|---|---|---|
| committer | Chris Metcalf <cmetcalf@tilera.com> | 2010-08-06 10:37:02 -0400 |
| commit | ab11b487402f97975f3ac1eeea09c82f4431481e (patch) | |
| tree | 86337c5cbbd2b0c4bd07c0847a1dc7de3d898147 /net/wireless | |
| parent | 1c689cbcf2c2b7a35cd237abddd9206bb1b6fee1 (diff) | |
| parent | fc1caf6eafb30ea185720e29f7f5eccca61ecd60 (diff) | |
Merge branch 'master' into for-linus
Diffstat (limited to 'net/wireless')
| -rw-r--r-- | net/wireless/chan.c | 5 | ||||
| -rw-r--r-- | net/wireless/core.c | 65 | ||||
| -rw-r--r-- | net/wireless/core.h | 1 | ||||
| -rw-r--r-- | net/wireless/genregdb.awk | 1 | ||||
| -rw-r--r-- | net/wireless/ibss.c | 4 | ||||
| -rw-r--r-- | net/wireless/lib80211_crypt_ccmp.c | 1 | ||||
| -rw-r--r-- | net/wireless/lib80211_crypt_tkip.c | 3 | ||||
| -rw-r--r-- | net/wireless/lib80211_crypt_wep.c | 1 | ||||
| -rw-r--r-- | net/wireless/mlme.c | 16 | ||||
| -rw-r--r-- | net/wireless/nl80211.c | 93 | ||||
| -rw-r--r-- | net/wireless/reg.c | 668 | ||||
| -rw-r--r-- | net/wireless/reg.h | 2 | ||||
| -rw-r--r-- | net/wireless/scan.c | 5 | ||||
| -rw-r--r-- | net/wireless/sme.c | 2 | ||||
| -rw-r--r-- | net/wireless/util.c | 4 | ||||
| -rw-r--r-- | net/wireless/wext-compat.c | 11 |
16 files changed, 191 insertions, 691 deletions
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index b01a6f6397d7..d0c92dddb26b 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
| @@ -35,8 +35,9 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev, | |||
| 35 | if (!ht_cap->ht_supported) | 35 | if (!ht_cap->ht_supported) |
| 36 | return NULL; | 36 | return NULL; |
| 37 | 37 | ||
| 38 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | 38 | if (channel_type != NL80211_CHAN_HT20 && |
| 39 | ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) | 39 | (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || |
| 40 | ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) | ||
| 40 | return NULL; | 41 | return NULL; |
| 41 | } | 42 | } |
| 42 | 43 | ||
diff --git a/net/wireless/core.c b/net/wireless/core.c index 37d0e0ab4432..541e2fff5e9c 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
| @@ -472,24 +472,22 @@ int wiphy_register(struct wiphy *wiphy) | |||
| 472 | /* check and set up bitrates */ | 472 | /* check and set up bitrates */ |
| 473 | ieee80211_set_bitrate_flags(wiphy); | 473 | ieee80211_set_bitrate_flags(wiphy); |
| 474 | 474 | ||
| 475 | mutex_lock(&cfg80211_mutex); | ||
| 476 | |||
| 475 | res = device_add(&rdev->wiphy.dev); | 477 | res = device_add(&rdev->wiphy.dev); |
| 476 | if (res) | 478 | if (res) |
| 477 | return res; | 479 | goto out_unlock; |
| 478 | 480 | ||
| 479 | res = rfkill_register(rdev->rfkill); | 481 | res = rfkill_register(rdev->rfkill); |
| 480 | if (res) | 482 | if (res) |
| 481 | goto out_rm_dev; | 483 | goto out_rm_dev; |
| 482 | 484 | ||
| 483 | mutex_lock(&cfg80211_mutex); | ||
| 484 | |||
| 485 | /* set up regulatory info */ | 485 | /* set up regulatory info */ |
| 486 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); | 486 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); |
| 487 | 487 | ||
| 488 | list_add_rcu(&rdev->list, &cfg80211_rdev_list); | 488 | list_add_rcu(&rdev->list, &cfg80211_rdev_list); |
| 489 | cfg80211_rdev_list_generation++; | 489 | cfg80211_rdev_list_generation++; |
| 490 | 490 | ||
| 491 | mutex_unlock(&cfg80211_mutex); | ||
| 492 | |||
| 493 | /* add to debugfs */ | 491 | /* add to debugfs */ |
| 494 | rdev->wiphy.debugfsdir = | 492 | rdev->wiphy.debugfsdir = |
| 495 | debugfs_create_dir(wiphy_name(&rdev->wiphy), | 493 | debugfs_create_dir(wiphy_name(&rdev->wiphy), |
| @@ -509,11 +507,15 @@ int wiphy_register(struct wiphy *wiphy) | |||
| 509 | } | 507 | } |
| 510 | 508 | ||
| 511 | cfg80211_debugfs_rdev_add(rdev); | 509 | cfg80211_debugfs_rdev_add(rdev); |
| 510 | mutex_unlock(&cfg80211_mutex); | ||
| 512 | 511 | ||
| 513 | return 0; | 512 | return 0; |
| 514 | 513 | ||
| 515 | out_rm_dev: | 514 | out_rm_dev: |
| 516 | device_del(&rdev->wiphy.dev); | 515 | device_del(&rdev->wiphy.dev); |
| 516 | |||
| 517 | out_unlock: | ||
| 518 | mutex_unlock(&cfg80211_mutex); | ||
| 517 | return res; | 519 | return res; |
| 518 | } | 520 | } |
| 519 | EXPORT_SYMBOL(wiphy_register); | 521 | EXPORT_SYMBOL(wiphy_register); |
| @@ -894,7 +896,7 @@ out_fail_pernet: | |||
| 894 | } | 896 | } |
| 895 | subsys_initcall(cfg80211_init); | 897 | subsys_initcall(cfg80211_init); |
| 896 | 898 | ||
| 897 | static void cfg80211_exit(void) | 899 | static void __exit cfg80211_exit(void) |
| 898 | { | 900 | { |
| 899 | debugfs_remove(ieee80211_debugfs_dir); | 901 | debugfs_remove(ieee80211_debugfs_dir); |
| 900 | nl80211_exit(); | 902 | nl80211_exit(); |
| @@ -905,3 +907,52 @@ static void cfg80211_exit(void) | |||
| 905 | destroy_workqueue(cfg80211_wq); | 907 | destroy_workqueue(cfg80211_wq); |
| 906 | } | 908 | } |
| 907 | module_exit(cfg80211_exit); | 909 | module_exit(cfg80211_exit); |
| 910 | |||
| 911 | static int ___wiphy_printk(const char *level, const struct wiphy *wiphy, | ||
| 912 | struct va_format *vaf) | ||
| 913 | { | ||
| 914 | if (!wiphy) | ||
| 915 | return printk("%s(NULL wiphy *): %pV", level, vaf); | ||
| 916 | |||
| 917 | return printk("%s%s: %pV", level, wiphy_name(wiphy), vaf); | ||
| 918 | } | ||
| 919 | |||
| 920 | int __wiphy_printk(const char *level, const struct wiphy *wiphy, | ||
| 921 | const char *fmt, ...) | ||
| 922 | { | ||
| 923 | struct va_format vaf; | ||
| 924 | va_list args; | ||
| 925 | int r; | ||
| 926 | |||
| 927 | va_start(args, fmt); | ||
| 928 | |||
| 929 | vaf.fmt = fmt; | ||
| 930 | vaf.va = &args; | ||
| 931 | |||
| 932 | r = ___wiphy_printk(level, wiphy, &vaf); | ||
| 933 | va_end(args); | ||
| 934 | |||
| 935 | return r; | ||
| 936 | } | ||
| 937 | EXPORT_SYMBOL(__wiphy_printk); | ||
| 938 | |||
| 939 | #define define_wiphy_printk_level(func, kern_level) \ | ||
| 940 | int func(const struct wiphy *wiphy, const char *fmt, ...) \ | ||
| 941 | { \ | ||
| 942 | struct va_format vaf; \ | ||
| 943 | va_list args; \ | ||
| 944 | int r; \ | ||
| 945 | \ | ||
| 946 | va_start(args, fmt); \ | ||
| 947 | \ | ||
| 948 | vaf.fmt = fmt; \ | ||
| 949 | vaf.va = &args; \ | ||
| 950 | \ | ||
| 951 | r = ___wiphy_printk(kern_level, wiphy, &vaf); \ | ||
| 952 | va_end(args); \ | ||
| 953 | \ | ||
| 954 | return r; \ | ||
| 955 | } \ | ||
| 956 | EXPORT_SYMBOL(func); | ||
| 957 | |||
| 958 | define_wiphy_printk_level(wiphy_debug, KERN_DEBUG); | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index ae930acf75e9..63d57ae399c3 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
| @@ -339,6 +339,7 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, | |||
| 339 | struct net_device *dev, | 339 | struct net_device *dev, |
| 340 | struct ieee80211_channel *chan, | 340 | struct ieee80211_channel *chan, |
| 341 | enum nl80211_channel_type channel_type, | 341 | enum nl80211_channel_type channel_type, |
| 342 | bool channel_type_valid, | ||
| 342 | const u8 *buf, size_t len, u64 *cookie); | 343 | const u8 *buf, size_t len, u64 *cookie); |
| 343 | 344 | ||
| 344 | /* SME */ | 345 | /* SME */ |
diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index 3cc9e69880a8..53c143f5e770 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk | |||
| @@ -21,6 +21,7 @@ BEGIN { | |||
| 21 | print "" | 21 | print "" |
| 22 | print "#include <linux/nl80211.h>" | 22 | print "#include <linux/nl80211.h>" |
| 23 | print "#include <net/cfg80211.h>" | 23 | print "#include <net/cfg80211.h>" |
| 24 | print "#include \"regdb.h\"" | ||
| 24 | print "" | 25 | print "" |
| 25 | regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n" | 26 | regdb = "const struct ieee80211_regdomain *reg_regdb[] = {\n" |
| 26 | } | 27 | } |
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index adcabba02e20..27a8ce9343c3 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c | |||
| @@ -247,8 +247,10 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | |||
| 247 | if (!netif_running(wdev->netdev)) | 247 | if (!netif_running(wdev->netdev)) |
| 248 | return 0; | 248 | return 0; |
| 249 | 249 | ||
| 250 | if (wdev->wext.keys) | 250 | if (wdev->wext.keys) { |
| 251 | wdev->wext.keys->def = wdev->wext.default_key; | 251 | wdev->wext.keys->def = wdev->wext.default_key; |
| 252 | wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key; | ||
| 253 | } | ||
| 252 | 254 | ||
| 253 | wdev->wext.ibss.privacy = wdev->wext.default_key != -1; | 255 | wdev->wext.ibss.privacy = wdev->wext.default_key != -1; |
| 254 | 256 | ||
diff --git a/net/wireless/lib80211_crypt_ccmp.c b/net/wireless/lib80211_crypt_ccmp.c index b7fa31d5fd13..dacb3b4b1bdb 100644 --- a/net/wireless/lib80211_crypt_ccmp.c +++ b/net/wireless/lib80211_crypt_ccmp.c | |||
| @@ -467,7 +467,6 @@ static struct lib80211_crypto_ops lib80211_crypt_ccmp = { | |||
| 467 | .name = "CCMP", | 467 | .name = "CCMP", |
| 468 | .init = lib80211_ccmp_init, | 468 | .init = lib80211_ccmp_init, |
| 469 | .deinit = lib80211_ccmp_deinit, | 469 | .deinit = lib80211_ccmp_deinit, |
| 470 | .build_iv = lib80211_ccmp_hdr, | ||
| 471 | .encrypt_mpdu = lib80211_ccmp_encrypt, | 470 | .encrypt_mpdu = lib80211_ccmp_encrypt, |
| 472 | .decrypt_mpdu = lib80211_ccmp_decrypt, | 471 | .decrypt_mpdu = lib80211_ccmp_decrypt, |
| 473 | .encrypt_msdu = NULL, | 472 | .encrypt_msdu = NULL, |
diff --git a/net/wireless/lib80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c index 8cbdb32ff316..0fe40510e2cb 100644 --- a/net/wireless/lib80211_crypt_tkip.c +++ b/net/wireless/lib80211_crypt_tkip.c | |||
| @@ -578,7 +578,7 @@ static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) | |||
| 578 | } | 578 | } |
| 579 | 579 | ||
| 580 | if (ieee80211_is_data_qos(hdr11->frame_control)) { | 580 | if (ieee80211_is_data_qos(hdr11->frame_control)) { |
| 581 | hdr[12] = le16_to_cpu(*ieee80211_get_qos_ctl(hdr11)) | 581 | hdr[12] = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(hdr11))) |
| 582 | & IEEE80211_QOS_CTL_TID_MASK; | 582 | & IEEE80211_QOS_CTL_TID_MASK; |
| 583 | } else | 583 | } else |
| 584 | hdr[12] = 0; /* priority */ | 584 | hdr[12] = 0; /* priority */ |
| @@ -757,7 +757,6 @@ static struct lib80211_crypto_ops lib80211_crypt_tkip = { | |||
| 757 | .name = "TKIP", | 757 | .name = "TKIP", |
| 758 | .init = lib80211_tkip_init, | 758 | .init = lib80211_tkip_init, |
| 759 | .deinit = lib80211_tkip_deinit, | 759 | .deinit = lib80211_tkip_deinit, |
| 760 | .build_iv = lib80211_tkip_hdr, | ||
| 761 | .encrypt_mpdu = lib80211_tkip_encrypt, | 760 | .encrypt_mpdu = lib80211_tkip_encrypt, |
| 762 | .decrypt_mpdu = lib80211_tkip_decrypt, | 761 | .decrypt_mpdu = lib80211_tkip_decrypt, |
| 763 | .encrypt_msdu = lib80211_michael_mic_add, | 762 | .encrypt_msdu = lib80211_michael_mic_add, |
diff --git a/net/wireless/lib80211_crypt_wep.c b/net/wireless/lib80211_crypt_wep.c index 6d41e05ca33b..e2e88878ba35 100644 --- a/net/wireless/lib80211_crypt_wep.c +++ b/net/wireless/lib80211_crypt_wep.c | |||
| @@ -269,7 +269,6 @@ static struct lib80211_crypto_ops lib80211_crypt_wep = { | |||
| 269 | .name = "WEP", | 269 | .name = "WEP", |
| 270 | .init = lib80211_wep_init, | 270 | .init = lib80211_wep_init, |
| 271 | .deinit = lib80211_wep_deinit, | 271 | .deinit = lib80211_wep_deinit, |
| 272 | .build_iv = lib80211_wep_build_iv, | ||
| 273 | .encrypt_mpdu = lib80211_wep_encrypt, | 272 | .encrypt_mpdu = lib80211_wep_encrypt, |
| 274 | .decrypt_mpdu = lib80211_wep_decrypt, | 273 | .decrypt_mpdu = lib80211_wep_decrypt, |
| 275 | .encrypt_msdu = NULL, | 274 | .encrypt_msdu = NULL, |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 48ead6f0426d..e74a1a2119d3 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
| @@ -44,10 +44,10 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) | |||
| 44 | } | 44 | } |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | WARN_ON(!done); | 47 | if (done) { |
| 48 | 48 | nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); | |
| 49 | nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); | 49 | cfg80211_sme_rx_auth(dev, buf, len); |
| 50 | cfg80211_sme_rx_auth(dev, buf, len); | 50 | } |
| 51 | 51 | ||
| 52 | wdev_unlock(wdev); | 52 | wdev_unlock(wdev); |
| 53 | } | 53 | } |
| @@ -827,6 +827,7 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, | |||
| 827 | struct net_device *dev, | 827 | struct net_device *dev, |
| 828 | struct ieee80211_channel *chan, | 828 | struct ieee80211_channel *chan, |
| 829 | enum nl80211_channel_type channel_type, | 829 | enum nl80211_channel_type channel_type, |
| 830 | bool channel_type_valid, | ||
| 830 | const u8 *buf, size_t len, u64 *cookie) | 831 | const u8 *buf, size_t len, u64 *cookie) |
| 831 | { | 832 | { |
| 832 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 833 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| @@ -845,8 +846,9 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, | |||
| 845 | if (!wdev->current_bss || | 846 | if (!wdev->current_bss || |
| 846 | memcmp(wdev->current_bss->pub.bssid, mgmt->bssid, | 847 | memcmp(wdev->current_bss->pub.bssid, mgmt->bssid, |
| 847 | ETH_ALEN) != 0 || | 848 | ETH_ALEN) != 0 || |
| 848 | memcmp(wdev->current_bss->pub.bssid, mgmt->da, | 849 | (wdev->iftype == NL80211_IFTYPE_STATION && |
| 849 | ETH_ALEN) != 0) | 850 | memcmp(wdev->current_bss->pub.bssid, mgmt->da, |
| 851 | ETH_ALEN) != 0)) | ||
| 850 | return -ENOTCONN; | 852 | return -ENOTCONN; |
| 851 | } | 853 | } |
| 852 | 854 | ||
| @@ -855,7 +857,7 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, | |||
| 855 | 857 | ||
| 856 | /* Transmit the Action frame as requested by user space */ | 858 | /* Transmit the Action frame as requested by user space */ |
| 857 | return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type, | 859 | return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type, |
| 858 | buf, len, cookie); | 860 | channel_type_valid, buf, len, cookie); |
| 859 | } | 861 | } |
| 860 | 862 | ||
| 861 | bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf, | 863 | bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf, |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index db71150b8040..37902a54e9c1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
| @@ -153,6 +153,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
| 153 | [NL80211_ATTR_CQM] = { .type = NLA_NESTED, }, | 153 | [NL80211_ATTR_CQM] = { .type = NLA_NESTED, }, |
| 154 | [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG }, | 154 | [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG }, |
| 155 | [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 }, | 155 | [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 }, |
| 156 | |||
| 157 | [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, | ||
| 158 | [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, | ||
| 156 | }; | 159 | }; |
| 157 | 160 | ||
| 158 | /* policy for the attributes */ | 161 | /* policy for the attributes */ |
| @@ -869,6 +872,34 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
| 869 | goto bad_res; | 872 | goto bad_res; |
| 870 | } | 873 | } |
| 871 | 874 | ||
| 875 | if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) { | ||
| 876 | enum nl80211_tx_power_setting type; | ||
| 877 | int idx, mbm = 0; | ||
| 878 | |||
| 879 | if (!rdev->ops->set_tx_power) { | ||
| 880 | result = -EOPNOTSUPP; | ||
| 881 | goto bad_res; | ||
| 882 | } | ||
| 883 | |||
| 884 | idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING; | ||
| 885 | type = nla_get_u32(info->attrs[idx]); | ||
| 886 | |||
| 887 | if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] && | ||
| 888 | (type != NL80211_TX_POWER_AUTOMATIC)) { | ||
| 889 | result = -EINVAL; | ||
| 890 | goto bad_res; | ||
| 891 | } | ||
| 892 | |||
| 893 | if (type != NL80211_TX_POWER_AUTOMATIC) { | ||
| 894 | idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL; | ||
| 895 | mbm = nla_get_u32(info->attrs[idx]); | ||
| 896 | } | ||
| 897 | |||
| 898 | result = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm); | ||
| 899 | if (result) | ||
| 900 | goto bad_res; | ||
| 901 | } | ||
| 902 | |||
| 872 | changed = 0; | 903 | changed = 0; |
| 873 | 904 | ||
| 874 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { | 905 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { |
| @@ -1107,7 +1138,7 @@ static int nl80211_valid_4addr(struct cfg80211_registered_device *rdev, | |||
| 1107 | enum nl80211_iftype iftype) | 1138 | enum nl80211_iftype iftype) |
| 1108 | { | 1139 | { |
| 1109 | if (!use_4addr) { | 1140 | if (!use_4addr) { |
| 1110 | if (netdev && netdev->br_port) | 1141 | if (netdev && (netdev->priv_flags & IFF_BRIDGE_PORT)) |
| 1111 | return -EBUSY; | 1142 | return -EBUSY; |
| 1112 | return 0; | 1143 | return 0; |
| 1113 | } | 1144 | } |
| @@ -2738,6 +2769,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
| 2738 | 2769 | ||
| 2739 | nla_put_failure: | 2770 | nla_put_failure: |
| 2740 | genlmsg_cancel(msg, hdr); | 2771 | genlmsg_cancel(msg, hdr); |
| 2772 | nlmsg_free(msg); | ||
| 2741 | err = -EMSGSIZE; | 2773 | err = -EMSGSIZE; |
| 2742 | out: | 2774 | out: |
| 2743 | /* Cleanup */ | 2775 | /* Cleanup */ |
| @@ -2929,6 +2961,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
| 2929 | 2961 | ||
| 2930 | nla_put_failure: | 2962 | nla_put_failure: |
| 2931 | genlmsg_cancel(msg, hdr); | 2963 | genlmsg_cancel(msg, hdr); |
| 2964 | nlmsg_free(msg); | ||
| 2932 | err = -EMSGSIZE; | 2965 | err = -EMSGSIZE; |
| 2933 | out: | 2966 | out: |
| 2934 | mutex_unlock(&cfg80211_mutex); | 2967 | mutex_unlock(&cfg80211_mutex); |
| @@ -3955,6 +3988,55 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
| 3955 | } | 3988 | } |
| 3956 | } | 3989 | } |
| 3957 | 3990 | ||
| 3991 | if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { | ||
| 3992 | u8 *rates = | ||
| 3993 | nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | ||
| 3994 | int n_rates = | ||
| 3995 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | ||
| 3996 | struct ieee80211_supported_band *sband = | ||
| 3997 | wiphy->bands[ibss.channel->band]; | ||
| 3998 | int i, j; | ||
| 3999 | |||
| 4000 | if (n_rates == 0) { | ||
| 4001 | err = -EINVAL; | ||
| 4002 | goto out; | ||
| 4003 | } | ||
| 4004 | |||
| 4005 | for (i = 0; i < n_rates; i++) { | ||
| 4006 | int rate = (rates[i] & 0x7f) * 5; | ||
| 4007 | bool found = false; | ||
| 4008 | |||
| 4009 | for (j = 0; j < sband->n_bitrates; j++) { | ||
| 4010 | if (sband->bitrates[j].bitrate == rate) { | ||
| 4011 | found = true; | ||
| 4012 | ibss.basic_rates |= BIT(j); | ||
| 4013 | break; | ||
| 4014 | } | ||
| 4015 | } | ||
| 4016 | if (!found) { | ||
| 4017 | err = -EINVAL; | ||
| 4018 | goto out; | ||
| 4019 | } | ||
| 4020 | } | ||
| 4021 | } else { | ||
| 4022 | /* | ||
| 4023 | * If no rates were explicitly configured, | ||
| 4024 | * use the mandatory rate set for 11b or | ||
| 4025 | * 11a for maximum compatibility. | ||
| 4026 | */ | ||
| 4027 | struct ieee80211_supported_band *sband = | ||
| 4028 | wiphy->bands[ibss.channel->band]; | ||
| 4029 | int j; | ||
| 4030 | u32 flag = ibss.channel->band == IEEE80211_BAND_5GHZ ? | ||
| 4031 | IEEE80211_RATE_MANDATORY_A : | ||
| 4032 | IEEE80211_RATE_MANDATORY_B; | ||
| 4033 | |||
| 4034 | for (j = 0; j < sband->n_bitrates; j++) { | ||
| 4035 | if (sband->bitrates[j].flags & flag) | ||
| 4036 | ibss.basic_rates |= BIT(j); | ||
| 4037 | } | ||
| 4038 | } | ||
| 4039 | |||
| 3958 | err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); | 4040 | err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); |
| 3959 | 4041 | ||
| 3960 | out: | 4042 | out: |
| @@ -4653,7 +4735,8 @@ static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) | |||
| 4653 | if (err) | 4735 | if (err) |
| 4654 | goto unlock_rtnl; | 4736 | goto unlock_rtnl; |
| 4655 | 4737 | ||
| 4656 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 4738 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
| 4739 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
| 4657 | err = -EOPNOTSUPP; | 4740 | err = -EOPNOTSUPP; |
| 4658 | goto out; | 4741 | goto out; |
| 4659 | } | 4742 | } |
| @@ -4681,6 +4764,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
| 4681 | struct net_device *dev; | 4764 | struct net_device *dev; |
| 4682 | struct ieee80211_channel *chan; | 4765 | struct ieee80211_channel *chan; |
| 4683 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 4766 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
| 4767 | bool channel_type_valid = false; | ||
| 4684 | u32 freq; | 4768 | u32 freq; |
| 4685 | int err; | 4769 | int err; |
| 4686 | void *hdr; | 4770 | void *hdr; |
| @@ -4702,7 +4786,8 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
| 4702 | goto out; | 4786 | goto out; |
| 4703 | } | 4787 | } |
| 4704 | 4788 | ||
| 4705 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | 4789 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && |
| 4790 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
| 4706 | err = -EOPNOTSUPP; | 4791 | err = -EOPNOTSUPP; |
| 4707 | goto out; | 4792 | goto out; |
| 4708 | } | 4793 | } |
| @@ -4722,6 +4807,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
| 4722 | err = -EINVAL; | 4807 | err = -EINVAL; |
| 4723 | goto out; | 4808 | goto out; |
| 4724 | } | 4809 | } |
| 4810 | channel_type_valid = true; | ||
| 4725 | } | 4811 | } |
| 4726 | 4812 | ||
| 4727 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 4813 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
| @@ -4745,6 +4831,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
| 4745 | goto free_msg; | 4831 | goto free_msg; |
| 4746 | } | 4832 | } |
| 4747 | err = cfg80211_mlme_action(rdev, dev, chan, channel_type, | 4833 | err = cfg80211_mlme_action(rdev, dev, chan, channel_type, |
| 4834 | channel_type_valid, | ||
| 4748 | nla_data(info->attrs[NL80211_ATTR_FRAME]), | 4835 | nla_data(info->attrs[NL80211_ATTR_FRAME]), |
| 4749 | nla_len(info->attrs[NL80211_ATTR_FRAME]), | 4836 | nla_len(info->attrs[NL80211_ATTR_FRAME]), |
| 4750 | &cookie); | 4837 | &cookie); |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 8f0d97dd3109..f180db0de66c 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
| @@ -67,20 +67,12 @@ static struct platform_device *reg_pdev; | |||
| 67 | const struct ieee80211_regdomain *cfg80211_regdomain; | 67 | const struct ieee80211_regdomain *cfg80211_regdomain; |
| 68 | 68 | ||
| 69 | /* | 69 | /* |
| 70 | * We use this as a place for the rd structure built from the | ||
| 71 | * last parsed country IE to rest until CRDA gets back to us with | ||
| 72 | * what it thinks should apply for the same country | ||
| 73 | */ | ||
| 74 | static const struct ieee80211_regdomain *country_ie_regdomain; | ||
| 75 | |||
| 76 | /* | ||
| 77 | * Protects static reg.c components: | 70 | * Protects static reg.c components: |
| 78 | * - cfg80211_world_regdom | 71 | * - cfg80211_world_regdom |
| 79 | * - cfg80211_regdom | 72 | * - cfg80211_regdom |
| 80 | * - country_ie_regdomain | ||
| 81 | * - last_request | 73 | * - last_request |
| 82 | */ | 74 | */ |
| 83 | DEFINE_MUTEX(reg_mutex); | 75 | static DEFINE_MUTEX(reg_mutex); |
| 84 | #define assert_reg_lock() WARN_ON(!mutex_is_locked(®_mutex)) | 76 | #define assert_reg_lock() WARN_ON(!mutex_is_locked(®_mutex)) |
| 85 | 77 | ||
| 86 | /* Used to queue up regulatory hints */ | 78 | /* Used to queue up regulatory hints */ |
| @@ -275,25 +267,6 @@ static bool is_user_regdom_saved(void) | |||
| 275 | return true; | 267 | return true; |
| 276 | } | 268 | } |
| 277 | 269 | ||
| 278 | /** | ||
| 279 | * country_ie_integrity_changes - tells us if the country IE has changed | ||
| 280 | * @checksum: checksum of country IE of fields we are interested in | ||
| 281 | * | ||
| 282 | * If the country IE has not changed you can ignore it safely. This is | ||
| 283 | * useful to determine if two devices are seeing two different country IEs | ||
| 284 | * even on the same alpha2. Note that this will return false if no IE has | ||
| 285 | * been set on the wireless core yet. | ||
| 286 | */ | ||
| 287 | static bool country_ie_integrity_changes(u32 checksum) | ||
| 288 | { | ||
| 289 | /* If no IE has been set then the checksum doesn't change */ | ||
| 290 | if (unlikely(!last_request->country_ie_checksum)) | ||
| 291 | return false; | ||
| 292 | if (unlikely(last_request->country_ie_checksum != checksum)) | ||
| 293 | return true; | ||
| 294 | return false; | ||
| 295 | } | ||
| 296 | |||
| 297 | static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, | 270 | static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, |
| 298 | const struct ieee80211_regdomain *src_regd) | 271 | const struct ieee80211_regdomain *src_regd) |
| 299 | { | 272 | { |
| @@ -506,471 +479,6 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, | |||
| 506 | } | 479 | } |
| 507 | 480 | ||
| 508 | /* | 481 | /* |
| 509 | * This is a work around for sanity checking ieee80211_channel_to_frequency()'s | ||
| 510 | * work. ieee80211_channel_to_frequency() can for example currently provide a | ||
| 511 | * 2 GHz channel when in fact a 5 GHz channel was desired. An example would be | ||
| 512 | * an AP providing channel 8 on a country IE triplet when it sent this on the | ||
| 513 | * 5 GHz band, that channel is designed to be channel 8 on 5 GHz, not a 2 GHz | ||
| 514 | * channel. | ||
| 515 | * | ||
| 516 | * This can be removed once ieee80211_channel_to_frequency() takes in a band. | ||
| 517 | */ | ||
| 518 | static bool chan_in_band(int chan, enum ieee80211_band band) | ||
| 519 | { | ||
| 520 | int center_freq = ieee80211_channel_to_frequency(chan); | ||
| 521 | |||
| 522 | switch (band) { | ||
| 523 | case IEEE80211_BAND_2GHZ: | ||
| 524 | if (center_freq <= 2484) | ||
| 525 | return true; | ||
| 526 | return false; | ||
| 527 | case IEEE80211_BAND_5GHZ: | ||
| 528 | if (center_freq >= 5005) | ||
| 529 | return true; | ||
| 530 | return false; | ||
| 531 | default: | ||
| 532 | return false; | ||
| 533 | } | ||
| 534 | } | ||
| 535 | |||
| 536 | /* | ||
| 537 | * Some APs may send a country IE triplet for each channel they | ||
| 538 | * support and while this is completely overkill and silly we still | ||
| 539 | * need to support it. We avoid making a single rule for each channel | ||
| 540 | * though and to help us with this we use this helper to find the | ||
| 541 | * actual subband end channel. These type of country IE triplet | ||
| 542 | * scenerios are handled then, all yielding two regulaotry rules from | ||
| 543 | * parsing a country IE: | ||
| 544 | * | ||
| 545 | * [1] | ||
| 546 | * [2] | ||
| 547 | * [36] | ||
| 548 | * [40] | ||
| 549 | * | ||
| 550 | * [1] | ||
| 551 | * [2-4] | ||
| 552 | * [5-12] | ||
| 553 | * [36] | ||
| 554 | * [40-44] | ||
| 555 | * | ||
| 556 | * [1-4] | ||
| 557 | * [5-7] | ||
| 558 | * [36-44] | ||
| 559 | * [48-64] | ||
| 560 | * | ||
| 561 | * [36-36] | ||
| 562 | * [40-40] | ||
| 563 | * [44-44] | ||
| 564 | * [48-48] | ||
| 565 | * [52-52] | ||
| 566 | * [56-56] | ||
| 567 | * [60-60] | ||
| 568 | * [64-64] | ||
| 569 | * [100-100] | ||
| 570 | * [104-104] | ||
| 571 | * [108-108] | ||
| 572 | * [112-112] | ||
| 573 | * [116-116] | ||
| 574 | * [120-120] | ||
| 575 | * [124-124] | ||
| 576 | * [128-128] | ||
| 577 | * [132-132] | ||
| 578 | * [136-136] | ||
| 579 | * [140-140] | ||
| 580 | * | ||
| 581 | * Returns 0 if the IE has been found to be invalid in the middle | ||
| 582 | * somewhere. | ||
| 583 | */ | ||
| 584 | static int max_subband_chan(enum ieee80211_band band, | ||
| 585 | int orig_cur_chan, | ||
| 586 | int orig_end_channel, | ||
| 587 | s8 orig_max_power, | ||
| 588 | u8 **country_ie, | ||
| 589 | u8 *country_ie_len) | ||
| 590 | { | ||
| 591 | u8 *triplets_start = *country_ie; | ||
| 592 | u8 len_at_triplet = *country_ie_len; | ||
| 593 | int end_subband_chan = orig_end_channel; | ||
| 594 | |||
| 595 | /* | ||
| 596 | * We'll deal with padding for the caller unless | ||
| 597 | * its not immediate and we don't process any channels | ||
| 598 | */ | ||
| 599 | if (*country_ie_len == 1) { | ||
| 600 | *country_ie += 1; | ||
| 601 | *country_ie_len -= 1; | ||
| 602 | return orig_end_channel; | ||
| 603 | } | ||
| 604 | |||
| 605 | /* Move to the next triplet and then start search */ | ||
| 606 | *country_ie += 3; | ||
| 607 | *country_ie_len -= 3; | ||
| 608 | |||
| 609 | if (!chan_in_band(orig_cur_chan, band)) | ||
| 610 | return 0; | ||
| 611 | |||
| 612 | while (*country_ie_len >= 3) { | ||
| 613 | int end_channel = 0; | ||
| 614 | struct ieee80211_country_ie_triplet *triplet = | ||
| 615 | (struct ieee80211_country_ie_triplet *) *country_ie; | ||
| 616 | int cur_channel = 0, next_expected_chan; | ||
| 617 | |||
| 618 | /* means last triplet is completely unrelated to this one */ | ||
| 619 | if (triplet->ext.reg_extension_id >= | ||
| 620 | IEEE80211_COUNTRY_EXTENSION_ID) { | ||
| 621 | *country_ie -= 3; | ||
| 622 | *country_ie_len += 3; | ||
| 623 | break; | ||
| 624 | } | ||
| 625 | |||
| 626 | if (triplet->chans.first_channel == 0) { | ||
| 627 | *country_ie += 1; | ||
| 628 | *country_ie_len -= 1; | ||
| 629 | if (*country_ie_len != 0) | ||
| 630 | return 0; | ||
| 631 | break; | ||
| 632 | } | ||
| 633 | |||
| 634 | if (triplet->chans.num_channels == 0) | ||
| 635 | return 0; | ||
| 636 | |||
| 637 | /* Monitonically increasing channel order */ | ||
| 638 | if (triplet->chans.first_channel <= end_subband_chan) | ||
| 639 | return 0; | ||
| 640 | |||
| 641 | if (!chan_in_band(triplet->chans.first_channel, band)) | ||
| 642 | return 0; | ||
| 643 | |||
| 644 | /* 2 GHz */ | ||
| 645 | if (triplet->chans.first_channel <= 14) { | ||
| 646 | end_channel = triplet->chans.first_channel + | ||
| 647 | triplet->chans.num_channels - 1; | ||
| 648 | } | ||
| 649 | else { | ||
| 650 | end_channel = triplet->chans.first_channel + | ||
| 651 | (4 * (triplet->chans.num_channels - 1)); | ||
| 652 | } | ||
| 653 | |||
| 654 | if (!chan_in_band(end_channel, band)) | ||
| 655 | return 0; | ||
| 656 | |||
| 657 | if (orig_max_power != triplet->chans.max_power) { | ||
| 658 | *country_ie -= 3; | ||
| 659 | *country_ie_len += 3; | ||
| 660 | break; | ||
| 661 | } | ||
| 662 | |||
| 663 | cur_channel = triplet->chans.first_channel; | ||
| 664 | |||
| 665 | /* The key is finding the right next expected channel */ | ||
| 666 | if (band == IEEE80211_BAND_2GHZ) | ||
| 667 | next_expected_chan = end_subband_chan + 1; | ||
| 668 | else | ||
| 669 | next_expected_chan = end_subband_chan + 4; | ||
| 670 | |||
| 671 | if (cur_channel != next_expected_chan) { | ||
| 672 | *country_ie -= 3; | ||
| 673 | *country_ie_len += 3; | ||
| 674 | break; | ||
| 675 | } | ||
| 676 | |||
| 677 | end_subband_chan = end_channel; | ||
| 678 | |||
| 679 | /* Move to the next one */ | ||
| 680 | *country_ie += 3; | ||
| 681 | *country_ie_len -= 3; | ||
| 682 | |||
| 683 | /* | ||
| 684 | * Padding needs to be dealt with if we processed | ||
| 685 | * some channels. | ||
| 686 | */ | ||
| 687 | if (*country_ie_len == 1) { | ||
| 688 | *country_ie += 1; | ||
| 689 | *country_ie_len -= 1; | ||
| 690 | break; | ||
| 691 | } | ||
| 692 | |||
| 693 | /* If seen, the IE is invalid */ | ||
| 694 | if (*country_ie_len == 2) | ||
| 695 | return 0; | ||
| 696 | } | ||
| 697 | |||
| 698 | if (end_subband_chan == orig_end_channel) { | ||
| 699 | *country_ie = triplets_start; | ||
| 700 | *country_ie_len = len_at_triplet; | ||
| 701 | return orig_end_channel; | ||
| 702 | } | ||
| 703 | |||
| 704 | return end_subband_chan; | ||
| 705 | } | ||
| 706 | |||
| 707 | /* | ||
| 708 | * Converts a country IE to a regulatory domain. A regulatory domain | ||
| 709 | * structure has a lot of information which the IE doesn't yet have, | ||
| 710 | * so for the other values we use upper max values as we will intersect | ||
| 711 | * with our userspace regulatory agent to get lower bounds. | ||
| 712 | */ | ||
| 713 | static struct ieee80211_regdomain *country_ie_2_rd( | ||
| 714 | enum ieee80211_band band, | ||
| 715 | u8 *country_ie, | ||
| 716 | u8 country_ie_len, | ||
| 717 | u32 *checksum) | ||
| 718 | { | ||
| 719 | struct ieee80211_regdomain *rd = NULL; | ||
| 720 | unsigned int i = 0; | ||
| 721 | char alpha2[2]; | ||
| 722 | u32 flags = 0; | ||
| 723 | u32 num_rules = 0, size_of_regd = 0; | ||
| 724 | u8 *triplets_start = NULL; | ||
| 725 | u8 len_at_triplet = 0; | ||
| 726 | /* the last channel we have registered in a subband (triplet) */ | ||
| 727 | int last_sub_max_channel = 0; | ||
| 728 | |||
| 729 | *checksum = 0xDEADBEEF; | ||
| 730 | |||
| 731 | /* Country IE requirements */ | ||
| 732 | BUG_ON(country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN || | ||
| 733 | country_ie_len & 0x01); | ||
| 734 | |||
| 735 | alpha2[0] = country_ie[0]; | ||
| 736 | alpha2[1] = country_ie[1]; | ||
| 737 | |||
| 738 | /* | ||
| 739 | * Third octet can be: | ||
| 740 | * 'I' - Indoor | ||
| 741 | * 'O' - Outdoor | ||
| 742 | * | ||
| 743 | * anything else we assume is no restrictions | ||
| 744 | */ | ||
| 745 | if (country_ie[2] == 'I') | ||
| 746 | flags = NL80211_RRF_NO_OUTDOOR; | ||
| 747 | else if (country_ie[2] == 'O') | ||
| 748 | flags = NL80211_RRF_NO_INDOOR; | ||
| 749 | |||
| 750 | country_ie += 3; | ||
| 751 | country_ie_len -= 3; | ||
| 752 | |||
| 753 | triplets_start = country_ie; | ||
| 754 | len_at_triplet = country_ie_len; | ||
| 755 | |||
| 756 | *checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8); | ||
| 757 | |||
| 758 | /* | ||
| 759 | * We need to build a reg rule for each triplet, but first we must | ||
| 760 | * calculate the number of reg rules we will need. We will need one | ||
| 761 | * for each channel subband | ||
| 762 | */ | ||
| 763 | while (country_ie_len >= 3) { | ||
| 764 | int end_channel = 0; | ||
| 765 | struct ieee80211_country_ie_triplet *triplet = | ||
| 766 | (struct ieee80211_country_ie_triplet *) country_ie; | ||
| 767 | int cur_sub_max_channel = 0, cur_channel = 0; | ||
| 768 | |||
| 769 | if (triplet->ext.reg_extension_id >= | ||
| 770 | IEEE80211_COUNTRY_EXTENSION_ID) { | ||
| 771 | country_ie += 3; | ||
| 772 | country_ie_len -= 3; | ||
| 773 | continue; | ||
| 774 | } | ||
| 775 | |||
| 776 | /* | ||
| 777 | * APs can add padding to make length divisible | ||
| 778 | * by two, required by the spec. | ||
| 779 | */ | ||
| 780 | if (triplet->chans.first_channel == 0) { | ||
| 781 | country_ie++; | ||
| 782 | country_ie_len--; | ||
| 783 | /* This is expected to be at the very end only */ | ||
| 784 | if (country_ie_len != 0) | ||
| 785 | return NULL; | ||
| 786 | break; | ||
| 787 | } | ||
| 788 | |||
| 789 | if (triplet->chans.num_channels == 0) | ||
| 790 | return NULL; | ||
| 791 | |||
| 792 | if (!chan_in_band(triplet->chans.first_channel, band)) | ||
| 793 | return NULL; | ||
| 794 | |||
| 795 | /* 2 GHz */ | ||
| 796 | if (band == IEEE80211_BAND_2GHZ) | ||
| 797 | end_channel = triplet->chans.first_channel + | ||
| 798 | triplet->chans.num_channels - 1; | ||
| 799 | else | ||
| 800 | /* | ||
| 801 | * 5 GHz -- For example in country IEs if the first | ||
| 802 | * channel given is 36 and the number of channels is 4 | ||
| 803 | * then the individual channel numbers defined for the | ||
| 804 | * 5 GHz PHY by these parameters are: 36, 40, 44, and 48 | ||
| 805 | * and not 36, 37, 38, 39. | ||
| 806 | * | ||
| 807 | * See: http://tinyurl.com/11d-clarification | ||
| 808 | */ | ||
| 809 | end_channel = triplet->chans.first_channel + | ||
| 810 | (4 * (triplet->chans.num_channels - 1)); | ||
| 811 | |||
| 812 | cur_channel = triplet->chans.first_channel; | ||
| 813 | |||
| 814 | /* | ||
| 815 | * Enhancement for APs that send a triplet for every channel | ||
| 816 | * or for whatever reason sends triplets with multiple channels | ||
| 817 | * separated when in fact they should be together. | ||
| 818 | */ | ||
| 819 | end_channel = max_subband_chan(band, | ||
| 820 | cur_channel, | ||
| 821 | end_channel, | ||
| 822 | triplet->chans.max_power, | ||
| 823 | &country_ie, | ||
| 824 | &country_ie_len); | ||
| 825 | if (!end_channel) | ||
| 826 | return NULL; | ||
| 827 | |||
| 828 | if (!chan_in_band(end_channel, band)) | ||
| 829 | return NULL; | ||
| 830 | |||
| 831 | cur_sub_max_channel = end_channel; | ||
| 832 | |||
| 833 | /* Basic sanity check */ | ||
| 834 | if (cur_sub_max_channel < cur_channel) | ||
| 835 | return NULL; | ||
| 836 | |||
| 837 | /* | ||
| 838 | * Do not allow overlapping channels. Also channels | ||
| 839 | * passed in each subband must be monotonically | ||
| 840 | * increasing | ||
| 841 | */ | ||
| 842 | if (last_sub_max_channel) { | ||
| 843 | if (cur_channel <= last_sub_max_channel) | ||
| 844 | return NULL; | ||
| 845 | if (cur_sub_max_channel <= last_sub_max_channel) | ||
| 846 | return NULL; | ||
| 847 | } | ||
| 848 | |||
| 849 | /* | ||
| 850 | * When dot11RegulatoryClassesRequired is supported | ||
| 851 | * we can throw ext triplets as part of this soup, | ||
| 852 | * for now we don't care when those change as we | ||
| 853 | * don't support them | ||
| 854 | */ | ||
| 855 | *checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) | | ||
| 856 | ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) | | ||
| 857 | ((triplet->chans.max_power ^ cur_sub_max_channel) << 24); | ||
| 858 | |||
| 859 | last_sub_max_channel = cur_sub_max_channel; | ||
| 860 | |||
| 861 | num_rules++; | ||
| 862 | |||
| 863 | if (country_ie_len >= 3) { | ||
| 864 | country_ie += 3; | ||
| 865 | country_ie_len -= 3; | ||
| 866 | } | ||
| 867 | |||
| 868 | /* | ||
| 869 | * Note: this is not a IEEE requirement but | ||
| 870 | * simply a memory requirement | ||
| 871 | */ | ||
| 872 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) | ||
| 873 | return NULL; | ||
| 874 | } | ||
| 875 | |||
| 876 | country_ie = triplets_start; | ||
| 877 | country_ie_len = len_at_triplet; | ||
| 878 | |||
| 879 | size_of_regd = sizeof(struct ieee80211_regdomain) + | ||
| 880 | (num_rules * sizeof(struct ieee80211_reg_rule)); | ||
| 881 | |||
| 882 | rd = kzalloc(size_of_regd, GFP_KERNEL); | ||
| 883 | if (!rd) | ||
| 884 | return NULL; | ||
| 885 | |||
| 886 | rd->n_reg_rules = num_rules; | ||
| 887 | rd->alpha2[0] = alpha2[0]; | ||
| 888 | rd->alpha2[1] = alpha2[1]; | ||
| 889 | |||
| 890 | /* This time around we fill in the rd */ | ||
| 891 | while (country_ie_len >= 3) { | ||
| 892 | int end_channel = 0; | ||
| 893 | struct ieee80211_country_ie_triplet *triplet = | ||
| 894 | (struct ieee80211_country_ie_triplet *) country_ie; | ||
| 895 | struct ieee80211_reg_rule *reg_rule = NULL; | ||
| 896 | struct ieee80211_freq_range *freq_range = NULL; | ||
| 897 | struct ieee80211_power_rule *power_rule = NULL; | ||
| 898 | |||
| 899 | /* | ||
| 900 | * Must parse if dot11RegulatoryClassesRequired is true, | ||
| 901 | * we don't support this yet | ||
| 902 | */ | ||
| 903 | if (triplet->ext.reg_extension_id >= | ||
| 904 | IEEE80211_COUNTRY_EXTENSION_ID) { | ||
| 905 | country_ie += 3; | ||
| 906 | country_ie_len -= 3; | ||
| 907 | continue; | ||
| 908 | } | ||
| 909 | |||
| 910 | if (triplet->chans.first_channel == 0) { | ||
| 911 | country_ie++; | ||
| 912 | country_ie_len--; | ||
| 913 | break; | ||
| 914 | } | ||
| 915 | |||
| 916 | reg_rule = &rd->reg_rules[i]; | ||
| 917 | freq_range = ®_rule->freq_range; | ||
| 918 | power_rule = ®_rule->power_rule; | ||
| 919 | |||
| 920 | reg_rule->flags = flags; | ||
| 921 | |||
| 922 | /* 2 GHz */ | ||
| 923 | if (band == IEEE80211_BAND_2GHZ) | ||
| 924 | end_channel = triplet->chans.first_channel + | ||
| 925 | triplet->chans.num_channels -1; | ||
| 926 | else | ||
| 927 | end_channel = triplet->chans.first_channel + | ||
| 928 | (4 * (triplet->chans.num_channels - 1)); | ||
| 929 | |||
| 930 | end_channel = max_subband_chan(band, | ||
| 931 | triplet->chans.first_channel, | ||
| 932 | end_channel, | ||
| 933 | triplet->chans.max_power, | ||
| 934 | &country_ie, | ||
| 935 | &country_ie_len); | ||
| 936 | |||
| 937 | /* | ||
| 938 | * The +10 is since the regulatory domain expects | ||
| 939 | * the actual band edge, not the center of freq for | ||
| 940 | * its start and end freqs, assuming 20 MHz bandwidth on | ||
| 941 | * the channels passed | ||
| 942 | */ | ||
| 943 | freq_range->start_freq_khz = | ||
| 944 | MHZ_TO_KHZ(ieee80211_channel_to_frequency( | ||
| 945 | triplet->chans.first_channel) - 10); | ||
| 946 | freq_range->end_freq_khz = | ||
| 947 | MHZ_TO_KHZ(ieee80211_channel_to_frequency( | ||
| 948 | end_channel) + 10); | ||
| 949 | |||
| 950 | /* | ||
| 951 | * These are large arbitrary values we use to intersect later. | ||
| 952 | * Increment this if we ever support >= 40 MHz channels | ||
| 953 | * in IEEE 802.11 | ||
| 954 | */ | ||
| 955 | freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); | ||
| 956 | power_rule->max_antenna_gain = DBI_TO_MBI(100); | ||
| 957 | power_rule->max_eirp = DBM_TO_MBM(triplet->chans.max_power); | ||
| 958 | |||
| 959 | i++; | ||
| 960 | |||
| 961 | if (country_ie_len >= 3) { | ||
| 962 | country_ie += 3; | ||
| 963 | country_ie_len -= 3; | ||
| 964 | } | ||
| 965 | |||
| 966 | BUG_ON(i > NL80211_MAX_SUPP_REG_RULES); | ||
| 967 | } | ||
| 968 | |||
| 969 | return rd; | ||
| 970 | } | ||
| 971 | |||
| 972 | |||
| 973 | /* | ||
| 974 | * Helper for regdom_intersect(), this does the real | 482 | * Helper for regdom_intersect(), this does the real |
| 975 | * mathematical intersection fun | 483 | * mathematical intersection fun |
| 976 | */ | 484 | */ |
| @@ -1191,7 +699,6 @@ static int freq_reg_info_regd(struct wiphy *wiphy, | |||
| 1191 | 699 | ||
| 1192 | return -EINVAL; | 700 | return -EINVAL; |
| 1193 | } | 701 | } |
| 1194 | EXPORT_SYMBOL(freq_reg_info); | ||
| 1195 | 702 | ||
| 1196 | int freq_reg_info(struct wiphy *wiphy, | 703 | int freq_reg_info(struct wiphy *wiphy, |
| 1197 | u32 center_freq, | 704 | u32 center_freq, |
| @@ -1205,6 +712,7 @@ int freq_reg_info(struct wiphy *wiphy, | |||
| 1205 | reg_rule, | 712 | reg_rule, |
| 1206 | NULL); | 713 | NULL); |
| 1207 | } | 714 | } |
| 715 | EXPORT_SYMBOL(freq_reg_info); | ||
| 1208 | 716 | ||
| 1209 | /* | 717 | /* |
| 1210 | * Note that right now we assume the desired channel bandwidth | 718 | * Note that right now we assume the desired channel bandwidth |
| @@ -1243,41 +751,8 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
| 1243 | desired_bw_khz, | 751 | desired_bw_khz, |
| 1244 | ®_rule); | 752 | ®_rule); |
| 1245 | 753 | ||
| 1246 | if (r) { | 754 | if (r) |
| 1247 | /* | ||
| 1248 | * This means no regulatory rule was found in the country IE | ||
| 1249 | * with a frequency range on the center_freq's band, since | ||
| 1250 | * IEEE-802.11 allows for a country IE to have a subset of the | ||
| 1251 | * regulatory information provided in a country we ignore | ||
| 1252 | * disabling the channel unless at least one reg rule was | ||
| 1253 | * found on the center_freq's band. For details see this | ||
| 1254 | * clarification: | ||
| 1255 | * | ||
| 1256 | * http://tinyurl.com/11d-clarification | ||
| 1257 | */ | ||
| 1258 | if (r == -ERANGE && | ||
| 1259 | last_request->initiator == | ||
| 1260 | NL80211_REGDOM_SET_BY_COUNTRY_IE) { | ||
| 1261 | REG_DBG_PRINT("cfg80211: Leaving channel %d MHz " | ||
| 1262 | "intact on %s - no rule found in band on " | ||
| 1263 | "Country IE\n", | ||
| 1264 | chan->center_freq, wiphy_name(wiphy)); | ||
| 1265 | } else { | ||
| 1266 | /* | ||
| 1267 | * In this case we know the country IE has at least one reg rule | ||
| 1268 | * for the band so we respect its band definitions | ||
| 1269 | */ | ||
| 1270 | if (last_request->initiator == | ||
| 1271 | NL80211_REGDOM_SET_BY_COUNTRY_IE) | ||
| 1272 | REG_DBG_PRINT("cfg80211: Disabling " | ||
| 1273 | "channel %d MHz on %s due to " | ||
| 1274 | "Country IE\n", | ||
| 1275 | chan->center_freq, wiphy_name(wiphy)); | ||
| 1276 | flags |= IEEE80211_CHAN_DISABLED; | ||
| 1277 | chan->flags = flags; | ||
| 1278 | } | ||
| 1279 | return; | 755 | return; |
| 1280 | } | ||
| 1281 | 756 | ||
| 1282 | power_rule = ®_rule->power_rule; | 757 | power_rule = ®_rule->power_rule; |
| 1283 | freq_range = ®_rule->freq_range; | 758 | freq_range = ®_rule->freq_range; |
| @@ -1831,6 +1306,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
| 1831 | { | 1306 | { |
| 1832 | int r = 0; | 1307 | int r = 0; |
| 1833 | struct wiphy *wiphy = NULL; | 1308 | struct wiphy *wiphy = NULL; |
| 1309 | enum nl80211_reg_initiator initiator = reg_request->initiator; | ||
| 1834 | 1310 | ||
| 1835 | BUG_ON(!reg_request->alpha2); | 1311 | BUG_ON(!reg_request->alpha2); |
| 1836 | 1312 | ||
| @@ -1850,7 +1326,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) | |||
| 1850 | /* This is required so that the orig_* parameters are saved */ | 1326 | /* This is required so that the orig_* parameters are saved */ |
| 1851 | if (r == -EALREADY && wiphy && | 1327 | if (r == -EALREADY && wiphy && |
| 1852 | wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) | 1328 | wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) |
| 1853 | wiphy_update_regulatory(wiphy, reg_request->initiator); | 1329 | wiphy_update_regulatory(wiphy, initiator); |
| 1854 | out: | 1330 | out: |
| 1855 | mutex_unlock(®_mutex); | 1331 | mutex_unlock(®_mutex); |
| 1856 | mutex_unlock(&cfg80211_mutex); | 1332 | mutex_unlock(&cfg80211_mutex); |
| @@ -2008,35 +1484,6 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2) | |||
| 2008 | } | 1484 | } |
| 2009 | EXPORT_SYMBOL(regulatory_hint); | 1485 | EXPORT_SYMBOL(regulatory_hint); |
| 2010 | 1486 | ||
| 2011 | /* Caller must hold reg_mutex */ | ||
| 2012 | static bool reg_same_country_ie_hint(struct wiphy *wiphy, | ||
| 2013 | u32 country_ie_checksum) | ||
| 2014 | { | ||
| 2015 | struct wiphy *request_wiphy; | ||
| 2016 | |||
| 2017 | assert_reg_lock(); | ||
| 2018 | |||
| 2019 | if (unlikely(last_request->initiator != | ||
| 2020 | NL80211_REGDOM_SET_BY_COUNTRY_IE)) | ||
| 2021 | return false; | ||
| 2022 | |||
| 2023 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | ||
| 2024 | |||
| 2025 | if (!request_wiphy) | ||
| 2026 | return false; | ||
| 2027 | |||
| 2028 | if (likely(request_wiphy != wiphy)) | ||
| 2029 | return !country_ie_integrity_changes(country_ie_checksum); | ||
| 2030 | /* | ||
| 2031 | * We should not have let these through at this point, they | ||
| 2032 | * should have been picked up earlier by the first alpha2 check | ||
| 2033 | * on the device | ||
| 2034 | */ | ||
| 2035 | if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum))) | ||
| 2036 | return true; | ||
| 2037 | return false; | ||
| 2038 | } | ||
| 2039 | |||
| 2040 | /* | 1487 | /* |
| 2041 | * We hold wdev_lock() here so we cannot hold cfg80211_mutex() and | 1488 | * We hold wdev_lock() here so we cannot hold cfg80211_mutex() and |
| 2042 | * therefore cannot iterate over the rdev list here. | 1489 | * therefore cannot iterate over the rdev list here. |
| @@ -2046,9 +1493,7 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
| 2046 | u8 *country_ie, | 1493 | u8 *country_ie, |
| 2047 | u8 country_ie_len) | 1494 | u8 country_ie_len) |
| 2048 | { | 1495 | { |
| 2049 | struct ieee80211_regdomain *rd = NULL; | ||
| 2050 | char alpha2[2]; | 1496 | char alpha2[2]; |
| 2051 | u32 checksum = 0; | ||
| 2052 | enum environment_cap env = ENVIRON_ANY; | 1497 | enum environment_cap env = ENVIRON_ANY; |
| 2053 | struct regulatory_request *request; | 1498 | struct regulatory_request *request; |
| 2054 | 1499 | ||
| @@ -2064,14 +1509,6 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
| 2064 | if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) | 1509 | if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) |
| 2065 | goto out; | 1510 | goto out; |
| 2066 | 1511 | ||
| 2067 | /* | ||
| 2068 | * Pending country IE processing, this can happen after we | ||
| 2069 | * call CRDA and wait for a response if a beacon was received before | ||
| 2070 | * we were able to process the last regulatory_hint_11d() call | ||
| 2071 | */ | ||
| 2072 | if (country_ie_regdomain) | ||
| 2073 | goto out; | ||
| 2074 | |||
| 2075 | alpha2[0] = country_ie[0]; | 1512 | alpha2[0] = country_ie[0]; |
| 2076 | alpha2[1] = country_ie[1]; | 1513 | alpha2[1] = country_ie[1]; |
| 2077 | 1514 | ||
| @@ -2090,39 +1527,14 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
| 2090 | wiphy_idx_valid(last_request->wiphy_idx))) | 1527 | wiphy_idx_valid(last_request->wiphy_idx))) |
| 2091 | goto out; | 1528 | goto out; |
| 2092 | 1529 | ||
| 2093 | rd = country_ie_2_rd(band, country_ie, country_ie_len, &checksum); | ||
| 2094 | if (!rd) { | ||
| 2095 | REG_DBG_PRINT("cfg80211: Ignoring bogus country IE\n"); | ||
| 2096 | goto out; | ||
| 2097 | } | ||
| 2098 | |||
| 2099 | /* | ||
| 2100 | * This will not happen right now but we leave it here for the | ||
| 2101 | * the future when we want to add suspend/resume support and having | ||
| 2102 | * the user move to another country after doing so, or having the user | ||
| 2103 | * move to another AP. Right now we just trust the first AP. | ||
| 2104 | * | ||
| 2105 | * If we hit this before we add this support we want to be informed of | ||
| 2106 | * it as it would indicate a mistake in the current design | ||
| 2107 | */ | ||
| 2108 | if (WARN_ON(reg_same_country_ie_hint(wiphy, checksum))) | ||
| 2109 | goto free_rd_out; | ||
| 2110 | |||
| 2111 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); | 1530 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); |
| 2112 | if (!request) | 1531 | if (!request) |
| 2113 | goto free_rd_out; | 1532 | goto out; |
| 2114 | |||
| 2115 | /* | ||
| 2116 | * We keep this around for when CRDA comes back with a response so | ||
| 2117 | * we can intersect with that | ||
| 2118 | */ | ||
| 2119 | country_ie_regdomain = rd; | ||
| 2120 | 1533 | ||
| 2121 | request->wiphy_idx = get_wiphy_idx(wiphy); | 1534 | request->wiphy_idx = get_wiphy_idx(wiphy); |
| 2122 | request->alpha2[0] = rd->alpha2[0]; | 1535 | request->alpha2[0] = alpha2[0]; |
| 2123 | request->alpha2[1] = rd->alpha2[1]; | 1536 | request->alpha2[1] = alpha2[1]; |
| 2124 | request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE; | 1537 | request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE; |
| 2125 | request->country_ie_checksum = checksum; | ||
| 2126 | request->country_ie_env = env; | 1538 | request->country_ie_env = env; |
| 2127 | 1539 | ||
| 2128 | mutex_unlock(®_mutex); | 1540 | mutex_unlock(®_mutex); |
| @@ -2131,8 +1543,6 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
| 2131 | 1543 | ||
| 2132 | return; | 1544 | return; |
| 2133 | 1545 | ||
| 2134 | free_rd_out: | ||
| 2135 | kfree(rd); | ||
| 2136 | out: | 1546 | out: |
| 2137 | mutex_unlock(®_mutex); | 1547 | mutex_unlock(®_mutex); |
| 2138 | } | 1548 | } |
| @@ -2383,33 +1793,6 @@ static void print_regdomain_info(const struct ieee80211_regdomain *rd) | |||
| 2383 | print_rd_rules(rd); | 1793 | print_rd_rules(rd); |
| 2384 | } | 1794 | } |
| 2385 | 1795 | ||
| 2386 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
| 2387 | static void reg_country_ie_process_debug( | ||
| 2388 | const struct ieee80211_regdomain *rd, | ||
| 2389 | const struct ieee80211_regdomain *country_ie_regdomain, | ||
| 2390 | const struct ieee80211_regdomain *intersected_rd) | ||
| 2391 | { | ||
| 2392 | printk(KERN_DEBUG "cfg80211: Received country IE:\n"); | ||
| 2393 | print_regdomain_info(country_ie_regdomain); | ||
| 2394 | printk(KERN_DEBUG "cfg80211: CRDA thinks this should applied:\n"); | ||
| 2395 | print_regdomain_info(rd); | ||
| 2396 | if (intersected_rd) { | ||
| 2397 | printk(KERN_DEBUG "cfg80211: We intersect both of these " | ||
| 2398 | "and get:\n"); | ||
| 2399 | print_regdomain_info(intersected_rd); | ||
| 2400 | return; | ||
| 2401 | } | ||
| 2402 | printk(KERN_DEBUG "cfg80211: Intersection between both failed\n"); | ||
| 2403 | } | ||
| 2404 | #else | ||
| 2405 | static inline void reg_country_ie_process_debug( | ||
| 2406 | const struct ieee80211_regdomain *rd, | ||
| 2407 | const struct ieee80211_regdomain *country_ie_regdomain, | ||
| 2408 | const struct ieee80211_regdomain *intersected_rd) | ||
| 2409 | { | ||
| 2410 | } | ||
| 2411 | #endif | ||
| 2412 | |||
| 2413 | /* Takes ownership of rd only if it doesn't fail */ | 1796 | /* Takes ownership of rd only if it doesn't fail */ |
| 2414 | static int __set_regdom(const struct ieee80211_regdomain *rd) | 1797 | static int __set_regdom(const struct ieee80211_regdomain *rd) |
| 2415 | { | 1798 | { |
| @@ -2521,34 +1904,6 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
| 2521 | return 0; | 1904 | return 0; |
| 2522 | } | 1905 | } |
| 2523 | 1906 | ||
| 2524 | /* | ||
| 2525 | * Country IE requests are handled a bit differently, we intersect | ||
| 2526 | * the country IE rd with what CRDA believes that country should have | ||
| 2527 | */ | ||
| 2528 | |||
| 2529 | /* | ||
| 2530 | * Userspace could have sent two replies with only | ||
| 2531 | * one kernel request. By the second reply we would have | ||
| 2532 | * already processed and consumed the country_ie_regdomain. | ||
| 2533 | */ | ||
| 2534 | if (!country_ie_regdomain) | ||
| 2535 | return -EALREADY; | ||
| 2536 | BUG_ON(rd == country_ie_regdomain); | ||
| 2537 | |||
| 2538 | /* | ||
| 2539 | * Intersect what CRDA returned and our what we | ||
| 2540 | * had built from the Country IE received | ||
| 2541 | */ | ||
| 2542 | |||
| 2543 | intersected_rd = regdom_intersect(rd, country_ie_regdomain); | ||
| 2544 | |||
| 2545 | reg_country_ie_process_debug(rd, | ||
| 2546 | country_ie_regdomain, | ||
| 2547 | intersected_rd); | ||
| 2548 | |||
| 2549 | kfree(country_ie_regdomain); | ||
| 2550 | country_ie_regdomain = NULL; | ||
| 2551 | |||
| 2552 | if (!intersected_rd) | 1907 | if (!intersected_rd) |
| 2553 | return -EINVAL; | 1908 | return -EINVAL; |
| 2554 | 1909 | ||
| @@ -2630,7 +1985,7 @@ out: | |||
| 2630 | mutex_unlock(®_mutex); | 1985 | mutex_unlock(®_mutex); |
| 2631 | } | 1986 | } |
| 2632 | 1987 | ||
| 2633 | int regulatory_init(void) | 1988 | int __init regulatory_init(void) |
| 2634 | { | 1989 | { |
| 2635 | int err = 0; | 1990 | int err = 0; |
| 2636 | 1991 | ||
| @@ -2676,7 +2031,7 @@ int regulatory_init(void) | |||
| 2676 | return 0; | 2031 | return 0; |
| 2677 | } | 2032 | } |
| 2678 | 2033 | ||
| 2679 | void regulatory_exit(void) | 2034 | void /* __init_or_exit */ regulatory_exit(void) |
| 2680 | { | 2035 | { |
| 2681 | struct regulatory_request *reg_request, *tmp; | 2036 | struct regulatory_request *reg_request, *tmp; |
| 2682 | struct reg_beacon *reg_beacon, *btmp; | 2037 | struct reg_beacon *reg_beacon, *btmp; |
| @@ -2688,9 +2043,6 @@ void regulatory_exit(void) | |||
| 2688 | 2043 | ||
| 2689 | reset_regdomains(); | 2044 | reset_regdomains(); |
| 2690 | 2045 | ||
| 2691 | kfree(country_ie_regdomain); | ||
| 2692 | country_ie_regdomain = NULL; | ||
| 2693 | |||
| 2694 | kfree(last_request); | 2046 | kfree(last_request); |
| 2695 | 2047 | ||
| 2696 | platform_device_unregister(reg_pdev); | 2048 | platform_device_unregister(reg_pdev); |
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index b26224a9f3bc..c4695d07af23 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
| @@ -10,7 +10,7 @@ int regulatory_hint_user(const char *alpha2); | |||
| 10 | 10 | ||
| 11 | void reg_device_remove(struct wiphy *wiphy); | 11 | void reg_device_remove(struct wiphy *wiphy); |
| 12 | 12 | ||
| 13 | int regulatory_init(void); | 13 | int __init regulatory_init(void); |
| 14 | void regulatory_exit(void); | 14 | void regulatory_exit(void); |
| 15 | 15 | ||
| 16 | int set_regdom(const struct ieee80211_regdomain *rd); | 16 | int set_regdom(const struct ieee80211_regdomain *rd); |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 58401d246bda..5ca8c7180141 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
| @@ -275,6 +275,7 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, | |||
| 275 | { | 275 | { |
| 276 | struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); | 276 | struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); |
| 277 | struct cfg80211_internal_bss *bss, *res = NULL; | 277 | struct cfg80211_internal_bss *bss, *res = NULL; |
| 278 | unsigned long now = jiffies; | ||
| 278 | 279 | ||
| 279 | spin_lock_bh(&dev->bss_lock); | 280 | spin_lock_bh(&dev->bss_lock); |
| 280 | 281 | ||
| @@ -283,6 +284,10 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, | |||
| 283 | continue; | 284 | continue; |
| 284 | if (channel && bss->pub.channel != channel) | 285 | if (channel && bss->pub.channel != channel) |
| 285 | continue; | 286 | continue; |
| 287 | /* Don't get expired BSS structs */ | ||
| 288 | if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) && | ||
| 289 | !atomic_read(&bss->hold)) | ||
| 290 | continue; | ||
| 286 | if (is_bss(&bss->pub, bssid, ssid, ssid_len)) { | 291 | if (is_bss(&bss->pub, bssid, ssid, ssid_len)) { |
| 287 | res = bss; | 292 | res = bss; |
| 288 | kref_get(&res->ref); | 293 | kref_get(&res->ref); |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 72222f0074db..a8c2d6b877ae 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
| @@ -35,7 +35,7 @@ struct cfg80211_conn { | |||
| 35 | bool auto_auth, prev_bssid_valid; | 35 | bool auto_auth, prev_bssid_valid; |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | bool cfg80211_is_all_idle(void) | 38 | static bool cfg80211_is_all_idle(void) |
| 39 | { | 39 | { |
| 40 | struct cfg80211_registered_device *rdev; | 40 | struct cfg80211_registered_device *rdev; |
| 41 | struct wireless_dev *wdev; | 41 | struct wireless_dev *wdev; |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 3416373a9c0c..0c8a1e8b7690 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
| @@ -770,8 +770,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
| 770 | return -EOPNOTSUPP; | 770 | return -EOPNOTSUPP; |
| 771 | 771 | ||
| 772 | /* if it's part of a bridge, reject changing type to station/ibss */ | 772 | /* if it's part of a bridge, reject changing type to station/ibss */ |
| 773 | if (dev->br_port && (ntype == NL80211_IFTYPE_ADHOC || | 773 | if ((dev->priv_flags & IFF_BRIDGE_PORT) && |
| 774 | ntype == NL80211_IFTYPE_STATION)) | 774 | (ntype == NL80211_IFTYPE_ADHOC || ntype == NL80211_IFTYPE_STATION)) |
| 775 | return -EBUSY; | 775 | return -EBUSY; |
| 776 | 776 | ||
| 777 | if (ntype != otype) { | 777 | if (ntype != otype) { |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 96342993cf93..bb5e0a5ecfa1 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
| @@ -829,7 +829,7 @@ int cfg80211_wext_siwtxpower(struct net_device *dev, | |||
| 829 | { | 829 | { |
| 830 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 830 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
| 831 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 831 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
| 832 | enum tx_power_setting type; | 832 | enum nl80211_tx_power_setting type; |
| 833 | int dbm = 0; | 833 | int dbm = 0; |
| 834 | 834 | ||
| 835 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) | 835 | if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) |
| @@ -852,7 +852,7 @@ int cfg80211_wext_siwtxpower(struct net_device *dev, | |||
| 852 | if (data->txpower.value < 0) | 852 | if (data->txpower.value < 0) |
| 853 | return -EINVAL; | 853 | return -EINVAL; |
| 854 | dbm = data->txpower.value; | 854 | dbm = data->txpower.value; |
| 855 | type = TX_POWER_FIXED; | 855 | type = NL80211_TX_POWER_FIXED; |
| 856 | /* TODO: do regulatory check! */ | 856 | /* TODO: do regulatory check! */ |
| 857 | } else { | 857 | } else { |
| 858 | /* | 858 | /* |
| @@ -860,10 +860,10 @@ int cfg80211_wext_siwtxpower(struct net_device *dev, | |||
| 860 | * passed in from userland. | 860 | * passed in from userland. |
| 861 | */ | 861 | */ |
| 862 | if (data->txpower.value < 0) { | 862 | if (data->txpower.value < 0) { |
| 863 | type = TX_POWER_AUTOMATIC; | 863 | type = NL80211_TX_POWER_AUTOMATIC; |
| 864 | } else { | 864 | } else { |
| 865 | dbm = data->txpower.value; | 865 | dbm = data->txpower.value; |
| 866 | type = TX_POWER_LIMITED; | 866 | type = NL80211_TX_POWER_LIMITED; |
| 867 | } | 867 | } |
| 868 | } | 868 | } |
| 869 | } else { | 869 | } else { |
| @@ -872,7 +872,7 @@ int cfg80211_wext_siwtxpower(struct net_device *dev, | |||
| 872 | return 0; | 872 | return 0; |
| 873 | } | 873 | } |
| 874 | 874 | ||
| 875 | return rdev->ops->set_tx_power(wdev->wiphy, type, dbm); | 875 | return rdev->ops->set_tx_power(wdev->wiphy, type, DBM_TO_MBM(dbm)); |
| 876 | } | 876 | } |
| 877 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower); | 877 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower); |
| 878 | 878 | ||
| @@ -1471,6 +1471,7 @@ int cfg80211_wext_siwpmksa(struct net_device *dev, | |||
| 1471 | return -EOPNOTSUPP; | 1471 | return -EOPNOTSUPP; |
| 1472 | } | 1472 | } |
| 1473 | } | 1473 | } |
| 1474 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwpmksa); | ||
| 1474 | 1475 | ||
| 1475 | static const iw_handler cfg80211_handlers[] = { | 1476 | static const iw_handler cfg80211_handlers[] = { |
| 1476 | [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname, | 1477 | [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname, |
