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.c280
1 files changed, 263 insertions, 17 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 59eb2cf42e5f..572793c8c7ab 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 = {
@@ -87,6 +88,16 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
87 [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, 88 [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
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 },
91
92 [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 },
93 [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED },
94
95 [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
96 [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
97 [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
98
99 [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY,
100 .len = NL80211_HT_CAPABILITY_LEN },
90}; 101};
91 102
92/* message building helper */ 103/* message building helper */
@@ -106,10 +117,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
106 struct nlattr *nl_bands, *nl_band; 117 struct nlattr *nl_bands, *nl_band;
107 struct nlattr *nl_freqs, *nl_freq; 118 struct nlattr *nl_freqs, *nl_freq;
108 struct nlattr *nl_rates, *nl_rate; 119 struct nlattr *nl_rates, *nl_rate;
120 struct nlattr *nl_modes;
109 enum ieee80211_band band; 121 enum ieee80211_band band;
110 struct ieee80211_channel *chan; 122 struct ieee80211_channel *chan;
111 struct ieee80211_rate *rate; 123 struct ieee80211_rate *rate;
112 int i; 124 int i;
125 u16 ifmodes = dev->wiphy.interface_modes;
113 126
114 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); 127 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
115 if (!hdr) 128 if (!hdr)
@@ -118,6 +131,20 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
118 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx); 131 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
119 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); 132 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
120 133
134 nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
135 if (!nl_modes)
136 goto nla_put_failure;
137
138 i = 0;
139 while (ifmodes) {
140 if (ifmodes & 1)
141 NLA_PUT_FLAG(msg, i);
142 ifmodes >>= 1;
143 i++;
144 }
145
146 nla_nest_end(msg, nl_modes);
147
121 nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); 148 nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
122 if (!nl_bands) 149 if (!nl_bands)
123 goto nla_put_failure; 150 goto nla_put_failure;
@@ -272,7 +299,7 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
272 299
273 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); 300 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
274 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); 301 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name);
275 /* TODO: interface type */ 302 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype);
276 return genlmsg_end(msg, hdr); 303 return genlmsg_end(msg, hdr);
277 304
278 nla_put_failure: 305 nla_put_failure:
@@ -391,40 +418,56 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
391 int err, ifindex; 418 int err, ifindex;
392 enum nl80211_iftype type; 419 enum nl80211_iftype type;
393 struct net_device *dev; 420 struct net_device *dev;
394 u32 flags; 421 u32 _flags, *flags = NULL;
395 422
396 memset(&params, 0, sizeof(params)); 423 memset(&params, 0, sizeof(params));
397 424
398 if (info->attrs[NL80211_ATTR_IFTYPE]) {
399 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
400 if (type > NL80211_IFTYPE_MAX)
401 return -EINVAL;
402 } else
403 return -EINVAL;
404
405 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 425 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
406 if (err) 426 if (err)
407 return err; 427 return err;
408 ifindex = dev->ifindex; 428 ifindex = dev->ifindex;
429 type = dev->ieee80211_ptr->iftype;
409 dev_put(dev); 430 dev_put(dev);
410 431
411 if (!drv->ops->change_virtual_intf) { 432 err = -EINVAL;
433 if (info->attrs[NL80211_ATTR_IFTYPE]) {
434 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
435 if (type > NL80211_IFTYPE_MAX)
436 goto unlock;
437 }
438
439 if (!drv->ops->change_virtual_intf ||
440 !(drv->wiphy.interface_modes & (1 << type))) {
412 err = -EOPNOTSUPP; 441 err = -EOPNOTSUPP;
413 goto unlock; 442 goto unlock;
414 } 443 }
415 444
416 if (type == NL80211_IFTYPE_MESH_POINT && 445 if (info->attrs[NL80211_ATTR_MESH_ID]) {
417 info->attrs[NL80211_ATTR_MESH_ID]) { 446 if (type != NL80211_IFTYPE_MESH_POINT) {
447 err = -EINVAL;
448 goto unlock;
449 }
418 params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); 450 params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
419 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); 451 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
420 } 452 }
421 453
454 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
455 if (type != NL80211_IFTYPE_MONITOR) {
456 err = -EINVAL;
457 goto unlock;
458 }
459 err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
460 &_flags);
461 if (!err)
462 flags = &_flags;
463 }
422 rtnl_lock(); 464 rtnl_lock();
423 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
424 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
425 &flags);
426 err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, 465 err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
427 type, err ? NULL : &flags, &params); 466 type, flags, &params);
467
468 dev = __dev_get_by_index(&init_net, ifindex);
469 WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type));
470
428 rtnl_unlock(); 471 rtnl_unlock();
429 472
430 unlock: 473 unlock:
@@ -455,7 +498,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
455 if (IS_ERR(drv)) 498 if (IS_ERR(drv))
456 return PTR_ERR(drv); 499 return PTR_ERR(drv);
457 500
458 if (!drv->ops->add_virtual_intf) { 501 if (!drv->ops->add_virtual_intf ||
502 !(drv->wiphy.interface_modes & (1 << type))) {
459 err = -EOPNOTSUPP; 503 err = -EOPNOTSUPP;
460 goto unlock; 504 goto unlock;
461 } 505 }
@@ -1125,6 +1169,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
1125 params.listen_interval = 1169 params.listen_interval =
1126 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); 1170 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
1127 1171
1172 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
1173 params.ht_capa =
1174 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
1175
1128 if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], 1176 if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
1129 &params.station_flags)) 1177 &params.station_flags))
1130 return -EINVAL; 1178 return -EINVAL;
@@ -1188,6 +1236,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
1188 params.listen_interval = 1236 params.listen_interval =
1189 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); 1237 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
1190 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); 1238 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
1239 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
1240 params.ht_capa =
1241 nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
1191 1242
1192 if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], 1243 if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
1193 &params.station_flags)) 1244 &params.station_flags))
@@ -1525,6 +1576,183 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
1525 return err; 1576 return err;
1526} 1577}
1527 1578
1579static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
1580{
1581 struct cfg80211_registered_device *drv;
1582 int err;
1583 struct net_device *dev;
1584 struct bss_parameters params;
1585
1586 memset(&params, 0, sizeof(params));
1587 /* default to not changing parameters */
1588 params.use_cts_prot = -1;
1589 params.use_short_preamble = -1;
1590 params.use_short_slot_time = -1;
1591
1592 if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
1593 params.use_cts_prot =
1594 nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]);
1595 if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE])
1596 params.use_short_preamble =
1597 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]);
1598 if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
1599 params.use_short_slot_time =
1600 nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
1601
1602 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1603 if (err)
1604 return err;
1605
1606 if (!drv->ops->change_bss) {
1607 err = -EOPNOTSUPP;
1608 goto out;
1609 }
1610
1611 rtnl_lock();
1612 err = drv->ops->change_bss(&drv->wiphy, dev, &params);
1613 rtnl_unlock();
1614
1615 out:
1616 cfg80211_put_dev(drv);
1617 dev_put(dev);
1618 return err;
1619}
1620
1621static const struct nla_policy
1622 reg_rule_policy[NL80211_REG_RULE_ATTR_MAX + 1] = {
1623 [NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
1624 [NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
1625 [NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
1626 [NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
1627 [NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
1628 [NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
1629};
1630
1631static int parse_reg_rule(struct nlattr *tb[],
1632 struct ieee80211_reg_rule *reg_rule)
1633{
1634 struct ieee80211_freq_range *freq_range = &reg_rule->freq_range;
1635 struct ieee80211_power_rule *power_rule = &reg_rule->power_rule;
1636
1637 if (!tb[NL80211_ATTR_REG_RULE_FLAGS])
1638 return -EINVAL;
1639 if (!tb[NL80211_ATTR_FREQ_RANGE_START])
1640 return -EINVAL;
1641 if (!tb[NL80211_ATTR_FREQ_RANGE_END])
1642 return -EINVAL;
1643 if (!tb[NL80211_ATTR_FREQ_RANGE_MAX_BW])
1644 return -EINVAL;
1645 if (!tb[NL80211_ATTR_POWER_RULE_MAX_EIRP])
1646 return -EINVAL;
1647
1648 reg_rule->flags = nla_get_u32(tb[NL80211_ATTR_REG_RULE_FLAGS]);
1649
1650 freq_range->start_freq_khz =
1651 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]);
1652 freq_range->end_freq_khz =
1653 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]);
1654 freq_range->max_bandwidth_khz =
1655 nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]);
1656
1657 power_rule->max_eirp =
1658 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]);
1659
1660 if (tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN])
1661 power_rule->max_antenna_gain =
1662 nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]);
1663
1664 return 0;
1665}
1666
1667static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
1668{
1669 int r;
1670 char *data = NULL;
1671
1672 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
1673 return -EINVAL;
1674
1675 data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
1676
1677#ifdef CONFIG_WIRELESS_OLD_REGULATORY
1678 /* We ignore world regdom requests with the old regdom setup */
1679 if (is_world_regdom(data))
1680 return -EINVAL;
1681#endif
1682 mutex_lock(&cfg80211_drv_mutex);
1683 r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, NULL);
1684 mutex_unlock(&cfg80211_drv_mutex);
1685 return r;
1686}
1687
1688static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
1689{
1690 struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
1691 struct nlattr *nl_reg_rule;
1692 char *alpha2 = NULL;
1693 int rem_reg_rules = 0, r = 0;
1694 u32 num_rules = 0, rule_idx = 0, size_of_regd;
1695 struct ieee80211_regdomain *rd = NULL;
1696
1697 if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
1698 return -EINVAL;
1699
1700 if (!info->attrs[NL80211_ATTR_REG_RULES])
1701 return -EINVAL;
1702
1703 alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
1704
1705 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
1706 rem_reg_rules) {
1707 num_rules++;
1708 if (num_rules > NL80211_MAX_SUPP_REG_RULES)
1709 goto bad_reg;
1710 }
1711
1712 if (!reg_is_valid_request(alpha2))
1713 return -EINVAL;
1714
1715 size_of_regd = sizeof(struct ieee80211_regdomain) +
1716 (num_rules * sizeof(struct ieee80211_reg_rule));
1717
1718 rd = kzalloc(size_of_regd, GFP_KERNEL);
1719 if (!rd)
1720 return -ENOMEM;
1721
1722 rd->n_reg_rules = num_rules;
1723 rd->alpha2[0] = alpha2[0];
1724 rd->alpha2[1] = alpha2[1];
1725
1726 nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
1727 rem_reg_rules) {
1728 nla_parse(tb, NL80211_REG_RULE_ATTR_MAX,
1729 nla_data(nl_reg_rule), nla_len(nl_reg_rule),
1730 reg_rule_policy);
1731 r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
1732 if (r)
1733 goto bad_reg;
1734
1735 rule_idx++;
1736
1737 if (rule_idx > NL80211_MAX_SUPP_REG_RULES)
1738 goto bad_reg;
1739 }
1740
1741 BUG_ON(rule_idx != num_rules);
1742
1743 mutex_lock(&cfg80211_drv_mutex);
1744 r = set_regdom(rd);
1745 mutex_unlock(&cfg80211_drv_mutex);
1746 if (r)
1747 goto bad_reg;
1748
1749 return r;
1750
1751bad_reg:
1752 kfree(rd);
1753 return -EINVAL;
1754}
1755
1528static struct genl_ops nl80211_ops[] = { 1756static struct genl_ops nl80211_ops[] = {
1529 { 1757 {
1530 .cmd = NL80211_CMD_GET_WIPHY, 1758 .cmd = NL80211_CMD_GET_WIPHY,
@@ -1656,6 +1884,24 @@ static struct genl_ops nl80211_ops[] = {
1656 .policy = nl80211_policy, 1884 .policy = nl80211_policy,
1657 .flags = GENL_ADMIN_PERM, 1885 .flags = GENL_ADMIN_PERM,
1658 }, 1886 },
1887 {
1888 .cmd = NL80211_CMD_SET_BSS,
1889 .doit = nl80211_set_bss,
1890 .policy = nl80211_policy,
1891 .flags = GENL_ADMIN_PERM,
1892 },
1893 {
1894 .cmd = NL80211_CMD_SET_REG,
1895 .doit = nl80211_set_reg,
1896 .policy = nl80211_policy,
1897 .flags = GENL_ADMIN_PERM,
1898 },
1899 {
1900 .cmd = NL80211_CMD_REQ_SET_REG,
1901 .doit = nl80211_req_set_reg,
1902 .policy = nl80211_policy,
1903 .flags = GENL_ADMIN_PERM,
1904 },
1659}; 1905};
1660 1906
1661/* multicast groups */ 1907/* multicast groups */