diff options
| -rw-r--r-- | include/net/cfg80211.h | 2 | ||||
| -rw-r--r-- | include/net/regulatory.h | 21 | ||||
| -rw-r--r-- | include/uapi/linux/nl80211.h | 6 | ||||
| -rw-r--r-- | net/wireless/genregdb.awk | 8 | ||||
| -rw-r--r-- | net/wireless/nl80211.c | 13 | ||||
| -rw-r--r-- | net/wireless/reg.c | 32 |
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 | */ |
| 155 | struct ieee80211_channel { | 156 | struct 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 | ||
| 160 | struct ieee80211_regdomain { | 161 | struct 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 | ||
| 4619 | static int parse_reg_rule(struct nlattr *tb[], | 4624 | static 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 | ||
