aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/linux/nl80211.h44
-rw-r--r--include/net/cfg80211.h4
-rw-r--r--net/wireless/nl80211.c111
3 files changed, 157 insertions, 2 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index d4c556de7170..7a1c8c145b22 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -295,6 +295,10 @@
295 * This command is also used as an event to notify when a requested 295 * This command is also used as an event to notify when a requested
296 * remain-on-channel duration has expired. 296 * remain-on-channel duration has expired.
297 * 297 *
298 * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX
299 * rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface
300 * and @NL80211_ATTR_TX_RATES the set of allowed rates.
301 *
298 * @NL80211_CMD_MAX: highest used command number 302 * @NL80211_CMD_MAX: highest used command number
299 * @__NL80211_CMD_AFTER_LAST: internal use 303 * @__NL80211_CMD_AFTER_LAST: internal use
300 */ 304 */
@@ -381,6 +385,8 @@ enum nl80211_commands {
381 NL80211_CMD_REMAIN_ON_CHANNEL, 385 NL80211_CMD_REMAIN_ON_CHANNEL,
382 NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, 386 NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
383 387
388 NL80211_CMD_SET_TX_BITRATE_MASK,
389
384 /* add new commands above here */ 390 /* add new commands above here */
385 391
386 /* used to define NL80211_CMD_MAX below */ 392 /* used to define NL80211_CMD_MAX below */
@@ -640,6 +646,13 @@ enum nl80211_commands {
640 * 646 *
641 * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects. 647 * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects.
642 * 648 *
649 * @NL80211_ATTR_TX_RATES: Nested set of attributes
650 * (enum nl80211_tx_rate_attributes) describing TX rates per band. The
651 * enum nl80211_band value is used as the index (nla_type() of the nested
652 * data. If a band is not included, it will be configured to allow all
653 * rates based on negotiated supported rates information. This attribute
654 * is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
655 *
643 * @NL80211_ATTR_MAX: highest attribute number currently defined 656 * @NL80211_ATTR_MAX: highest attribute number currently defined
644 * @__NL80211_ATTR_AFTER_LAST: internal use 657 * @__NL80211_ATTR_AFTER_LAST: internal use
645 */ 658 */
@@ -783,6 +796,8 @@ enum nl80211_attrs {
783 796
784 NL80211_ATTR_WIPHY_COVERAGE_CLASS, 797 NL80211_ATTR_WIPHY_COVERAGE_CLASS,
785 798
799 NL80211_ATTR_TX_RATES,
800
786 /* add attributes here, update the policy in nl80211.c */ 801 /* add attributes here, update the policy in nl80211.c */
787 802
788 __NL80211_ATTR_AFTER_LAST, 803 __NL80211_ATTR_AFTER_LAST,
@@ -1482,4 +1497,33 @@ enum nl80211_key_attributes {
1482 NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1 1497 NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
1483}; 1498};
1484 1499
1500/**
1501 * enum nl80211_tx_rate_attributes - TX rate set attributes
1502 * @__NL80211_TXRATE_INVALID: invalid
1503 * @NL80211_TXRATE_LEGACY: Legacy (non-MCS) rates allowed for TX rate selection
1504 * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with
1505 * 1 = 500 kbps) but without the IE length restriction (at most
1506 * %NL80211_MAX_SUPP_RATES in a single array).
1507 * @__NL80211_TXRATE_AFTER_LAST: internal
1508 * @NL80211_TXRATE_MAX: highest TX rate attribute
1509 */
1510enum nl80211_tx_rate_attributes {
1511 __NL80211_TXRATE_INVALID,
1512 NL80211_TXRATE_LEGACY,
1513
1514 /* keep last */
1515 __NL80211_TXRATE_AFTER_LAST,
1516 NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1
1517};
1518
1519/**
1520 * enum nl80211_band - Frequency band
1521 * @NL80211_BAND_2GHZ - 2.4 GHz ISM band
1522 * @NL80211_BAND_5GHZ - around 5 GHz band (4.9 - 5.7 GHz)
1523 */
1524enum nl80211_band {
1525 NL80211_BAND_2GHZ,
1526 NL80211_BAND_5GHZ,
1527};
1528
1485#endif /* __LINUX_NL80211_H */ 1529#endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 22e062afb5a1..0d734413b5fb 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -39,8 +39,8 @@
39 * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7) 39 * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7)
40 */ 40 */
41enum ieee80211_band { 41enum ieee80211_band {
42 IEEE80211_BAND_2GHZ, 42 IEEE80211_BAND_2GHZ = NL80211_BAND_2GHZ,
43 IEEE80211_BAND_5GHZ, 43 IEEE80211_BAND_5GHZ = NL80211_BAND_5GHZ,
44 44
45 /* keep last */ 45 /* keep last */
46 IEEE80211_NUM_BANDS 46 IEEE80211_NUM_BANDS
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 = {