aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/nl80211.h48
-rw-r--r--net/wireless/core.c11
-rw-r--r--net/wireless/nl80211.c62
-rw-r--r--net/wireless/nl80211.h5
-rw-r--r--net/wireless/reg.c13
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 */
735enum 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;
369out_unlock: 380out_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 = {
2739static struct genl_multicast_group nl80211_scan_mcgrp = { 2739static struct genl_multicast_group nl80211_scan_mcgrp = {
2740 .name = "scan", 2740 .name = "scan",
2741}; 2741};
2742static 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 */
2828void 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
2874nla_put_failure:
2875 genlmsg_cancel(msg, hdr);
2876 nlmsg_free(msg);
2877}
2878
2821/* initialisation/exit functions */ 2879/* initialisation/exit functions */
2822 2880
2823int nl80211_init(void) 2881int 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);
12extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, 12extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
13 struct net_device *netdev); 13 struct net_device *netdev);
14extern void nl80211_send_reg_change_event(struct regulatory_request *request);
14#else 15#else
15static inline int nl80211_init(void) 16static 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{}
35static inline void
36nl80211_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 */
46static struct regulatory_request *last_request; 47static 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