aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 77880ba8b619..1221d726ed50 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -18,6 +18,7 @@
18#include <net/cfg80211.h> 18#include <net/cfg80211.h>
19#include "core.h" 19#include "core.h"
20#include "nl80211.h" 20#include "nl80211.h"
21#include "reg.h"
21 22
22/* the netlink family */ 23/* the netlink family */
23static struct genl_family nl80211_fam = { 24static struct genl_family nl80211_fam = {
@@ -88,6 +89,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
88 .len = IEEE80211_MAX_MESH_ID_LEN }, 89 .len = IEEE80211_MAX_MESH_ID_LEN },
89 [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, 90 [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
90 91
92 [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 },
93 [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED },
94
91 [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 }, 95 [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
92 [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 }, 96 [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
93 [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, 97 [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
@@ -1599,6 +1603,141 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
1599 return err; 1603 return err;
1600} 1604}
1601 1605
1606static const struct nla_policy
1607 reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
1608 [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
1609 [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
1610 [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
1611 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
1612 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
1613 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
1614};
1615
1616static int parse_reg_rule(struct nlattr *tb[],
1617 struct ieee80211_reg_rule *reg_rule)
1618{
1619 struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
1620 struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
1621
1622 if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
1623 return -EINVAL;
1624 if (!tb[NL80211_ATTR_FREQ_RANGE_START])
1625 return -EINVAL;
1626 if (!tb[NL80211_ATTR_FREQ_RANGE_END])
1627 return -EINVAL;
1628 if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
1629 return -EINVAL;
1630 if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
1631 return -EINVAL;
1632
1633 reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
1634
1635 freq_range->start_freq_khz =
1636 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
1637 freq_range->end_freq_khz =
1638 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
1639 freq_range->max_bandwidth_khz =
1640 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
1641
1642 power_rule->max_eirp =
1643 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
1644
1645 if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
1646 power_rule->max_antenna_gain =
1647 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
1648
1649 return 0;
1650}
1651
1652static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
1653{
1654 int r;
1655 char *data = NULL;
1656
1657 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
1658 return -EINVAL;
1659
1660 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
1661
1662#ifdef CONFIG_WIRELESS_OLD_REGULATORY
1663 /* We ignore world regdom requests with the old regdom setup */
1664 if (is_world_regdom(data))
1665 return -EINVAL;
1666#endif
1667 mutex_lock(&cfg80211_drv_mutex);
1668 r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, NULL);
1669 mutex_unlock(&cfg80211_drv_mutex);
1670 return r;
1671}
1672
1673static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
1674{
1675 struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
1676 struct nlattr *nl_reg_rule;
1677 char *alpha2 = NULL;
1678 int rem_reg_rules = 0, r = 0;
1679 u32 num_rules = 0, rule_idx = 0, size_of_regd;
1680 struct ieee80211_regdomain *rd = NULL;
1681
1682 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
1683 return -EINVAL;
1684
1685 if (!info->attrs[NL80211_ATTR_REG_RULES])
1686 return -EINVAL;
1687
1688 alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
1689
1690 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
1691 rem_reg_rules) {
1692 num_rules++;
1693 if (num_rules > NL80211_MAX_SUPP_REG_RULES)
1694 goto bad_reg;
1695 }
1696
1697 if (!reg_is_valid_request(alpha2))
1698 return -EINVAL;
1699
1700 size_of_regd = sizeof(struct ieee80211_regdomain) +
1701 (num_rules * sizeof(struct ieee80211_reg_rule));
1702
1703 rd = kzalloc(size_of_regd, GFP_KERNEL);
1704 if (!rd)
1705 return -ENOMEM;
1706
1707 rd->n_reg_rules = num_rules;
1708 rd->alpha2[0] = alpha2[0];
1709 rd->alpha2[1] = alpha2[1];
1710
1711 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
1712 rem_reg_rules) {
1713 nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
1714 nla_data(nl_reg_rule), nla_len(nl_reg_rule),
1715 reg_rule_policy);
1716 r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
1717 if (r)
1718 goto bad_reg;
1719
1720 rule_idx++;
1721
1722 if (rule_idx > NL80211_MAX_SUPP_REG_RULES)
1723 goto bad_reg;
1724 }
1725
1726 BUG_ON(rule_idx != num_rules);
1727
1728 mutex_lock(&cfg80211_drv_mutex);
1729 r = set_regdom(rd);
1730 mutex_unlock(&cfg80211_drv_mutex);
1731 if (r)
1732 goto bad_reg;
1733
1734 return r;
1735
1736bad_reg:
1737 kfree(rd);
1738 return -EINVAL;
1739}
1740
1602static struct genl_ops nl80211_ops[] = { 1741static struct genl_ops nl80211_ops[] = {
1603 { 1742 {
1604 .cmd = NL80211_CMD_GET_WIPHY, 1743 .cmd = NL80211_CMD_GET_WIPHY,
@@ -1736,6 +1875,18 @@ static struct genl_ops nl80211_ops[] = {
1736 .policy = nl80211_policy, 1875 .policy = nl80211_policy,
1737 .flags = GENL_ADMIN_PERM, 1876 .flags = GENL_ADMIN_PERM,
1738 }, 1877 },
1878 {
1879 .cmd = NL80211_CMD_SET_REG,
1880 .doit = nl80211_set_reg,
1881 .policy = nl80211_policy,
1882 .flags = GENL_ADMIN_PERM,
1883 },
1884 {
1885 .cmd = NL80211_CMD_REQ_SET_REG,
1886 .doit = nl80211_req_set_reg,
1887 .policy = nl80211_policy,
1888 .flags = GENL_ADMIN_PERM,
1889 },
1739}; 1890};
1740 1891
1741/* multicast groups */ 1892/* multicast groups */