aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJanusz Dziedzic <janusz.dziedzic@tieto.com>2014-02-21 13:46:12 -0500
committerJohannes Berg <johannes.berg@intel.com>2014-02-25 11:29:25 -0500
commit089027e57cfa79337feffdd7252c8ba0be352afa (patch)
tree076b28e399d4ae3eca61a5e1dea50057e1ebb1c0
parentfb5c96368fa306dae0f79d0078d2d4e505278204 (diff)
cfg80211: regulatory: allow getting DFS CAC time from userspace
Introduce DFS CAC time as a regd param, configured per REG_RULE and set per channel in cfg80211. DFS CAC time is close connected with regulatory database configuration. Instead of using hardcoded values, get DFS CAC time form regulatory database. Pass DFS CAC time to user mode (mainly for iw reg get, iw list, iw info). Allow setting DFS CAC time via CRDA. Add support for internal regulatory database. Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com> [rewrap commit log] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/net/cfg80211.h2
-rw-r--r--include/net/regulatory.h21
-rw-r--r--include/uapi/linux/nl80211.h6
-rw-r--r--net/wireless/genregdb.awk8
-rw-r--r--net/wireless/nl80211.c13
-rw-r--r--net/wireless/reg.c32
6 files changed, 66 insertions, 16 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 8c9ba44fb7cf..bfa9a0c7b2d7 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -151,6 +151,7 @@ enum ieee80211_channel_flags {
151 * @dfs_state: current state of this channel. Only relevant if radar is required 151 * @dfs_state: current state of this channel. Only relevant if radar is required
152 * on this channel. 152 * on this channel.
153 * @dfs_state_entered: timestamp (jiffies) when the dfs state was entered. 153 * @dfs_state_entered: timestamp (jiffies) when the dfs state was entered.
154 * @dfs_cac_ms: DFS CAC time in milliseconds, this is valid for DFS channels.
154 */ 155 */
155struct ieee80211_channel { 156struct ieee80211_channel {
156 enum ieee80211_band band; 157 enum ieee80211_band band;
@@ -165,6 +166,7 @@ struct ieee80211_channel {
165 int orig_mag, orig_mpwr; 166 int orig_mag, orig_mpwr;
166 enum nl80211_dfs_state dfs_state; 167 enum nl80211_dfs_state dfs_state;
167 unsigned long dfs_state_entered; 168 unsigned long dfs_state_entered;
169 unsigned int dfs_cac_ms;
168}; 170};
169 171
170/** 172/**
diff --git a/include/net/regulatory.h b/include/net/regulatory.h
index b07cdc9fa454..75fc1f5a948d 100644
--- a/include/net/regulatory.h
+++ b/include/net/regulatory.h
@@ -155,6 +155,7 @@ struct ieee80211_reg_rule {
155 struct ieee80211_freq_range freq_range; 155 struct ieee80211_freq_range freq_range;
156 struct ieee80211_power_rule power_rule; 156 struct ieee80211_power_rule power_rule;
157 u32 flags; 157 u32 flags;
158 u32 dfs_cac_ms;
158}; 159};
159 160
160struct ieee80211_regdomain { 161struct ieee80211_regdomain {
@@ -172,14 +173,18 @@ struct ieee80211_regdomain {
172#define DBM_TO_MBM(gain) ((gain) * 100) 173#define DBM_TO_MBM(gain) ((gain) * 100)
173#define MBM_TO_DBM(gain) ((gain) / 100) 174#define MBM_TO_DBM(gain) ((gain) / 100)
174 175
175#define REG_RULE(start, end, bw, gain, eirp, reg_flags) \ 176#define REG_RULE_EXT(start, end, bw, gain, eirp, dfs_cac, reg_flags) \
176{ \ 177{ \
177 .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \ 178 .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \
178 .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \ 179 .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \
179 .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \ 180 .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \
180 .power_rule.max_antenna_gain = DBI_TO_MBI(gain),\ 181 .power_rule.max_antenna_gain = DBI_TO_MBI(gain), \
181 .power_rule.max_eirp = DBM_TO_MBM(eirp), \ 182 .power_rule.max_eirp = DBM_TO_MBM(eirp), \
182 .flags = reg_flags, \ 183 .flags = reg_flags, \
184 .dfs_cac_ms = dfs_cac, \
183} 185}
184 186
187#define REG_RULE(start, end, bw, gain, eirp, reg_flags) \
188 REG_RULE_EXT(start, end, bw, gain, eirp, 0, reg_flags)
189
185#endif 190#endif
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index ff72cab3cd3a..1ba9d626aa83 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2335,6 +2335,7 @@ enum nl80211_band_attr {
2335 * @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel 2335 * @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel
2336 * using this channel as the primary or any of the secondary channels 2336 * using this channel as the primary or any of the secondary channels
2337 * isn't possible 2337 * isn't possible
2338 * @NL80211_FREQUENCY_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds.
2338 * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number 2339 * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
2339 * currently defined 2340 * currently defined
2340 * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use 2341 * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -2353,6 +2354,7 @@ enum nl80211_frequency_attr {
2353 NL80211_FREQUENCY_ATTR_NO_HT40_PLUS, 2354 NL80211_FREQUENCY_ATTR_NO_HT40_PLUS,
2354 NL80211_FREQUENCY_ATTR_NO_80MHZ, 2355 NL80211_FREQUENCY_ATTR_NO_80MHZ,
2355 NL80211_FREQUENCY_ATTR_NO_160MHZ, 2356 NL80211_FREQUENCY_ATTR_NO_160MHZ,
2357 NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
2356 2358
2357 /* keep last */ 2359 /* keep last */
2358 __NL80211_FREQUENCY_ATTR_AFTER_LAST, 2360 __NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -2449,6 +2451,8 @@ enum nl80211_reg_type {
2449 * If you don't have one then don't send this. 2451 * If you don't have one then don't send this.
2450 * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for 2452 * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
2451 * a given frequency range. The value is in mBm (100 * dBm). 2453 * a given frequency range. The value is in mBm (100 * dBm).
2454 * @NL80211_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds.
2455 * If not present or 0 default CAC time will be used.
2452 * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number 2456 * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number
2453 * currently defined 2457 * currently defined
2454 * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use 2458 * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use
@@ -2464,6 +2468,8 @@ enum nl80211_reg_rule_attr {
2464 NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, 2468 NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
2465 NL80211_ATTR_POWER_RULE_MAX_EIRP, 2469 NL80211_ATTR_POWER_RULE_MAX_EIRP,
2466 2470
2471 NL80211_ATTR_DFS_CAC_TIME,
2472
2467 /* keep last */ 2473 /* keep last */
2468 __NL80211_REG_RULE_ATTR_AFTER_LAST, 2474 __NL80211_REG_RULE_ATTR_AFTER_LAST,
2469 NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1 2475 NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk
index fdfd3f063a9b..b35da8dc85de 100644
--- a/net/wireless/genregdb.awk
+++ b/net/wireless/genregdb.awk
@@ -66,6 +66,7 @@ function parse_reg_rule()
66 units = $8 66 units = $8
67 sub(/\)/, "", units) 67 sub(/\)/, "", units)
68 sub(/,/, "", units) 68 sub(/,/, "", units)
69 dfs_cac = $9
69 if (units == "mW") { 70 if (units == "mW") {
70 if (power == 100) { 71 if (power == 100) {
71 power = 20 72 power = 20
@@ -78,7 +79,12 @@ function parse_reg_rule()
78 } else { 79 } else {
79 print "Unknown power value in database!" 80 print "Unknown power value in database!"
80 } 81 }
82 } else {
83 dfs_cac = $8
81 } 84 }
85 sub(/,/, "", dfs_cac)
86 sub(/\(/, "", dfs_cac)
87 sub(/\)/, "", dfs_cac)
82 flagstr = "" 88 flagstr = ""
83 for (i=8; i<=NF; i++) 89 for (i=8; i<=NF; i++)
84 flagstr = flagstr $i 90 flagstr = flagstr $i
@@ -111,7 +117,7 @@ function parse_reg_rule()
111 117
112 } 118 }
113 flags = flags "0" 119 flags = flags "0"
114 printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags 120 printf "\t\tREG_RULE_EXT(%d, %d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, dfs_cac, flags
115 rules++ 121 rules++
116} 122}
117 123
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 2c38b28a85b9..9f7ebf94a050 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -593,6 +593,10 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
593 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME, 593 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME,
594 time)) 594 time))
595 goto nla_put_failure; 595 goto nla_put_failure;
596 if (nla_put_u32(msg,
597 NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
598 chan->dfs_cac_ms))
599 goto nla_put_failure;
596 } 600 }
597 } 601 }
598 602
@@ -4614,6 +4618,7 @@ static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] =
4614 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, 4618 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
4615 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, 4619 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
4616 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, 4620 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
4621 [NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 },
4617}; 4622};
4618 4623
4619static int parse_reg_rule(struct nlattr *tb[], 4624static int parse_reg_rule(struct nlattr *tb[],
@@ -4649,6 +4654,10 @@ static int parse_reg_rule(struct nlattr *tb[],
4649 power_rule->max_antenna_gain = 4654 power_rule->max_antenna_gain =
4650 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]); 4655 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
4651 4656
4657 if (tb[NL80211_ATTR_DFS_CAC_TIME])
4658 reg_rule->dfs_cac_ms =
4659 nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]);
4660
4652 return 0; 4661 return 0;
4653} 4662}
4654 4663
@@ -5136,7 +5145,9 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
5136 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, 5145 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
5137 power_rule->max_antenna_gain) || 5146 power_rule->max_antenna_gain) ||
5138 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, 5147 nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP,
5139 power_rule->max_eirp)) 5148 power_rule->max_eirp) ||
5149 nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME,
5150 reg_rule->dfs_cac_ms))
5140 goto nla_put_failure_rcu; 5151 goto nla_put_failure_rcu;
5141 5152
5142 nla_nest_end(msg, nl_reg_rule); 5153 nla_nest_end(msg, nl_reg_rule);
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 651404c22de9..b95e9cf139c0 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -756,6 +756,9 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
756 power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain, 756 power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain,
757 power_rule2->max_antenna_gain); 757 power_rule2->max_antenna_gain);
758 758
759 intersected_rule->dfs_cac_ms = max(rule1->dfs_cac_ms,
760 rule2->dfs_cac_ms);
761
759 if (!is_valid_reg_rule(intersected_rule)) 762 if (!is_valid_reg_rule(intersected_rule))
760 return -EINVAL; 763 return -EINVAL;
761 764
@@ -1078,6 +1081,14 @@ static void handle_channel(struct wiphy *wiphy,
1078 min_t(int, chan->orig_mag, 1081 min_t(int, chan->orig_mag,
1079 MBI_TO_DBI(power_rule->max_antenna_gain)); 1082 MBI_TO_DBI(power_rule->max_antenna_gain));
1080 chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp); 1083 chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
1084
1085 if (chan->flags & IEEE80211_CHAN_RADAR) {
1086 if (reg_rule->dfs_cac_ms)
1087 chan->dfs_cac_ms = reg_rule->dfs_cac_ms;
1088 else
1089 chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
1090 }
1091
1081 if (chan->orig_mpwr) { 1092 if (chan->orig_mpwr) {
1082 /* 1093 /*
1083 * Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER 1094 * Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER
@@ -2256,9 +2267,9 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
2256 const struct ieee80211_reg_rule *reg_rule = NULL; 2267 const struct ieee80211_reg_rule *reg_rule = NULL;
2257 const struct ieee80211_freq_range *freq_range = NULL; 2268 const struct ieee80211_freq_range *freq_range = NULL;
2258 const struct ieee80211_power_rule *power_rule = NULL; 2269 const struct ieee80211_power_rule *power_rule = NULL;
2259 char bw[32]; 2270 char bw[32], cac_time[32];
2260 2271
2261 pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n"); 2272 pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp), (dfs_cac_time)\n");
2262 2273
2263 for (i = 0; i < rd->n_reg_rules; i++) { 2274 for (i = 0; i < rd->n_reg_rules; i++) {
2264 reg_rule = &rd->reg_rules[i]; 2275 reg_rule = &rd->reg_rules[i];
@@ -2273,23 +2284,32 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
2273 snprintf(bw, sizeof(bw), "%d KHz", 2284 snprintf(bw, sizeof(bw), "%d KHz",
2274 freq_range->max_bandwidth_khz); 2285 freq_range->max_bandwidth_khz);
2275 2286
2287 if (reg_rule->flags & NL80211_RRF_DFS)
2288 scnprintf(cac_time, sizeof(cac_time), "%u s",
2289 reg_rule->dfs_cac_ms/1000);
2290 else
2291 scnprintf(cac_time, sizeof(cac_time), "N/A");
2292
2293
2276 /* 2294 /*
2277 * There may not be documentation for max antenna gain 2295 * There may not be documentation for max antenna gain
2278 * in certain regions 2296 * in certain regions
2279 */ 2297 */
2280 if (power_rule->max_antenna_gain) 2298 if (power_rule->max_antenna_gain)
2281 pr_info(" (%d KHz - %d KHz @ %s), (%d mBi, %d mBm)\n", 2299 pr_info(" (%d KHz - %d KHz @ %s), (%d mBi, %d mBm), (%s)\n",
2282 freq_range->start_freq_khz, 2300 freq_range->start_freq_khz,
2283 freq_range->end_freq_khz, 2301 freq_range->end_freq_khz,
2284 bw, 2302 bw,
2285 power_rule->max_antenna_gain, 2303 power_rule->max_antenna_gain,
2286 power_rule->max_eirp); 2304 power_rule->max_eirp,
2305 cac_time);
2287 else 2306 else
2288 pr_info(" (%d KHz - %d KHz @ %s), (N/A, %d mBm)\n", 2307 pr_info(" (%d KHz - %d KHz @ %s), (N/A, %d mBm), (%s)\n",
2289 freq_range->start_freq_khz, 2308 freq_range->start_freq_khz,
2290 freq_range->end_freq_khz, 2309 freq_range->end_freq_khz,
2291 bw, 2310 bw,
2292 power_rule->max_eirp); 2311 power_rule->max_eirp,
2312 cac_time);
2293 } 2313 }
2294} 2314}
2295 2315