diff options
author | Johannes Berg <johannes.berg@intel.com> | 2015-10-15 03:25:18 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2015-10-16 03:15:39 -0400 |
commit | b68630369167a7fd2c4c3d1be96430defc59fb9a (patch) | |
tree | 3caad5e514413a691ae2c90380a5b35bf38456a9 | |
parent | 922ec58c70cd4a1065dd3c9f94e845dc1348b533 (diff) |
cfg80211: reg: make CRDA support optional
If there's a built-in regulatory database, there may be little point
in also calling out to CRDA and failing if the system is configured
that way. Allow removing CRDA support to save ~1K kernel size.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | net/wireless/Kconfig | 10 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 104 | ||||
-rw-r--r-- | net/wireless/reg.c | 73 |
3 files changed, 114 insertions, 73 deletions
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 4f5543dd2524..da72ed32f143 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig | |||
@@ -174,6 +174,16 @@ config CFG80211_INTERNAL_REGDB | |||
174 | 174 | ||
175 | Most distributions have a CRDA package. So if unsure, say N. | 175 | Most distributions have a CRDA package. So if unsure, say N. |
176 | 176 | ||
177 | config CFG80211_CRDA_SUPPORT | ||
178 | bool "support CRDA" if CFG80211_INTERNAL_REGDB | ||
179 | default y | ||
180 | depends on CFG80211 | ||
181 | help | ||
182 | You should enable this option unless you know for sure you have no | ||
183 | need for it, for example when using internal regdb (above.) | ||
184 | |||
185 | If unsure, say Y. | ||
186 | |||
177 | config CFG80211_WEXT | 187 | config CFG80211_WEXT |
178 | bool "cfg80211 wireless extensions compatibility" if !CFG80211_WEXT_EXPORT | 188 | bool "cfg80211 wireless extensions compatibility" if !CFG80211_WEXT_EXPORT |
179 | depends on CFG80211 | 189 | depends on CFG80211 |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 28c29e7da749..d693c9d031fc 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -4944,56 +4944,6 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
4944 | return err; | 4944 | return err; |
4945 | } | 4945 | } |
4946 | 4946 | ||
4947 | static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { | ||
4948 | [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 }, | ||
4949 | [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 }, | ||
4950 | [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 }, | ||
4951 | [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, | ||
4952 | [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, | ||
4953 | [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, | ||
4954 | [NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 }, | ||
4955 | }; | ||
4956 | |||
4957 | static int parse_reg_rule(struct nlattr *tb[], | ||
4958 | struct ieee80211_reg_rule *reg_rule) | ||
4959 | { | ||
4960 | struct ieee80211_freq_range *freq_range = ®_rule->freq_range; | ||
4961 | struct ieee80211_power_rule *power_rule = ®_rule->power_rule; | ||
4962 | |||
4963 | if (!tb[NL80211_ATTR_REG_RULE_FLAGS]) | ||
4964 | return -EINVAL; | ||
4965 | if (!tb[NL80211_ATTR_FREQ_RANGE_START]) | ||
4966 | return -EINVAL; | ||
4967 | if (!tb[NL80211_ATTR_FREQ_RANGE_END]) | ||
4968 | return -EINVAL; | ||
4969 | if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) | ||
4970 | return -EINVAL; | ||
4971 | if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) | ||
4972 | return -EINVAL; | ||
4973 | |||
4974 | reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]); | ||
4975 | |||
4976 | freq_range->start_freq_khz = | ||
4977 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); | ||
4978 | freq_range->end_freq_khz = | ||
4979 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); | ||
4980 | freq_range->max_bandwidth_khz = | ||
4981 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); | ||
4982 | |||
4983 | power_rule->max_eirp = | ||
4984 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); | ||
4985 | |||
4986 | if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]) | ||
4987 | power_rule->max_antenna_gain = | ||
4988 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]); | ||
4989 | |||
4990 | if (tb[NL80211_ATTR_DFS_CAC_TIME]) | ||
4991 | reg_rule->dfs_cac_ms = | ||
4992 | nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]); | ||
4993 | |||
4994 | return 0; | ||
4995 | } | ||
4996 | |||
4997 | static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | 4947 | static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) |
4998 | { | 4948 | { |
4999 | char *data = NULL; | 4949 | char *data = NULL; |
@@ -5625,6 +5575,57 @@ out_err: | |||
5625 | return err; | 5575 | return err; |
5626 | } | 5576 | } |
5627 | 5577 | ||
5578 | #ifdef CONFIG_CFG80211_CRDA_SUPPORT | ||
5579 | static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = { | ||
5580 | [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 }, | ||
5581 | [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 }, | ||
5582 | [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 }, | ||
5583 | [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, | ||
5584 | [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, | ||
5585 | [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, | ||
5586 | [NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 }, | ||
5587 | }; | ||
5588 | |||
5589 | static int parse_reg_rule(struct nlattr *tb[], | ||
5590 | struct ieee80211_reg_rule *reg_rule) | ||
5591 | { | ||
5592 | struct ieee80211_freq_range *freq_range = ®_rule->freq_range; | ||
5593 | struct ieee80211_power_rule *power_rule = ®_rule->power_rule; | ||
5594 | |||
5595 | if (!tb[NL80211_ATTR_REG_RULE_FLAGS]) | ||
5596 | return -EINVAL; | ||
5597 | if (!tb[NL80211_ATTR_FREQ_RANGE_START]) | ||
5598 | return -EINVAL; | ||
5599 | if (!tb[NL80211_ATTR_FREQ_RANGE_END]) | ||
5600 | return -EINVAL; | ||
5601 | if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) | ||
5602 | return -EINVAL; | ||
5603 | if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) | ||
5604 | return -EINVAL; | ||
5605 | |||
5606 | reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]); | ||
5607 | |||
5608 | freq_range->start_freq_khz = | ||
5609 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]); | ||
5610 | freq_range->end_freq_khz = | ||
5611 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]); | ||
5612 | freq_range->max_bandwidth_khz = | ||
5613 | nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]); | ||
5614 | |||
5615 | power_rule->max_eirp = | ||
5616 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]); | ||
5617 | |||
5618 | if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]) | ||
5619 | power_rule->max_antenna_gain = | ||
5620 | nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]); | ||
5621 | |||
5622 | if (tb[NL80211_ATTR_DFS_CAC_TIME]) | ||
5623 | reg_rule->dfs_cac_ms = | ||
5624 | nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]); | ||
5625 | |||
5626 | return 0; | ||
5627 | } | ||
5628 | |||
5628 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | 5629 | static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) |
5629 | { | 5630 | { |
5630 | struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; | 5631 | struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; |
@@ -5701,6 +5702,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
5701 | kfree(rd); | 5702 | kfree(rd); |
5702 | return r; | 5703 | return r; |
5703 | } | 5704 | } |
5705 | #endif /* CONFIG_CFG80211_CRDA_SUPPORT */ | ||
5704 | 5706 | ||
5705 | static int validate_scan_freqs(struct nlattr *freqs) | 5707 | static int validate_scan_freqs(struct nlattr *freqs) |
5706 | { | 5708 | { |
@@ -10895,6 +10897,7 @@ static const struct genl_ops nl80211_ops[] = { | |||
10895 | .internal_flags = NL80211_FLAG_NEED_RTNL, | 10897 | .internal_flags = NL80211_FLAG_NEED_RTNL, |
10896 | /* can be retrieved by unprivileged users */ | 10898 | /* can be retrieved by unprivileged users */ |
10897 | }, | 10899 | }, |
10900 | #ifdef CONFIG_CFG80211_CRDA_SUPPORT | ||
10898 | { | 10901 | { |
10899 | .cmd = NL80211_CMD_SET_REG, | 10902 | .cmd = NL80211_CMD_SET_REG, |
10900 | .doit = nl80211_set_reg, | 10903 | .doit = nl80211_set_reg, |
@@ -10902,6 +10905,7 @@ static const struct genl_ops nl80211_ops[] = { | |||
10902 | .flags = GENL_ADMIN_PERM, | 10905 | .flags = GENL_ADMIN_PERM, |
10903 | .internal_flags = NL80211_FLAG_NEED_RTNL, | 10906 | .internal_flags = NL80211_FLAG_NEED_RTNL, |
10904 | }, | 10907 | }, |
10908 | #endif | ||
10905 | { | 10909 | { |
10906 | .cmd = NL80211_CMD_REQ_SET_REG, | 10910 | .cmd = NL80211_CMD_REQ_SET_REG, |
10907 | .doit = nl80211_req_set_reg, | 10911 | .doit = nl80211_req_set_reg, |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 3b3119fa87ae..55462fe04d5d 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -135,10 +135,7 @@ static spinlock_t reg_indoor_lock; | |||
135 | /* Used to track the userspace process controlling the indoor setting */ | 135 | /* Used to track the userspace process controlling the indoor setting */ |
136 | static u32 reg_is_indoor_portid; | 136 | static u32 reg_is_indoor_portid; |
137 | 137 | ||
138 | /* Max number of consecutive attempts to communicate with CRDA */ | 138 | static void restore_regulatory_settings(bool reset_user); |
139 | #define REG_MAX_CRDA_TIMEOUTS 10 | ||
140 | |||
141 | static u32 reg_crda_timeouts; | ||
142 | 139 | ||
143 | static const struct ieee80211_regdomain *get_cfg80211_regdom(void) | 140 | static const struct ieee80211_regdomain *get_cfg80211_regdom(void) |
144 | { | 141 | { |
@@ -226,9 +223,6 @@ static DECLARE_DELAYED_WORK(reg_check_chans, reg_check_chans_work); | |||
226 | static void reg_todo(struct work_struct *work); | 223 | static void reg_todo(struct work_struct *work); |
227 | static DECLARE_WORK(reg_work, reg_todo); | 224 | static DECLARE_WORK(reg_work, reg_todo); |
228 | 225 | ||
229 | static void reg_timeout_work(struct work_struct *work); | ||
230 | static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work); | ||
231 | |||
232 | /* We keep a static world regulatory domain in case of the absence of CRDA */ | 226 | /* We keep a static world regulatory domain in case of the absence of CRDA */ |
233 | static const struct ieee80211_regdomain world_regdom = { | 227 | static const struct ieee80211_regdomain world_regdom = { |
234 | .n_reg_rules = 8, | 228 | .n_reg_rules = 8, |
@@ -533,6 +527,39 @@ static inline int reg_regdb_query(const char *alpha2) | |||
533 | } | 527 | } |
534 | #endif /* CONFIG_CFG80211_INTERNAL_REGDB */ | 528 | #endif /* CONFIG_CFG80211_INTERNAL_REGDB */ |
535 | 529 | ||
530 | #ifdef CONFIG_CFG80211_CRDA_SUPPORT | ||
531 | /* Max number of consecutive attempts to communicate with CRDA */ | ||
532 | #define REG_MAX_CRDA_TIMEOUTS 10 | ||
533 | |||
534 | static u32 reg_crda_timeouts; | ||
535 | |||
536 | static void crda_timeout_work(struct work_struct *work); | ||
537 | static DECLARE_DELAYED_WORK(crda_timeout, crda_timeout_work); | ||
538 | |||
539 | static void crda_timeout_work(struct work_struct *work) | ||
540 | { | ||
541 | REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n"); | ||
542 | rtnl_lock(); | ||
543 | reg_crda_timeouts++; | ||
544 | restore_regulatory_settings(true); | ||
545 | rtnl_unlock(); | ||
546 | } | ||
547 | |||
548 | static void cancel_crda_timeout(void) | ||
549 | { | ||
550 | cancel_delayed_work(&crda_timeout); | ||
551 | } | ||
552 | |||
553 | static void cancel_crda_timeout_sync(void) | ||
554 | { | ||
555 | cancel_delayed_work_sync(&crda_timeout); | ||
556 | } | ||
557 | |||
558 | static void reset_crda_timeouts(void) | ||
559 | { | ||
560 | reg_crda_timeouts = 0; | ||
561 | } | ||
562 | |||
536 | /* | 563 | /* |
537 | * This lets us keep regulatory code which is updated on a regulatory | 564 | * This lets us keep regulatory code which is updated on a regulatory |
538 | * basis in userspace. | 565 | * basis in userspace. |
@@ -562,9 +589,18 @@ static int call_crda(const char *alpha2) | |||
562 | return ret; | 589 | return ret; |
563 | 590 | ||
564 | queue_delayed_work(system_power_efficient_wq, | 591 | queue_delayed_work(system_power_efficient_wq, |
565 | ®_timeout, msecs_to_jiffies(3142)); | 592 | &crda_timeout, msecs_to_jiffies(3142)); |
566 | return 0; | 593 | return 0; |
567 | } | 594 | } |
595 | #else | ||
596 | static inline void cancel_crda_timeout(void) {} | ||
597 | static inline void cancel_crda_timeout_sync(void) {} | ||
598 | static inline void reset_crda_timeouts(void) {} | ||
599 | static inline int call_crda(const char *alpha2) | ||
600 | { | ||
601 | return -ENODATA; | ||
602 | } | ||
603 | #endif /* CONFIG_CFG80211_CRDA_SUPPORT */ | ||
568 | 604 | ||
569 | static bool reg_query_database(struct regulatory_request *request) | 605 | static bool reg_query_database(struct regulatory_request *request) |
570 | { | 606 | { |
@@ -1856,7 +1892,7 @@ static void reg_set_request_processed(void) | |||
1856 | need_more_processing = true; | 1892 | need_more_processing = true; |
1857 | spin_unlock(®_requests_lock); | 1893 | spin_unlock(®_requests_lock); |
1858 | 1894 | ||
1859 | cancel_delayed_work(®_timeout); | 1895 | cancel_crda_timeout(); |
1860 | 1896 | ||
1861 | if (need_more_processing) | 1897 | if (need_more_processing) |
1862 | schedule_work(®_work); | 1898 | schedule_work(®_work); |
@@ -2355,7 +2391,7 @@ int regulatory_hint_user(const char *alpha2, | |||
2355 | request->user_reg_hint_type = user_reg_hint_type; | 2391 | request->user_reg_hint_type = user_reg_hint_type; |
2356 | 2392 | ||
2357 | /* Allow calling CRDA again */ | 2393 | /* Allow calling CRDA again */ |
2358 | reg_crda_timeouts = 0; | 2394 | reset_crda_timeouts(); |
2359 | 2395 | ||
2360 | queue_regulatory_request(request); | 2396 | queue_regulatory_request(request); |
2361 | 2397 | ||
@@ -2427,7 +2463,7 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2) | |||
2427 | request->initiator = NL80211_REGDOM_SET_BY_DRIVER; | 2463 | request->initiator = NL80211_REGDOM_SET_BY_DRIVER; |
2428 | 2464 | ||
2429 | /* Allow calling CRDA again */ | 2465 | /* Allow calling CRDA again */ |
2430 | reg_crda_timeouts = 0; | 2466 | reset_crda_timeouts(); |
2431 | 2467 | ||
2432 | queue_regulatory_request(request); | 2468 | queue_regulatory_request(request); |
2433 | 2469 | ||
@@ -2483,7 +2519,7 @@ void regulatory_hint_country_ie(struct wiphy *wiphy, enum ieee80211_band band, | |||
2483 | request->country_ie_env = env; | 2519 | request->country_ie_env = env; |
2484 | 2520 | ||
2485 | /* Allow calling CRDA again */ | 2521 | /* Allow calling CRDA again */ |
2486 | reg_crda_timeouts = 0; | 2522 | reset_crda_timeouts(); |
2487 | 2523 | ||
2488 | queue_regulatory_request(request); | 2524 | queue_regulatory_request(request); |
2489 | request = NULL; | 2525 | request = NULL; |
@@ -2970,7 +3006,7 @@ int set_regdom(const struct ieee80211_regdomain *rd, | |||
2970 | } | 3006 | } |
2971 | 3007 | ||
2972 | if (regd_src == REGD_SOURCE_CRDA) | 3008 | if (regd_src == REGD_SOURCE_CRDA) |
2973 | reg_crda_timeouts = 0; | 3009 | reset_crda_timeouts(); |
2974 | 3010 | ||
2975 | lr = get_last_request(); | 3011 | lr = get_last_request(); |
2976 | 3012 | ||
@@ -3127,15 +3163,6 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy) | |||
3127 | lr->country_ie_env = ENVIRON_ANY; | 3163 | lr->country_ie_env = ENVIRON_ANY; |
3128 | } | 3164 | } |
3129 | 3165 | ||
3130 | static void reg_timeout_work(struct work_struct *work) | ||
3131 | { | ||
3132 | REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n"); | ||
3133 | rtnl_lock(); | ||
3134 | reg_crda_timeouts++; | ||
3135 | restore_regulatory_settings(true); | ||
3136 | rtnl_unlock(); | ||
3137 | } | ||
3138 | |||
3139 | /* | 3166 | /* |
3140 | * See http://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii, for | 3167 | * See http://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii, for |
3141 | * UNII band definitions | 3168 | * UNII band definitions |
@@ -3221,7 +3248,7 @@ void regulatory_exit(void) | |||
3221 | struct reg_beacon *reg_beacon, *btmp; | 3248 | struct reg_beacon *reg_beacon, *btmp; |
3222 | 3249 | ||
3223 | cancel_work_sync(®_work); | 3250 | cancel_work_sync(®_work); |
3224 | cancel_delayed_work_sync(®_timeout); | 3251 | cancel_crda_timeout_sync(); |
3225 | cancel_delayed_work_sync(®_check_chans); | 3252 | cancel_delayed_work_sync(®_check_chans); |
3226 | 3253 | ||
3227 | /* Lock to suppress warnings */ | 3254 | /* Lock to suppress warnings */ |