aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-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
4 files changed, 90 insertions, 1 deletions
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