aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2009-12-29 05:59:45 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-12 13:51:23 -0500
commit13ae75b103e07304a34ab40c9136e9f53e06475c (patch)
tree61cfd1471cdefe8cf1a3da12b4b99aafc2770f76 /net/wireless/nl80211.c
parent37eb0b164cf9fa9f70c8500926f5cde7c652f48e (diff)
nl80211: New command for setting TX rate mask for rate control
Add a new NL80211_CMD_SET_TX_BITRATE_MASK command and related attributes to provide support for setting TX rate mask for rate control. This uses the existing cfg80211 set_bitrate_mask operation that was previously used only with WEXT compat code (SIOCSIWRATE). The nl80211 command allows more generic configuration of allowed rates as a mask instead of fixed/max rate. Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c09fbcd278fb..b804062e0179 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -144,6 +144,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
144 .len = WLAN_PMKID_LEN }, 144 .len = WLAN_PMKID_LEN },
145 [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, 145 [NL80211_ATTR_DURATION] = { .type = NLA_U32 },
146 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, 146 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
147 [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
147}; 148};
148 149
149/* policy for the attributes */ 150/* policy for the attributes */
@@ -575,6 +576,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
575 CMD(del_pmksa, DEL_PMKSA); 576 CMD(del_pmksa, DEL_PMKSA);
576 CMD(flush_pmksa, FLUSH_PMKSA); 577 CMD(flush_pmksa, FLUSH_PMKSA);
577 CMD(remain_on_channel, REMAIN_ON_CHANNEL); 578 CMD(remain_on_channel, REMAIN_ON_CHANNEL);
579 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
578 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { 580 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
579 i++; 581 i++;
580 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); 582 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
@@ -4438,6 +4440,109 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
4438 return err; 4440 return err;
4439} 4441}
4440 4442
4443static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
4444 u8 *rates, u8 rates_len)
4445{
4446 u8 i;
4447 u32 mask = 0;
4448
4449 for (i = 0; i < rates_len; i++) {
4450 int rate = (rates[i] & 0x7f) * 5;
4451 int ridx;
4452 for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
4453 struct ieee80211_rate *srate =
4454 &sband->bitrates[ridx];
4455 if (rate == srate->bitrate) {
4456 mask |= 1 << ridx;
4457 break;
4458 }
4459 }
4460 if (ridx == sband->n_bitrates)
4461 return 0; /* rate not found */
4462 }
4463
4464 return mask;
4465}
4466
4467static struct nla_policy
4468nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] __read_mostly = {
4469 [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
4470 .len = NL80211_MAX_SUPP_RATES },
4471};
4472
4473static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
4474 struct genl_info *info)
4475{
4476 struct nlattr *tb[NL80211_TXRATE_MAX + 1];
4477 struct cfg80211_registered_device *rdev;
4478 struct cfg80211_bitrate_mask mask;
4479 int err, rem, i;
4480 struct net_device *dev;
4481 struct nlattr *tx_rates;
4482 struct ieee80211_supported_band *sband;
4483
4484 if (info->attrs[NL80211_ATTR_TX_RATES] == NULL)
4485 return -EINVAL;
4486
4487 rtnl_lock();
4488
4489 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4490 if (err)
4491 goto unlock_rtnl;
4492
4493 if (!rdev->ops->set_bitrate_mask) {
4494 err = -EOPNOTSUPP;
4495 goto unlock;
4496 }
4497
4498 memset(&mask, 0, sizeof(mask));
4499 /* Default to all rates enabled */
4500 for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
4501 sband = rdev->wiphy.bands[i];
4502 mask.control[i].legacy =
4503 sband ? (1 << sband->n_bitrates) - 1 : 0;
4504 }
4505
4506 /*
4507 * The nested attribute uses enum nl80211_band as the index. This maps
4508 * directly to the enum ieee80211_band values used in cfg80211.
4509 */
4510 nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem)
4511 {
4512 enum ieee80211_band band = nla_type(tx_rates);
4513 if (band < 0 || band >= IEEE80211_NUM_BANDS) {
4514 err = -EINVAL;
4515 goto unlock;
4516 }
4517 sband = rdev->wiphy.bands[band];
4518 if (sband == NULL) {
4519 err = -EINVAL;
4520 goto unlock;
4521 }
4522 nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
4523 nla_len(tx_rates), nl80211_txattr_policy);
4524 if (tb[NL80211_TXRATE_LEGACY]) {
4525 mask.control[band].legacy = rateset_to_mask(
4526 sband,
4527 nla_data(tb[NL80211_TXRATE_LEGACY]),
4528 nla_len(tb[NL80211_TXRATE_LEGACY]));
4529 if (mask.control[band].legacy == 0) {
4530 err = -EINVAL;
4531 goto unlock;
4532 }
4533 }
4534 }
4535
4536 err = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, NULL, &mask);
4537
4538 unlock:
4539 dev_put(dev);
4540 cfg80211_unlock_rdev(rdev);
4541 unlock_rtnl:
4542 rtnl_unlock();
4543 return err;
4544}
4545
4441static struct genl_ops nl80211_ops[] = { 4546static struct genl_ops nl80211_ops[] = {
4442 { 4547 {
4443 .cmd = NL80211_CMD_GET_WIPHY, 4548 .cmd = NL80211_CMD_GET_WIPHY,
@@ -4712,6 +4817,12 @@ static struct genl_ops nl80211_ops[] = {
4712 .policy = nl80211_policy, 4817 .policy = nl80211_policy,
4713 .flags = GENL_ADMIN_PERM, 4818 .flags = GENL_ADMIN_PERM,
4714 }, 4819 },
4820 {
4821 .cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
4822 .doit = nl80211_set_tx_bitrate_mask,
4823 .policy = nl80211_policy,
4824 .flags = GENL_ADMIN_PERM,
4825 },
4715}; 4826};
4716 4827
4717static struct genl_multicast_group nl80211_mlme_mcgrp = { 4828static struct genl_multicast_group nl80211_mlme_mcgrp = {