aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/nl80211.h21
-rw-r--r--include/net/regulatory.h1
-rw-r--r--net/wireless/nl80211.c15
-rw-r--r--net/wireless/reg.c37
-rw-r--r--net/wireless/reg.h1
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 */
1933enum 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 {
93struct ieee80211_regdomain { 93struct 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
1949bool 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
1964static 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
1949static void print_regdomain(const struct ieee80211_regdomain *rd) 1985static 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
6bool is_world_regdom(const char *alpha2); 6bool is_world_regdom(const char *alpha2);
7bool reg_is_valid_request(const char *alpha2); 7bool reg_is_valid_request(const char *alpha2);
8bool reg_supported_dfs_region(u8 dfs_region);
8 9
9int regulatory_hint_user(const char *alpha2); 10int regulatory_hint_user(const char *alpha2);
10 11