From 10809c7ca89776b132ca6ff0860c63dcdad63dc3 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 11 Oct 2011 10:59:02 -0700 Subject: [PATCH] --- yaml --- r: 278215 b: refs/heads/master c: 8b60b07805d557542160d852874fa6a1b969184e h: refs/heads/master i: 278213: a0884f713e51934f6ce89489c4f5f8c04faf8c71 278211: 727f5decce0ada4cf10686d86e2419f0661a1c3c 278207: 3448c4a5998f64b65ac4dfe8aa387e62f350fb88 v: v3 --- [refs] | 2 +- trunk/include/linux/nl80211.h | 21 +++++++++++++++++++ trunk/include/net/regulatory.h | 1 + trunk/net/wireless/nl80211.c | 15 ++++++++++++++ trunk/net/wireless/reg.c | 37 ++++++++++++++++++++++++++++++++++ trunk/net/wireless/reg.h | 1 + 6 files changed, 76 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index a17b15830b2a..6cb87c6dba83 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 4713e962c5d98901890c446843ae4e0a9d37b7b3 +refs/heads/master: 8b60b07805d557542160d852874fa6a1b969184e diff --git a/trunk/include/linux/nl80211.h b/trunk/include/linux/nl80211.h index f9261c253735..6396819a7e41 100644 --- a/trunk/include/linux/nl80211.h +++ b/trunk/include/linux/nl80211.h @@ -1170,6 +1170,10 @@ enum nl80211_commands { * probe-response frame. The DA field in the 802.11 header is zero-ed out, * to be filled by the FW. * + * @NL80211_ATTR_DFS_REGION: region for regulatory rules which this country + * abides to when initiating radiation on DFS channels. A country maps + * to one DFS region. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1408,6 +1412,8 @@ enum nl80211_attrs { NL80211_ATTR_PROBE_RESP, + NL80211_ATTR_DFS_REGION, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1916,6 +1922,21 @@ enum nl80211_reg_rule_flags { NL80211_RRF_NO_IBSS = 1<<8, }; +/** + * enum nl80211_dfs_regions - regulatory DFS regions + * + * @NL80211_DFS_UNSET: Country has no DFS master region specified + * @NL80211_DFS_FCC_: Country follows DFS master rules from FCC + * @NL80211_DFS_FCC_: Country follows DFS master rules from ETSI + * @NL80211_DFS_JP_: Country follows DFS master rules from JP/MKK/Telec + */ +enum nl80211_dfs_regions { + NL80211_DFS_UNSET = 0, + NL80211_DFS_FCC = 1, + NL80211_DFS_ETSI = 2, + NL80211_DFS_JP = 3, +}; + /** * enum nl80211_survey_info - survey information * diff --git a/trunk/include/net/regulatory.h b/trunk/include/net/regulatory.h index eb7d3c2d4274..7399c93cb4bc 100644 --- a/trunk/include/net/regulatory.h +++ b/trunk/include/net/regulatory.h @@ -93,6 +93,7 @@ struct ieee80211_reg_rule { struct ieee80211_regdomain { u32 n_reg_rules; char alpha2[2]; + u8 dfs_region; struct ieee80211_reg_rule reg_rules[]; }; diff --git a/trunk/net/wireless/nl80211.c b/trunk/net/wireless/nl80211.c index 6bc7c4b32fa5..50482e129263 100644 --- a/trunk/net/wireless/nl80211.c +++ b/trunk/net/wireless/nl80211.c @@ -199,6 +199,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG }, [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 }, }; /* policy for the key attributes */ @@ -3382,6 +3383,9 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, cfg80211_regdomain->alpha2); + if (cfg80211_regdomain->dfs_region) + NLA_PUT_U8(msg, NL80211_ATTR_DFS_REGION, + cfg80211_regdomain->dfs_region); nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); if (!nl_reg_rules) @@ -3440,6 +3444,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) char *alpha2 = NULL; int rem_reg_rules = 0, r = 0; u32 num_rules = 0, rule_idx = 0, size_of_regd; + u8 dfs_region = 0; struct ieee80211_regdomain *rd = NULL; if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) @@ -3450,6 +3455,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); + if (info->attrs[NL80211_ATTR_DFS_REGION]) + dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]); + nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], rem_reg_rules) { num_rules++; @@ -3477,6 +3485,13 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) rd->alpha2[0] = alpha2[0]; rd->alpha2[1] = alpha2[1]; + /* + * Disable DFS master mode if the DFS region was + * not supported or known on this kernel. + */ + if (reg_supported_dfs_region(dfs_region)) + rd->dfs_region = dfs_region; + nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], rem_reg_rules) { nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, diff --git a/trunk/net/wireless/reg.c b/trunk/net/wireless/reg.c index 2520a1b7e7db..69141ed1f6df 100644 --- a/trunk/net/wireless/reg.c +++ b/trunk/net/wireless/reg.c @@ -1946,6 +1946,42 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) } } +bool reg_supported_dfs_region(u8 dfs_region) +{ + switch (dfs_region) { + case NL80211_DFS_UNSET: + case NL80211_DFS_FCC: + case NL80211_DFS_ETSI: + case NL80211_DFS_JP: + return true; + default: + REG_DBG_PRINT("Ignoring uknown DFS master region: %d\n", + dfs_region); + return false; + } +} + +static void print_dfs_region(u8 dfs_region) +{ + if (!dfs_region) + return; + + switch (dfs_region) { + case NL80211_DFS_FCC: + pr_info(" DFS Master region FCC"); + break; + case NL80211_DFS_ETSI: + pr_info(" DFS Master region ETSI"); + break; + case NL80211_DFS_JP: + pr_info(" DFS Master region JP"); + break; + default: + pr_info(" DFS Master region Uknown"); + break; + } +} + static void print_regdomain(const struct ieee80211_regdomain *rd) { @@ -1973,6 +2009,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) pr_info("Regulatory domain changed to country: %c%c\n", rd->alpha2[0], rd->alpha2[1]); } + print_dfs_region(rd->dfs_region); print_rd_rules(rd); } diff --git a/trunk/net/wireless/reg.h b/trunk/net/wireless/reg.h index 4a56799d868d..786e414afd91 100644 --- a/trunk/net/wireless/reg.h +++ b/trunk/net/wireless/reg.h @@ -5,6 +5,7 @@ extern const struct ieee80211_regdomain *cfg80211_regdomain; bool is_world_regdom(const char *alpha2); bool reg_is_valid_request(const char *alpha2); +bool reg_supported_dfs_region(u8 dfs_region); int regulatory_hint_user(const char *alpha2);