diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-12-06 09:47:38 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-01-03 07:01:29 -0500 |
commit | 458f4f9e960b9a3b674c4b87d996eef186b1fe83 (patch) | |
tree | febf655badc2a045b3aaaf63271226729c76e325 /net/wireless/nl80211.c | |
parent | 379b82f4c9dc6e67bf61aa61b096c06a2f320f60 (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.c | 35 |
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 | ||
4153 | static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | 4149 | static 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 = ®dom->reg_rules[i]; |
4200 | freq_range = ®_rule->freq_range; | 4198 | freq_range = ®_rule->freq_range; |
4201 | power_rule = ®_rule->power_rule; | 4199 | power_rule = ®_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 | ||
4229 | nla_put_failure_rcu: | ||
4230 | rcu_read_unlock(); | ||
4230 | nla_put_failure: | 4231 | nla_put_failure: |
4231 | genlmsg_cancel(msg, hdr); | 4232 | genlmsg_cancel(msg, hdr); |
4232 | put_failure: | 4233 | put_failure: |