diff options
-rw-r--r-- | include/linux/nl80211.h | 21 | ||||
-rw-r--r-- | include/net/regulatory.h | 1 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 15 | ||||
-rw-r--r-- | net/wireless/reg.c | 37 | ||||
-rw-r--r-- | net/wireless/reg.h | 1 |
5 files changed, 75 insertions, 0 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index f9261c253735..6396819a7e41 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -1170,6 +1170,10 @@ enum nl80211_commands { | |||
1170 | * probe-response frame. The DA field in the 802.11 header is zero-ed out, | 1170 | * probe-response frame. The DA field in the 802.11 header is zero-ed out, |
1171 | * to be filled by the FW. | 1171 | * to be filled by the FW. |
1172 | * | 1172 | * |
1173 | * @NL80211_ATTR_DFS_REGION: region for regulatory rules which this country | ||
1174 | * abides to when initiating radiation on DFS channels. A country maps | ||
1175 | * to one DFS region. | ||
1176 | * | ||
1173 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 1177 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
1174 | * @__NL80211_ATTR_AFTER_LAST: internal use | 1178 | * @__NL80211_ATTR_AFTER_LAST: internal use |
1175 | */ | 1179 | */ |
@@ -1408,6 +1412,8 @@ enum nl80211_attrs { | |||
1408 | 1412 | ||
1409 | NL80211_ATTR_PROBE_RESP, | 1413 | NL80211_ATTR_PROBE_RESP, |
1410 | 1414 | ||
1415 | NL80211_ATTR_DFS_REGION, | ||
1416 | |||
1411 | /* add attributes here, update the policy in nl80211.c */ | 1417 | /* add attributes here, update the policy in nl80211.c */ |
1412 | 1418 | ||
1413 | __NL80211_ATTR_AFTER_LAST, | 1419 | __NL80211_ATTR_AFTER_LAST, |
@@ -1917,6 +1923,21 @@ enum nl80211_reg_rule_flags { | |||
1917 | }; | 1923 | }; |
1918 | 1924 | ||
1919 | /** | 1925 | /** |
1926 | * enum nl80211_dfs_regions - regulatory DFS regions | ||
1927 | * | ||
1928 | * @NL80211_DFS_UNSET: Country has no DFS master region specified | ||
1929 | * @NL80211_DFS_FCC_: Country follows DFS master rules from FCC | ||
1930 | * @NL80211_DFS_FCC_: Country follows DFS master rules from ETSI | ||
1931 | * @NL80211_DFS_JP_: Country follows DFS master rules from JP/MKK/Telec | ||
1932 | */ | ||
1933 | enum nl80211_dfs_regions { | ||
1934 | NL80211_DFS_UNSET = 0, | ||
1935 | NL80211_DFS_FCC = 1, | ||
1936 | NL80211_DFS_ETSI = 2, | ||
1937 | NL80211_DFS_JP = 3, | ||
1938 | }; | ||
1939 | |||
1940 | /** | ||
1920 | * enum nl80211_survey_info - survey information | 1941 | * enum nl80211_survey_info - survey information |
1921 | * | 1942 | * |
1922 | * These attribute types are used with %NL80211_ATTR_SURVEY_INFO | 1943 | * These attribute types are used with %NL80211_ATTR_SURVEY_INFO |
diff --git a/include/net/regulatory.h b/include/net/regulatory.h index eb7d3c2d4274..7399c93cb4bc 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h | |||
@@ -93,6 +93,7 @@ struct ieee80211_reg_rule { | |||
93 | struct ieee80211_regdomain { | 93 | struct ieee80211_regdomain { |
94 | u32 n_reg_rules; | 94 | u32 n_reg_rules; |
95 | char alpha2[2]; | 95 | char alpha2[2]; |
96 | u8 dfs_region; | ||
96 | struct ieee80211_reg_rule reg_rules[]; | 97 | struct ieee80211_reg_rule reg_rules[]; |
97 | }; | 98 | }; |
98 | 99 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 6bc7c4b32fa5..50482e129263 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -199,6 +199,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
199 | [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG }, | 199 | [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG }, |
200 | [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, | 200 | [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, |
201 | .len = IEEE80211_MAX_DATA_LEN }, | 201 | .len = IEEE80211_MAX_DATA_LEN }, |
202 | [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 }, | ||
202 | }; | 203 | }; |
203 | 204 | ||
204 | /* policy for the key attributes */ | 205 | /* policy for the key attributes */ |
@@ -3382,6 +3383,9 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
3382 | 3383 | ||
3383 | NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, | 3384 | NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, |
3384 | cfg80211_regdomain->alpha2); | 3385 | cfg80211_regdomain->alpha2); |
3386 | if (cfg80211_regdomain->dfs_region) | ||
3387 | NLA_PUT_U8(msg, NL80211_ATTR_DFS_REGION, | ||
3388 | cfg80211_regdomain->dfs_region); | ||
3385 | 3389 | ||
3386 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); | 3390 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); |
3387 | if (!nl_reg_rules) | 3391 | if (!nl_reg_rules) |
@@ -3440,6 +3444,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3440 | char *alpha2 = NULL; | 3444 | char *alpha2 = NULL; |
3441 | int rem_reg_rules = 0, r = 0; | 3445 | int rem_reg_rules = 0, r = 0; |
3442 | u32 num_rules = 0, rule_idx = 0, size_of_regd; | 3446 | u32 num_rules = 0, rule_idx = 0, size_of_regd; |
3447 | u8 dfs_region = 0; | ||
3443 | struct ieee80211_regdomain *rd = NULL; | 3448 | struct ieee80211_regdomain *rd = NULL; |
3444 | 3449 | ||
3445 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) | 3450 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) |
@@ -3450,6 +3455,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3450 | 3455 | ||
3451 | alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); | 3456 | alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); |
3452 | 3457 | ||
3458 | if (info->attrs[NL80211_ATTR_DFS_REGION]) | ||
3459 | dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]); | ||
3460 | |||
3453 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], | 3461 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], |
3454 | rem_reg_rules) { | 3462 | rem_reg_rules) { |
3455 | num_rules++; | 3463 | num_rules++; |
@@ -3477,6 +3485,13 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3477 | rd->alpha2[0] = alpha2[0]; | 3485 | rd->alpha2[0] = alpha2[0]; |
3478 | rd->alpha2[1] = alpha2[1]; | 3486 | rd->alpha2[1] = alpha2[1]; |
3479 | 3487 | ||
3488 | /* | ||
3489 | * Disable DFS master mode if the DFS region was | ||
3490 | * not supported or known on this kernel. | ||
3491 | */ | ||
3492 | if (reg_supported_dfs_region(dfs_region)) | ||
3493 | rd->dfs_region = dfs_region; | ||
3494 | |||
3480 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], | 3495 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], |
3481 | rem_reg_rules) { | 3496 | rem_reg_rules) { |
3482 | nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, | 3497 | nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2520a1b7e7db..69141ed1f6df 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -1946,6 +1946,42 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) | |||
1946 | } | 1946 | } |
1947 | } | 1947 | } |
1948 | 1948 | ||
1949 | bool reg_supported_dfs_region(u8 dfs_region) | ||
1950 | { | ||
1951 | switch (dfs_region) { | ||
1952 | case NL80211_DFS_UNSET: | ||
1953 | case NL80211_DFS_FCC: | ||
1954 | case NL80211_DFS_ETSI: | ||
1955 | case NL80211_DFS_JP: | ||
1956 | return true; | ||
1957 | default: | ||
1958 | REG_DBG_PRINT("Ignoring uknown DFS master region: %d\n", | ||
1959 | dfs_region); | ||
1960 | return false; | ||
1961 | } | ||
1962 | } | ||
1963 | |||
1964 | static void print_dfs_region(u8 dfs_region) | ||
1965 | { | ||
1966 | if (!dfs_region) | ||
1967 | return; | ||
1968 | |||
1969 | switch (dfs_region) { | ||
1970 | case NL80211_DFS_FCC: | ||
1971 | pr_info(" DFS Master region FCC"); | ||
1972 | break; | ||
1973 | case NL80211_DFS_ETSI: | ||
1974 | pr_info(" DFS Master region ETSI"); | ||
1975 | break; | ||
1976 | case NL80211_DFS_JP: | ||
1977 | pr_info(" DFS Master region JP"); | ||
1978 | break; | ||
1979 | default: | ||
1980 | pr_info(" DFS Master region Uknown"); | ||
1981 | break; | ||
1982 | } | ||
1983 | } | ||
1984 | |||
1949 | static void print_regdomain(const struct ieee80211_regdomain *rd) | 1985 | static void print_regdomain(const struct ieee80211_regdomain *rd) |
1950 | { | 1986 | { |
1951 | 1987 | ||
@@ -1973,6 +2009,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) | |||
1973 | pr_info("Regulatory domain changed to country: %c%c\n", | 2009 | pr_info("Regulatory domain changed to country: %c%c\n", |
1974 | rd->alpha2[0], rd->alpha2[1]); | 2010 | rd->alpha2[0], rd->alpha2[1]); |
1975 | } | 2011 | } |
2012 | print_dfs_region(rd->dfs_region); | ||
1976 | print_rd_rules(rd); | 2013 | print_rd_rules(rd); |
1977 | } | 2014 | } |
1978 | 2015 | ||
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 4a56799d868d..786e414afd91 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -5,6 +5,7 @@ extern const struct ieee80211_regdomain *cfg80211_regdomain; | |||
5 | 5 | ||
6 | bool is_world_regdom(const char *alpha2); | 6 | bool is_world_regdom(const char *alpha2); |
7 | bool reg_is_valid_request(const char *alpha2); | 7 | bool reg_is_valid_request(const char *alpha2); |
8 | bool reg_supported_dfs_region(u8 dfs_region); | ||
8 | 9 | ||
9 | int regulatory_hint_user(const char *alpha2); | 10 | int regulatory_hint_user(const char *alpha2); |
10 | 11 | ||