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>
This commit is contained in:
Johannes Berg 2015-10-15 09:25:18 +02:00
Родитель 922ec58c70
Коммит b686303691
3 изменённых файлов: 114 добавлений и 73 удалений

Просмотреть файл

@ -174,6 +174,16 @@ config CFG80211_INTERNAL_REGDB
Most distributions have a CRDA package. So if unsure, say N. Most distributions have a CRDA package. So if unsure, say N.
config CFG80211_CRDA_SUPPORT
bool "support CRDA" if CFG80211_INTERNAL_REGDB
default y
depends on CFG80211
help
You should enable this option unless you know for sure you have no
need for it, for example when using internal regdb (above.)
If unsure, say Y.
config CFG80211_WEXT config CFG80211_WEXT
bool "cfg80211 wireless extensions compatibility" if !CFG80211_WEXT_EXPORT bool "cfg80211 wireless extensions compatibility" if !CFG80211_WEXT_EXPORT
depends on CFG80211 depends on CFG80211

Просмотреть файл

@ -4944,56 +4944,6 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
return err; return err;
} }
static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
[NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
[NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
[NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
[NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
[NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
[NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
};
static int parse_reg_rule(struct nlattr *tb[],
struct ieee80211_reg_rule *reg_rule)
{
struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
return -EINVAL;
if (!tb[NL80211_ATTR_FREQ_RANGE_START])
return -EINVAL;
if (!tb[NL80211_ATTR_FREQ_RANGE_END])
return -EINVAL;
if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
return -EINVAL;
if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
return -EINVAL;
reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
freq_range->start_freq_khz =
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
freq_range->end_freq_khz =
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
freq_range->max_bandwidth_khz =
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
power_rule->max_eirp =
nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
power_rule->max_antenna_gain =
nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
if (tb[NL80211_ATTR_DFS_CAC_TIME])
reg_rule->dfs_cac_ms =
nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
return 0;
}
static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
{ {
char *data = NULL; char *data = NULL;
@ -5625,6 +5575,57 @@ out_err:
return err; return err;
} }
#ifdef CONFIG_CFG80211_CRDA_SUPPORT
static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
[NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
[NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
[NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
[NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
[NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
[NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
};
static int parse_reg_rule(struct nlattr *tb[],
struct ieee80211_reg_rule *reg_rule)
{
struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
return -EINVAL;
if (!tb[NL80211_ATTR_FREQ_RANGE_START])
return -EINVAL;
if (!tb[NL80211_ATTR_FREQ_RANGE_END])
return -EINVAL;
if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
return -EINVAL;
if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
return -EINVAL;
reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
freq_range->start_freq_khz =
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
freq_range->end_freq_khz =
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
freq_range->max_bandwidth_khz =
nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
power_rule->max_eirp =
nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
power_rule->max_antenna_gain =
nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
if (tb[NL80211_ATTR_DFS_CAC_TIME])
reg_rule->dfs_cac_ms =
nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
return 0;
}
static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
{ {
struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; 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)
kfree(rd); kfree(rd);
return r; return r;
} }
#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
static int validate_scan_freqs(struct nlattr *freqs) static int validate_scan_freqs(struct nlattr *freqs)
{ {
@ -10895,6 +10897,7 @@ static const struct genl_ops nl80211_ops[] = {
.internal_flags = NL80211_FLAG_NEED_RTNL, .internal_flags = NL80211_FLAG_NEED_RTNL,
/* can be retrieved by unprivileged users */ /* can be retrieved by unprivileged users */
}, },
#ifdef CONFIG_CFG80211_CRDA_SUPPORT
{ {
.cmd = NL80211_CMD_SET_REG, .cmd = NL80211_CMD_SET_REG,
.doit = nl80211_set_reg, .doit = nl80211_set_reg,
@ -10902,6 +10905,7 @@ static const struct genl_ops nl80211_ops[] = {
.flags = GENL_ADMIN_PERM, .flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_RTNL, .internal_flags = NL80211_FLAG_NEED_RTNL,
}, },
#endif
{ {
.cmd = NL80211_CMD_REQ_SET_REG, .cmd = NL80211_CMD_REQ_SET_REG,
.doit = nl80211_req_set_reg, .doit = nl80211_req_set_reg,

Просмотреть файл

@ -135,10 +135,7 @@ static spinlock_t reg_indoor_lock;
/* Used to track the userspace process controlling the indoor setting */ /* Used to track the userspace process controlling the indoor setting */
static u32 reg_is_indoor_portid; static u32 reg_is_indoor_portid;
/* Max number of consecutive attempts to communicate with CRDA */ static void restore_regulatory_settings(bool reset_user);
#define REG_MAX_CRDA_TIMEOUTS 10
static u32 reg_crda_timeouts;
static const struct ieee80211_regdomain *get_cfg80211_regdom(void) static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
{ {
@ -226,9 +223,6 @@ static DECLARE_DELAYED_WORK(reg_check_chans, reg_check_chans_work);
static void reg_todo(struct work_struct *work); static void reg_todo(struct work_struct *work);
static DECLARE_WORK(reg_work, reg_todo); static DECLARE_WORK(reg_work, reg_todo);
static void reg_timeout_work(struct work_struct *work);
static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work);
/* We keep a static world regulatory domain in case of the absence of CRDA */ /* We keep a static world regulatory domain in case of the absence of CRDA */
static const struct ieee80211_regdomain world_regdom = { static const struct ieee80211_regdomain world_regdom = {
.n_reg_rules = 8, .n_reg_rules = 8,
@ -533,6 +527,39 @@ static inline int reg_regdb_query(const char *alpha2)
} }
#endif /* CONFIG_CFG80211_INTERNAL_REGDB */ #endif /* CONFIG_CFG80211_INTERNAL_REGDB */
#ifdef CONFIG_CFG80211_CRDA_SUPPORT
/* Max number of consecutive attempts to communicate with CRDA */
#define REG_MAX_CRDA_TIMEOUTS 10
static u32 reg_crda_timeouts;
static void crda_timeout_work(struct work_struct *work);
static DECLARE_DELAYED_WORK(crda_timeout, crda_timeout_work);
static void crda_timeout_work(struct work_struct *work)
{
REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
rtnl_lock();
reg_crda_timeouts++;
restore_regulatory_settings(true);
rtnl_unlock();
}
static void cancel_crda_timeout(void)
{
cancel_delayed_work(&crda_timeout);
}
static void cancel_crda_timeout_sync(void)
{
cancel_delayed_work_sync(&crda_timeout);
}
static void reset_crda_timeouts(void)
{
reg_crda_timeouts = 0;
}
/* /*
* This lets us keep regulatory code which is updated on a regulatory * This lets us keep regulatory code which is updated on a regulatory
* basis in userspace. * basis in userspace.
@ -562,9 +589,18 @@ static int call_crda(const char *alpha2)
return ret; return ret;
queue_delayed_work(system_power_efficient_wq, queue_delayed_work(system_power_efficient_wq,
&reg_timeout, msecs_to_jiffies(3142)); &crda_timeout, msecs_to_jiffies(3142));
return 0; return 0;
} }
#else
static inline void cancel_crda_timeout(void) {}
static inline void cancel_crda_timeout_sync(void) {}
static inline void reset_crda_timeouts(void) {}
static inline int call_crda(const char *alpha2)
{
return -ENODATA;
}
#endif /* CONFIG_CFG80211_CRDA_SUPPORT */
static bool reg_query_database(struct regulatory_request *request) static bool reg_query_database(struct regulatory_request *request)
{ {
@ -1856,7 +1892,7 @@ static void reg_set_request_processed(void)
need_more_processing = true; need_more_processing = true;
spin_unlock(&reg_requests_lock); spin_unlock(&reg_requests_lock);
cancel_delayed_work(&reg_timeout); cancel_crda_timeout();
if (need_more_processing) if (need_more_processing)
schedule_work(&reg_work); schedule_work(&reg_work);
@ -2355,7 +2391,7 @@ int regulatory_hint_user(const char *alpha2,
request->user_reg_hint_type = user_reg_hint_type; request->user_reg_hint_type = user_reg_hint_type;
/* Allow calling CRDA again */ /* Allow calling CRDA again */
reg_crda_timeouts = 0; reset_crda_timeouts();
queue_regulatory_request(request); queue_regulatory_request(request);
@ -2427,7 +2463,7 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
request->initiator = NL80211_REGDOM_SET_BY_DRIVER; request->initiator = NL80211_REGDOM_SET_BY_DRIVER;
/* Allow calling CRDA again */ /* Allow calling CRDA again */
reg_crda_timeouts = 0; reset_crda_timeouts();
queue_regulatory_request(request); queue_regulatory_request(request);
@ -2483,7 +2519,7 @@ void regulatory_hint_country_ie(struct wiphy *wiphy, enum ieee80211_band band,
request->country_ie_env = env; request->country_ie_env = env;
/* Allow calling CRDA again */ /* Allow calling CRDA again */
reg_crda_timeouts = 0; reset_crda_timeouts();
queue_regulatory_request(request); queue_regulatory_request(request);
request = NULL; request = NULL;
@ -2970,7 +3006,7 @@ int set_regdom(const struct ieee80211_regdomain *rd,
} }
if (regd_src == REGD_SOURCE_CRDA) if (regd_src == REGD_SOURCE_CRDA)
reg_crda_timeouts = 0; reset_crda_timeouts();
lr = get_last_request(); lr = get_last_request();
@ -3127,15 +3163,6 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy)
lr->country_ie_env = ENVIRON_ANY; lr->country_ie_env = ENVIRON_ANY;
} }
static void reg_timeout_work(struct work_struct *work)
{
REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
rtnl_lock();
reg_crda_timeouts++;
restore_regulatory_settings(true);
rtnl_unlock();
}
/* /*
* See http://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii, for * See http://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii, for
* UNII band definitions * UNII band definitions
@ -3221,7 +3248,7 @@ void regulatory_exit(void)
struct reg_beacon *reg_beacon, *btmp; struct reg_beacon *reg_beacon, *btmp;
cancel_work_sync(&reg_work); cancel_work_sync(&reg_work);
cancel_delayed_work_sync(&reg_timeout); cancel_crda_timeout_sync();
cancel_delayed_work_sync(&reg_check_chans); cancel_delayed_work_sync(&reg_check_chans);
/* Lock to suppress warnings */ /* Lock to suppress warnings */