aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-12-06 09:47:38 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-01-03 07:01:29 -0500
commit458f4f9e960b9a3b674c4b87d996eef186b1fe83 (patch)
treefebf655badc2a045b3aaaf63271226729c76e325 /net/wireless/nl80211.c
parent379b82f4c9dc6e67bf61aa61b096c06a2f320f60 (diff)
regulatory: use RCU to protect global and wiphy regdomains
To simplify the locking and not require cfg80211_mutex (which nl80211 uses to access the global regdomain) and also to make it possible for drivers to access their wiphy->regd safely, use RCU to protect these pointers. Acked-by: Luis R. Rodriguez <mcgrof@do-not-panic.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c35
1 files changed, 18 insertions, 17 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index b387deaf1132..b3cf7cc0d4a1 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3787,12 +3787,8 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
3787 * window between nl80211_init() and regulatory_init(), if that is 3787 * window between nl80211_init() and regulatory_init(), if that is
3788 * even possible. 3788 * even possible.
3789 */ 3789 */
3790 mutex_lock(&cfg80211_mutex); 3790 if (unlikely(!rcu_access_pointer(cfg80211_regdomain)))
3791 if (unlikely(!cfg80211_regdomain)) {
3792 mutex_unlock(&cfg80211_mutex);
3793 return -EINPROGRESS; 3791 return -EINPROGRESS;
3794 }
3795 mutex_unlock(&cfg80211_mutex);
3796 3792
3797 if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) 3793 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
3798 return -EINVAL; 3794 return -EINVAL;
@@ -4152,6 +4148,7 @@ static int nl80211_update_mesh_config(struct sk_buff *skb,
4152 4148
4153static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) 4149static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
4154{ 4150{
4151 const struct ieee80211_regdomain *regdom;
4155 struct sk_buff *msg; 4152 struct sk_buff *msg;
4156 void *hdr = NULL; 4153 void *hdr = NULL;
4157 struct nlattr *nl_reg_rules; 4154 struct nlattr *nl_reg_rules;
@@ -4174,35 +4171,36 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
4174 if (!hdr) 4171 if (!hdr)
4175 goto put_failure; 4172 goto put_failure;
4176 4173
4177 if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2,
4178 cfg80211_regdomain->alpha2) ||
4179 (cfg80211_regdomain->dfs_region &&
4180 nla_put_u8(msg, NL80211_ATTR_DFS_REGION,
4181 cfg80211_regdomain->dfs_region)))
4182 goto nla_put_failure;
4183
4184 if (reg_last_request_cell_base() && 4174 if (reg_last_request_cell_base() &&
4185 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, 4175 nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
4186 NL80211_USER_REG_HINT_CELL_BASE)) 4176 NL80211_USER_REG_HINT_CELL_BASE))
4187 goto nla_put_failure; 4177 goto nla_put_failure;
4188 4178
4179 rcu_read_lock();
4180 regdom = rcu_dereference(cfg80211_regdomain);
4181
4182 if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) ||
4183 (regdom->dfs_region &&
4184 nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region)))
4185 goto nla_put_failure_rcu;
4186
4189 nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); 4187 nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
4190 if (!nl_reg_rules) 4188 if (!nl_reg_rules)
4191 goto nla_put_failure; 4189 goto nla_put_failure_rcu;
4192 4190
4193 for (i = 0; i < cfg80211_regdomain->n_reg_rules; i++) { 4191 for (i = 0; i < regdom->n_reg_rules; i++) {
4194 struct nlattr *nl_reg_rule; 4192 struct nlattr *nl_reg_rule;
4195 const struct ieee80211_reg_rule *reg_rule; 4193 const struct ieee80211_reg_rule *reg_rule;
4196 const struct ieee80211_freq_range *freq_range; 4194 const struct ieee80211_freq_range *freq_range;
4197 const struct ieee80211_power_rule *power_rule; 4195 const struct ieee80211_power_rule *power_rule;
4198 4196
4199 reg_rule = &cfg80211_regdomain->reg_rules[i]; 4197 reg_rule = &regdom->reg_rules[i];
4200 freq_range = &reg_rule->freq_range; 4198 freq_range = &reg_rule->freq_range;
4201 power_rule = &reg_rule->power_rule; 4199 power_rule = &reg_rule->power_rule;
4202 4200
4203 nl_reg_rule = nla_nest_start(msg, i); 4201 nl_reg_rule = nla_nest_start(msg, i);
4204 if (!nl_reg_rule) 4202 if (!nl_reg_rule)
4205 goto nla_put_failure; 4203 goto nla_put_failure_rcu;
4206 4204
4207 if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS, 4205 if (nla_put_u32(msg, NL80211_ATTR_REG_RULE_FLAGS,
4208 reg_rule->flags) || 4206 reg_rule->flags) ||
@@ -4216,10 +4214,11 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
4216 power_rule->max_antenna_gain) || 4214 power_rule->max_antenna_gain) ||
4217 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, 4215 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
4218 power_rule->max_eirp)) 4216 power_rule->max_eirp))
4219 goto nla_put_failure; 4217 goto nla_put_failure_rcu;
4220 4218
4221 nla_nest_end(msg, nl_reg_rule); 4219 nla_nest_end(msg, nl_reg_rule);
4222 } 4220 }
4221 rcu_read_unlock();
4223 4222
4224 nla_nest_end(msg, nl_reg_rules); 4223 nla_nest_end(msg, nl_reg_rules);
4225 4224
@@ -4227,6 +4226,8 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
4227 err = genlmsg_reply(msg, info); 4226 err = genlmsg_reply(msg, info);
4228 goto out; 4227 goto out;
4229 4228
4229nla_put_failure_rcu:
4230 rcu_read_unlock();
4230nla_put_failure: 4231nla_put_failure:
4231 genlmsg_cancel(msg, hdr); 4232 genlmsg_cancel(msg, hdr);
4232put_failure: 4233put_failure: