diff options
-rw-r--r-- | include/linux/nl80211.h | 48 | ||||
-rw-r--r-- | net/wireless/core.c | 11 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 62 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 5 | ||||
-rw-r--r-- | net/wireless/reg.c | 13 |
5 files changed, 138 insertions, 1 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index c0fd432b57dc..f33aa08dd9b3 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -150,6 +150,17 @@ | |||
150 | * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, | 150 | * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, |
151 | * partial scan results may be available | 151 | * partial scan results may be available |
152 | * | 152 | * |
153 | * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain | ||
154 | * has been changed and provides details of the request information | ||
155 | * that caused the change such as who initiated the regulatory request | ||
156 | * (%NL80211_ATTR_REG_INITIATOR), the wiphy_idx | ||
157 | * (%NL80211_ATTR_REG_ALPHA2) on which the request was made from if | ||
158 | * the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or | ||
159 | * %NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain | ||
160 | * set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is | ||
161 | * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on | ||
162 | * to (%NL80211_ATTR_REG_ALPHA2). | ||
163 | * | ||
153 | * @NL80211_CMD_MAX: highest used command number | 164 | * @NL80211_CMD_MAX: highest used command number |
154 | * @__NL80211_CMD_AFTER_LAST: internal use | 165 | * @__NL80211_CMD_AFTER_LAST: internal use |
155 | */ | 166 | */ |
@@ -204,6 +215,8 @@ enum nl80211_commands { | |||
204 | NL80211_CMD_NEW_SCAN_RESULTS, | 215 | NL80211_CMD_NEW_SCAN_RESULTS, |
205 | NL80211_CMD_SCAN_ABORTED, | 216 | NL80211_CMD_SCAN_ABORTED, |
206 | 217 | ||
218 | NL80211_CMD_REG_CHANGE, | ||
219 | |||
207 | /* add new commands above here */ | 220 | /* add new commands above here */ |
208 | 221 | ||
209 | /* used to define NL80211_CMD_MAX below */ | 222 | /* used to define NL80211_CMD_MAX below */ |
@@ -218,6 +231,8 @@ enum nl80211_commands { | |||
218 | #define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS | 231 | #define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS |
219 | #define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE | 232 | #define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE |
220 | 233 | ||
234 | #define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE | ||
235 | |||
221 | /** | 236 | /** |
222 | * enum nl80211_attrs - nl80211 netlink attributes | 237 | * enum nl80211_attrs - nl80211 netlink attributes |
223 | * | 238 | * |
@@ -329,6 +344,11 @@ enum nl80211_commands { | |||
329 | * messages carried the same generation number) | 344 | * messages carried the same generation number) |
330 | * @NL80211_ATTR_BSS: scan result BSS | 345 | * @NL80211_ATTR_BSS: scan result BSS |
331 | * | 346 | * |
347 | * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain | ||
348 | * currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_* | ||
349 | * @NL80211_ATTR_REG_TYPE: indicates the type of the regulatory domain currently | ||
350 | * set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*) | ||
351 | * | ||
332 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 352 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
333 | * @__NL80211_ATTR_AFTER_LAST: internal use | 353 | * @__NL80211_ATTR_AFTER_LAST: internal use |
334 | */ | 354 | */ |
@@ -403,6 +423,9 @@ enum nl80211_attrs { | |||
403 | NL80211_ATTR_SCAN_GENERATION, | 423 | NL80211_ATTR_SCAN_GENERATION, |
404 | NL80211_ATTR_BSS, | 424 | NL80211_ATTR_BSS, |
405 | 425 | ||
426 | NL80211_ATTR_REG_INITIATOR, | ||
427 | NL80211_ATTR_REG_TYPE, | ||
428 | |||
406 | /* add attributes here, update the policy in nl80211.c */ | 429 | /* add attributes here, update the policy in nl80211.c */ |
407 | 430 | ||
408 | __NL80211_ATTR_AFTER_LAST, | 431 | __NL80211_ATTR_AFTER_LAST, |
@@ -420,6 +443,8 @@ enum nl80211_attrs { | |||
420 | #define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE | 443 | #define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE |
421 | #define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE | 444 | #define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE |
422 | #define NL80211_ATTR_IE NL80211_ATTR_IE | 445 | #define NL80211_ATTR_IE NL80211_ATTR_IE |
446 | #define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR | ||
447 | #define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE | ||
423 | 448 | ||
424 | #define NL80211_MAX_SUPP_RATES 32 | 449 | #define NL80211_MAX_SUPP_RATES 32 |
425 | #define NL80211_MAX_SUPP_REG_RULES 32 | 450 | #define NL80211_MAX_SUPP_REG_RULES 32 |
@@ -692,6 +717,29 @@ enum nl80211_reg_initiator { | |||
692 | }; | 717 | }; |
693 | 718 | ||
694 | /** | 719 | /** |
720 | * enum nl80211_reg_type - specifies the type of regulatory domain | ||
721 | * @NL80211_REGDOM_TYPE_COUNTRY: the regulatory domain set is one that pertains | ||
722 | * to a specific country. When this is set you can count on the | ||
723 | * ISO / IEC 3166 alpha2 country code being valid. | ||
724 | * @NL80211_REGDOM_TYPE_WORLD: the regulatory set domain is the world regulatory | ||
725 | * domain. | ||
726 | * @NL80211_REGDOM_TYPE_CUSTOM_WORLD: the regulatory domain set is a custom | ||
727 | * driver specific world regulatory domain. These do not apply system-wide | ||
728 | * and are only applicable to the individual devices which have requested | ||
729 | * them to be applied. | ||
730 | * @NL80211_REGDOM_TYPE_INTERSECTION: the regulatory domain set is the product | ||
731 | * of an intersection between two regulatory domains -- the previously | ||
732 | * set regulatory domain on the system and the last accepted regulatory | ||
733 | * domain request to be processed. | ||
734 | */ | ||
735 | enum nl80211_reg_type { | ||
736 | NL80211_REGDOM_TYPE_COUNTRY, | ||
737 | NL80211_REGDOM_TYPE_WORLD, | ||
738 | NL80211_REGDOM_TYPE_CUSTOM_WORLD, | ||
739 | NL80211_REGDOM_TYPE_INTERSECTION, | ||
740 | }; | ||
741 | |||
742 | /** | ||
695 | * enum nl80211_reg_rule_attr - regulatory rule attributes | 743 | * enum nl80211_reg_rule_attr - regulatory rule attributes |
696 | * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional | 744 | * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional |
697 | * considerations for a given frequency range. These are the | 745 | * considerations for a given frequency range. These are the |
diff --git a/net/wireless/core.c b/net/wireless/core.c index c939f5ee065e..17fe39049740 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -365,6 +365,17 @@ int wiphy_register(struct wiphy *wiphy) | |||
365 | if (IS_ERR(drv->wiphy.debugfsdir)) | 365 | if (IS_ERR(drv->wiphy.debugfsdir)) |
366 | drv->wiphy.debugfsdir = NULL; | 366 | drv->wiphy.debugfsdir = NULL; |
367 | 367 | ||
368 | if (wiphy->custom_regulatory) { | ||
369 | struct regulatory_request request; | ||
370 | |||
371 | request.wiphy_idx = get_wiphy_idx(wiphy); | ||
372 | request.initiator = NL80211_REGDOM_SET_BY_DRIVER; | ||
373 | request.alpha2[0] = '9'; | ||
374 | request.alpha2[1] = '9'; | ||
375 | |||
376 | nl80211_send_reg_change_event(&request); | ||
377 | } | ||
378 | |||
368 | res = 0; | 379 | res = 0; |
369 | out_unlock: | 380 | out_unlock: |
370 | mutex_unlock(&cfg80211_mutex); | 381 | mutex_unlock(&cfg80211_mutex); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 531bb67cf502..8ac3d26014a8 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -2739,6 +2739,9 @@ static struct genl_multicast_group nl80211_config_mcgrp = { | |||
2739 | static struct genl_multicast_group nl80211_scan_mcgrp = { | 2739 | static struct genl_multicast_group nl80211_scan_mcgrp = { |
2740 | .name = "scan", | 2740 | .name = "scan", |
2741 | }; | 2741 | }; |
2742 | static struct genl_multicast_group nl80211_regulatory_mcgrp = { | ||
2743 | .name = "regulatory", | ||
2744 | }; | ||
2742 | 2745 | ||
2743 | /* notification functions */ | 2746 | /* notification functions */ |
2744 | 2747 | ||
@@ -2818,6 +2821,61 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | |||
2818 | genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); | 2821 | genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); |
2819 | } | 2822 | } |
2820 | 2823 | ||
2824 | /* | ||
2825 | * This can happen on global regulatory changes or device specific settings | ||
2826 | * based on custom world regulatory domains. | ||
2827 | */ | ||
2828 | void nl80211_send_reg_change_event(struct regulatory_request *request) | ||
2829 | { | ||
2830 | struct sk_buff *msg; | ||
2831 | void *hdr; | ||
2832 | |||
2833 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
2834 | if (!msg) | ||
2835 | return; | ||
2836 | |||
2837 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE); | ||
2838 | if (!hdr) { | ||
2839 | nlmsg_free(msg); | ||
2840 | return; | ||
2841 | } | ||
2842 | |||
2843 | /* Userspace can always count this one always being set */ | ||
2844 | NLA_PUT_U8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator); | ||
2845 | |||
2846 | if (request->alpha2[0] == '0' && request->alpha2[1] == '0') | ||
2847 | NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, | ||
2848 | NL80211_REGDOM_TYPE_WORLD); | ||
2849 | else if (request->alpha2[0] == '9' && request->alpha2[1] == '9') | ||
2850 | NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, | ||
2851 | NL80211_REGDOM_TYPE_CUSTOM_WORLD); | ||
2852 | else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') || | ||
2853 | request->intersect) | ||
2854 | NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, | ||
2855 | NL80211_REGDOM_TYPE_INTERSECTION); | ||
2856 | else { | ||
2857 | NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE, | ||
2858 | NL80211_REGDOM_TYPE_COUNTRY); | ||
2859 | NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, request->alpha2); | ||
2860 | } | ||
2861 | |||
2862 | if (wiphy_idx_valid(request->wiphy_idx)) | ||
2863 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx); | ||
2864 | |||
2865 | if (genlmsg_end(msg, hdr) < 0) { | ||
2866 | nlmsg_free(msg); | ||
2867 | return; | ||
2868 | } | ||
2869 | |||
2870 | genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_KERNEL); | ||
2871 | |||
2872 | return; | ||
2873 | |||
2874 | nla_put_failure: | ||
2875 | genlmsg_cancel(msg, hdr); | ||
2876 | nlmsg_free(msg); | ||
2877 | } | ||
2878 | |||
2821 | /* initialisation/exit functions */ | 2879 | /* initialisation/exit functions */ |
2822 | 2880 | ||
2823 | int nl80211_init(void) | 2881 | int nl80211_init(void) |
@@ -2842,6 +2900,10 @@ int nl80211_init(void) | |||
2842 | if (err) | 2900 | if (err) |
2843 | goto err_out; | 2901 | goto err_out; |
2844 | 2902 | ||
2903 | err = genl_register_mc_group(&nl80211_fam, &nl80211_regulatory_mcgrp); | ||
2904 | if (err) | ||
2905 | goto err_out; | ||
2906 | |||
2845 | return 0; | 2907 | return 0; |
2846 | err_out: | 2908 | err_out: |
2847 | genl_unregister_family(&nl80211_fam); | 2909 | genl_unregister_family(&nl80211_fam); |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 69787b621365..e65a3c38c52f 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -11,6 +11,7 @@ extern void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
11 | struct net_device *netdev); | 11 | struct net_device *netdev); |
12 | extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | 12 | extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, |
13 | struct net_device *netdev); | 13 | struct net_device *netdev); |
14 | extern void nl80211_send_reg_change_event(struct regulatory_request *request); | ||
14 | #else | 15 | #else |
15 | static inline int nl80211_init(void) | 16 | static inline int nl80211_init(void) |
16 | { | 17 | { |
@@ -31,6 +32,10 @@ static inline void nl80211_send_scan_aborted( | |||
31 | struct cfg80211_registered_device *rdev, | 32 | struct cfg80211_registered_device *rdev, |
32 | struct net_device *netdev) | 33 | struct net_device *netdev) |
33 | {} | 34 | {} |
35 | static inline void | ||
36 | nl80211_send_reg_change_event(struct regulatory_request *request) | ||
37 | { | ||
38 | } | ||
34 | #endif /* CONFIG_NL80211 */ | 39 | #endif /* CONFIG_NL80211 */ |
35 | 40 | ||
36 | #endif /* __NET_WIRELESS_NL80211_H */ | 41 | #endif /* __NET_WIRELESS_NL80211_H */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 68fde6d33dc3..eb8b8ed16155 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <net/cfg80211.h> | 41 | #include <net/cfg80211.h> |
42 | #include "core.h" | 42 | #include "core.h" |
43 | #include "reg.h" | 43 | #include "reg.h" |
44 | #include "nl80211.h" | ||
44 | 45 | ||
45 | /* Receipt of information from last regulatory request */ | 46 | /* Receipt of information from last regulatory request */ |
46 | static struct regulatory_request *last_request; | 47 | static struct regulatory_request *last_request; |
@@ -1403,8 +1404,16 @@ new_request: | |||
1403 | pending_request = NULL; | 1404 | pending_request = NULL; |
1404 | 1405 | ||
1405 | /* When r == REG_INTERSECT we do need to call CRDA */ | 1406 | /* When r == REG_INTERSECT we do need to call CRDA */ |
1406 | if (r < 0) | 1407 | if (r < 0) { |
1408 | /* | ||
1409 | * Since CRDA will not be called in this case as we already | ||
1410 | * have applied the requested regulatory domain before we just | ||
1411 | * inform userspace we have processed the request | ||
1412 | */ | ||
1413 | if (r == -EALREADY) | ||
1414 | nl80211_send_reg_change_event(last_request); | ||
1407 | return r; | 1415 | return r; |
1416 | } | ||
1408 | 1417 | ||
1409 | /* | 1418 | /* |
1410 | * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled | 1419 | * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled |
@@ -2084,6 +2093,8 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2084 | 2093 | ||
2085 | print_regdomain(cfg80211_regdomain); | 2094 | print_regdomain(cfg80211_regdomain); |
2086 | 2095 | ||
2096 | nl80211_send_reg_change_event(last_request); | ||
2097 | |||
2087 | return r; | 2098 | return r; |
2088 | } | 2099 | } |
2089 | 2100 | ||