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 { * @dfs_state: current state of this channel. Only relevant if radar is required * on this channel. * @dfs_state_entered: timestamp (jiffies) when the dfs state was entered. + * @dfs_cac_ms: DFS CAC time in milliseconds, this is valid for DFS channels. */ struct ieee80211_channel { enum ieee80211_band band; @@ -165,6 +166,7 @@ struct ieee80211_channel { int orig_mag, orig_mpwr; enum nl80211_dfs_state dfs_state; unsigned long dfs_state_entered; + unsigned int dfs_cac_ms; }; /** 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 { struct ieee80211_freq_range freq_range; struct ieee80211_power_rule power_rule; u32 flags; + u32 dfs_cac_ms; }; struct ieee80211_regdomain { @@ -172,14 +173,18 @@ struct ieee80211_regdomain { #define DBM_TO_MBM(gain) ((gain) * 100) #define MBM_TO_DBM(gain) ((gain) / 100) -#define REG_RULE(start, end, bw, gain, eirp, reg_flags) \ -{ \ - .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \ - .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \ - .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \ - .power_rule.max_antenna_gain = DBI_TO_MBI(gain),\ - .power_rule.max_eirp = DBM_TO_MBM(eirp), \ - .flags = reg_flags, \ +#define REG_RULE_EXT(start, end, bw, gain, eirp, dfs_cac, reg_flags) \ +{ \ + .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \ + .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \ + .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \ + .power_rule.max_antenna_gain = DBI_TO_MBI(gain), \ + .power_rule.max_eirp = DBM_TO_MBM(eirp), \ + .flags = reg_flags, \ + .dfs_cac_ms = dfs_cac, \ } +#define REG_RULE(start, end, bw, gain, eirp, reg_flags) \ + REG_RULE_EXT(start, end, bw, gain, eirp, 0, reg_flags) + #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 { * @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel * using this channel as the primary or any of the secondary channels * isn't possible + * @NL80211_FREQUENCY_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds. * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number * currently defined * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use @@ -2353,6 +2354,7 @@ enum nl80211_frequency_attr { NL80211_FREQUENCY_ATTR_NO_HT40_PLUS, NL80211_FREQUENCY_ATTR_NO_80MHZ, NL80211_FREQUENCY_ATTR_NO_160MHZ, + NL80211_FREQUENCY_ATTR_DFS_CAC_TIME, /* keep last */ __NL80211_FREQUENCY_ATTR_AFTER_LAST, @@ -2449,6 +2451,8 @@ enum nl80211_reg_type { * If you don't have one then don't send this. * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for * a given frequency range. The value is in mBm (100 * dBm). + * @NL80211_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds. + * If not present or 0 default CAC time will be used. * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number * currently defined * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use @@ -2464,6 +2468,8 @@ enum nl80211_reg_rule_attr { NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, NL80211_ATTR_POWER_RULE_MAX_EIRP, + NL80211_ATTR_DFS_CAC_TIME, + /* keep last */ __NL80211_REG_RULE_ATTR_AFTER_LAST, 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() units = $8 sub(/\)/, "", units) sub(/,/, "", units) + dfs_cac = $9 if (units == "mW") { if (power == 100) { power = 20 @@ -78,7 +79,12 @@ function parse_reg_rule() } else { print "Unknown power value in database!" } + } else { + dfs_cac = $8 } + sub(/,/, "", dfs_cac) + sub(/\(/, "", dfs_cac) + sub(/\)/, "", dfs_cac) flagstr = "" for (i=8; i<=NF; i++) flagstr = flagstr $i @@ -111,7 +117,7 @@ function parse_reg_rule() } flags = flags "0" - printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags + printf "\t\tREG_RULE_EXT(%d, %d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, dfs_cac, flags rules++ } 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, if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME, time)) goto nla_put_failure; + if (nla_put_u32(msg, + NL80211_FREQUENCY_ATTR_DFS_CAC_TIME, + chan->dfs_cac_ms)) + goto nla_put_failure; } } @@ -4614,6 +4618,7 @@ static const struct nla_policy reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 }, [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 }, [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 }, + [NL80211_ATTR_DFS_CAC_TIME] = { .type = NLA_U32 }, }; static int parse_reg_rule(struct nlattr *tb[], @@ -4649,6 +4654,10 @@ static int parse_reg_rule(struct nlattr *tb[], power_rule->max_antenna_gain = nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]); + if (tb[NL80211_ATTR_DFS_CAC_TIME]) + reg_rule->dfs_cac_ms = + nla_get_u32(tb[NL80211_ATTR_DFS_CAC_TIME]); + return 0; } @@ -5136,7 +5145,9 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, power_rule->max_antenna_gain) || nla_put_u32(msg, NL80211_ATTR_POWER_RULE_MAX_EIRP, - power_rule->max_eirp)) + power_rule->max_eirp) || + nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME, + reg_rule->dfs_cac_ms)) goto nla_put_failure_rcu; 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, power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain, power_rule2->max_antenna_gain); + intersected_rule->dfs_cac_ms = max(rule1->dfs_cac_ms, + rule2->dfs_cac_ms); + if (!is_valid_reg_rule(intersected_rule)) return -EINVAL; @@ -1078,6 +1081,14 @@ static void handle_channel(struct wiphy *wiphy, min_t(int, chan->orig_mag, MBI_TO_DBI(power_rule->max_antenna_gain)); chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp); + + if (chan->flags & IEEE80211_CHAN_RADAR) { + if (reg_rule->dfs_cac_ms) + chan->dfs_cac_ms = reg_rule->dfs_cac_ms; + else + chan->dfs_cac_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; + } + if (chan->orig_mpwr) { /* * Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER @@ -2256,9 +2267,9 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) const struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_freq_range *freq_range = NULL; const struct ieee80211_power_rule *power_rule = NULL; - char bw[32]; + char bw[32], cac_time[32]; - pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)\n"); + pr_info(" (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp), (dfs_cac_time)\n"); for (i = 0; i < rd->n_reg_rules; i++) { reg_rule = &rd->reg_rules[i]; @@ -2273,23 +2284,32 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) snprintf(bw, sizeof(bw), "%d KHz", freq_range->max_bandwidth_khz); + if (reg_rule->flags & NL80211_RRF_DFS) + scnprintf(cac_time, sizeof(cac_time), "%u s", + reg_rule->dfs_cac_ms/1000); + else + scnprintf(cac_time, sizeof(cac_time), "N/A"); + + /* * There may not be documentation for max antenna gain * in certain regions */ if (power_rule->max_antenna_gain) - pr_info(" (%d KHz - %d KHz @ %s), (%d mBi, %d mBm)\n", + pr_info(" (%d KHz - %d KHz @ %s), (%d mBi, %d mBm), (%s)\n", freq_range->start_freq_khz, freq_range->end_freq_khz, bw, power_rule->max_antenna_gain, - power_rule->max_eirp); + power_rule->max_eirp, + cac_time); else - pr_info(" (%d KHz - %d KHz @ %s), (N/A, %d mBm)\n", + pr_info(" (%d KHz - %d KHz @ %s), (N/A, %d mBm), (%s)\n", freq_range->start_freq_khz, freq_range->end_freq_khz, bw, - power_rule->max_eirp); + power_rule->max_eirp, + cac_time); } } |