diff options
| author | Jouni Malinen <jouni.malinen@atheros.com> | 2009-12-29 05:59:45 -0500 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2010-01-12 13:51:23 -0500 |
| commit | 13ae75b103e07304a34ab40c9136e9f53e06475c (patch) | |
| tree | 61cfd1471cdefe8cf1a3da12b4b99aafc2770f76 | |
| parent | 37eb0b164cf9fa9f70c8500926f5cde7c652f48e (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.h | 44 | ||||
| -rw-r--r-- | include/net/cfg80211.h | 4 | ||||
| -rw-r--r-- | net/wireless/nl80211.c | 111 |
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 | */ | ||
| 1510 | enum 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 | */ | ||
| 1524 | enum 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 | */ |
| 41 | enum ieee80211_band { | 41 | enum 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 | ||
| 4443 | static 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 | |||
| 4467 | static struct nla_policy | ||
| 4468 | nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] __read_mostly = { | ||
| 4469 | [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY, | ||
| 4470 | .len = NL80211_MAX_SUPP_RATES }, | ||
| 4471 | }; | ||
| 4472 | |||
| 4473 | static 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 | |||
| 4441 | static struct genl_ops nl80211_ops[] = { | 4546 | static 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 | ||
| 4717 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 4828 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
