aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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