History

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.

Janusz Dziedzic committed 12 years ago

Commit 089027e1 parent fb5c9636 files · +66 −16Browse files

Unified · Split

6 files
  1. include/net/cfg80211.h +2 −0
  2. include/net/regulatory.h +13 −8
  3. include/uapi/linux/nl80211.h +6 −0
  4. net/wireless/genregdb.awk +7 −1
  5. net/wireless/nl80211.c +12 −1
  6. net/wireless/reg.c +26 −6
include/net/cfg80211.h+2−0
@@ -151,6 +151,7 @@ enum ieee80211_channel_flags { · 150 unmodified lines
151 * @dfs_state: current state of this channel. Only relevant if radar is required151 * @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 { · 8 unmodified lines
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/**
include/net/regulatory.h+13−8
@@ -155,6 +155,7 @@ struct ieee80211_reg_rule { · 154 unmodified lines
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 { · 11 unmodified lines
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#endif190#endif
include/uapi/linux/nl80211.h+6−0
@@ -2335,6 +2335,7 @@ enum nl80211_band_attr { · 2334 unmodified lines
2335 * @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel2335 * @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 channels2336 * using this channel as the primary or any of the secondary channels
2337 * isn't possible2337 * isn't possible
2338 * @NL80211_FREQUENCY_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds.
2338 * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number2339 * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
2339 * currently defined2340 * currently defined
2340 * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use2341 * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -2353,6 +2354,7 @@ enum nl80211_frequency_attr { · 12 unmodified lines
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 { · 90 unmodified lines
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 for2452 * @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 number2456 * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number
2453 * currently defined2457 * currently defined
2454 * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use2458 * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use
@@ -2464,6 +2468,8 @@ enum nl80211_reg_rule_attr { · 9 unmodified lines
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 - 12475 NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
net/wireless/genregdb.awk+7−1
@@ -66,6 +66,7 @@ function parse_reg_rule() · 65 unmodified lines
66 units = $866 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 = 2072 power = 20
@@ -78,7 +79,12 @@ function parse_reg_rule() · 6 unmodified lines
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 $i90 flagstr = flagstr $i
@@ -111,7 +117,7 @@ function parse_reg_rule() · 26 unmodified lines
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, flags120 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
net/wireless/nl80211.c+12−1
@@ -593,6 +593,10 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, · 592 unmodified lines
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] = · 4015 unmodified lines
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[], · 29 unmodified lines
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) · 481 unmodified lines
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);
net/wireless/reg.c+26−6
@@ -756,6 +756,9 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1, · 755 unmodified lines
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, · 316 unmodified lines
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_POWER1094 * Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER
@@ -2256,9 +2267,9 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) · 1172 unmodified lines
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) · 8 unmodified lines
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 gain2295 * There may not be documentation for max antenna gain
2278 * in certain regions2296 * 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 else2306 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