diff options
author | Ben Greear <greearb@candelatech.com> | 2011-11-18 14:31:59 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-21 16:22:06 -0500 |
commit | 7e7c8926b2f4e3453b8aeb39cd814d2af3fec24f (patch) | |
tree | e22df42bf84d6ea3cb67ae0e332d7d7d10cca4b4 /net/wireless | |
parent | dd76986b0e398978ca32dd60c1b7dc50ab4e9ae1 (diff) |
wireless: Support ht-capabilities over-rides.
This allows users to disable features such as HT, HT40,
and to modify the MCS, AMPDU, and AMSDU settings for
drivers that support it.
The MCS, AMPDU, and AMSDU features that may be disabled are
are reported in the phy-info netlink message as a mask.
Attemping to disable features that are not supported will
take no affect, but will not return errors. This is to aid
backwards compatibility in user-space apps that may not be
clever enough to deal with parsing the the capabilities mask.
This patch only enables the infrastructure. An additional
patch will enable the feature in mac80211.
Signed-off-by: Ben Greear <greearb@candelatech.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.h | 10 | ||||
-rw-r--r-- | net/wireless/mlme.c | 37 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 44 | ||||
-rw-r--r-- | net/wireless/sme.c | 7 |
4 files changed, 91 insertions, 7 deletions
diff --git a/net/wireless/core.h b/net/wireless/core.h index 1c7d4df5418c..fb08c28fc90a 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -341,13 +341,17 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
341 | const u8 *bssid, const u8 *prev_bssid, | 341 | const u8 *bssid, const u8 *prev_bssid, |
342 | const u8 *ssid, int ssid_len, | 342 | const u8 *ssid, int ssid_len, |
343 | const u8 *ie, int ie_len, bool use_mfp, | 343 | const u8 *ie, int ie_len, bool use_mfp, |
344 | struct cfg80211_crypto_settings *crypt); | 344 | struct cfg80211_crypto_settings *crypt, |
345 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
346 | struct ieee80211_ht_cap *ht_capa_mask); | ||
345 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 347 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
346 | struct net_device *dev, struct ieee80211_channel *chan, | 348 | struct net_device *dev, struct ieee80211_channel *chan, |
347 | const u8 *bssid, const u8 *prev_bssid, | 349 | const u8 *bssid, const u8 *prev_bssid, |
348 | const u8 *ssid, int ssid_len, | 350 | const u8 *ssid, int ssid_len, |
349 | const u8 *ie, int ie_len, bool use_mfp, | 351 | const u8 *ie, int ie_len, bool use_mfp, |
350 | struct cfg80211_crypto_settings *crypt); | 352 | struct cfg80211_crypto_settings *crypt, |
353 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
354 | struct ieee80211_ht_cap *ht_capa_mask); | ||
351 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | 355 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, |
352 | struct net_device *dev, const u8 *bssid, | 356 | struct net_device *dev, const u8 *bssid, |
353 | const u8 *ie, int ie_len, u16 reason, | 357 | const u8 *ie, int ie_len, u16 reason, |
@@ -379,6 +383,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
379 | bool channel_type_valid, unsigned int wait, | 383 | bool channel_type_valid, unsigned int wait, |
380 | const u8 *buf, size_t len, bool no_cck, | 384 | const u8 *buf, size_t len, bool no_cck, |
381 | bool dont_wait_for_ack, u64 *cookie); | 385 | bool dont_wait_for_ack, u64 *cookie); |
386 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | ||
387 | const struct ieee80211_ht_cap *ht_capa_mask); | ||
382 | 388 | ||
383 | /* SME */ | 389 | /* SME */ |
384 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 390 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 6c1bafd508c8..438dfc105b4a 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -501,13 +501,32 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
501 | return err; | 501 | return err; |
502 | } | 502 | } |
503 | 503 | ||
504 | /* Do a logical ht_capa &= ht_capa_mask. */ | ||
505 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | ||
506 | const struct ieee80211_ht_cap *ht_capa_mask) | ||
507 | { | ||
508 | int i; | ||
509 | u8 *p1, *p2; | ||
510 | if (!ht_capa_mask) { | ||
511 | memset(ht_capa, 0, sizeof(*ht_capa)); | ||
512 | return; | ||
513 | } | ||
514 | |||
515 | p1 = (u8*)(ht_capa); | ||
516 | p2 = (u8*)(ht_capa_mask); | ||
517 | for (i = 0; i<sizeof(*ht_capa); i++) | ||
518 | p1[i] &= p2[i]; | ||
519 | } | ||
520 | |||
504 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 521 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
505 | struct net_device *dev, | 522 | struct net_device *dev, |
506 | struct ieee80211_channel *chan, | 523 | struct ieee80211_channel *chan, |
507 | const u8 *bssid, const u8 *prev_bssid, | 524 | const u8 *bssid, const u8 *prev_bssid, |
508 | const u8 *ssid, int ssid_len, | 525 | const u8 *ssid, int ssid_len, |
509 | const u8 *ie, int ie_len, bool use_mfp, | 526 | const u8 *ie, int ie_len, bool use_mfp, |
510 | struct cfg80211_crypto_settings *crypt) | 527 | struct cfg80211_crypto_settings *crypt, |
528 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
529 | struct ieee80211_ht_cap *ht_capa_mask) | ||
511 | { | 530 | { |
512 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 531 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
513 | struct cfg80211_assoc_request req; | 532 | struct cfg80211_assoc_request req; |
@@ -537,6 +556,15 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
537 | memcpy(&req.crypto, crypt, sizeof(req.crypto)); | 556 | memcpy(&req.crypto, crypt, sizeof(req.crypto)); |
538 | req.use_mfp = use_mfp; | 557 | req.use_mfp = use_mfp; |
539 | req.prev_bssid = prev_bssid; | 558 | req.prev_bssid = prev_bssid; |
559 | req.flags = assoc_flags; | ||
560 | if (ht_capa) | ||
561 | memcpy(&req.ht_capa, ht_capa, sizeof(req.ht_capa)); | ||
562 | if (ht_capa_mask) | ||
563 | memcpy(&req.ht_capa_mask, ht_capa_mask, | ||
564 | sizeof(req.ht_capa_mask)); | ||
565 | cfg80211_oper_and_ht_capa(&req.ht_capa_mask, | ||
566 | rdev->wiphy.ht_capa_mod_mask); | ||
567 | |||
540 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, | 568 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, |
541 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | 569 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); |
542 | if (!req.bss) { | 570 | if (!req.bss) { |
@@ -574,14 +602,17 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
574 | const u8 *bssid, const u8 *prev_bssid, | 602 | const u8 *bssid, const u8 *prev_bssid, |
575 | const u8 *ssid, int ssid_len, | 603 | const u8 *ssid, int ssid_len, |
576 | const u8 *ie, int ie_len, bool use_mfp, | 604 | const u8 *ie, int ie_len, bool use_mfp, |
577 | struct cfg80211_crypto_settings *crypt) | 605 | struct cfg80211_crypto_settings *crypt, |
606 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
607 | struct ieee80211_ht_cap *ht_capa_mask) | ||
578 | { | 608 | { |
579 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 609 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
580 | int err; | 610 | int err; |
581 | 611 | ||
582 | wdev_lock(wdev); | 612 | wdev_lock(wdev); |
583 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 613 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, |
584 | ssid, ssid_len, ie, ie_len, use_mfp, crypt); | 614 | ssid, ssid_len, ie, ie_len, use_mfp, crypt, |
615 | assoc_flags, ht_capa, ht_capa_mask); | ||
585 | wdev_unlock(wdev); | 616 | wdev_unlock(wdev); |
586 | 617 | ||
587 | return err; | 618 | return err; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 889f06483862..a1cabde7cb5f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -200,6 +200,10 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
200 | [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, | 200 | [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, |
201 | .len = IEEE80211_MAX_DATA_LEN }, | 201 | .len = IEEE80211_MAX_DATA_LEN }, |
202 | [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 }, | 202 | [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 }, |
203 | [NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG }, | ||
204 | [NL80211_ATTR_HT_CAPABILITY_MASK] = { | ||
205 | .len = NL80211_HT_CAPABILITY_LEN | ||
206 | }, | ||
203 | }; | 207 | }; |
204 | 208 | ||
205 | /* policy for the key attributes */ | 209 | /* policy for the key attributes */ |
@@ -1032,6 +1036,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1032 | 1036 | ||
1033 | NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features); | 1037 | NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features); |
1034 | 1038 | ||
1039 | if (dev->wiphy.ht_capa_mod_mask) | ||
1040 | NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, | ||
1041 | sizeof(*dev->wiphy.ht_capa_mod_mask), | ||
1042 | dev->wiphy.ht_capa_mod_mask); | ||
1043 | |||
1035 | return genlmsg_end(msg, hdr); | 1044 | return genlmsg_end(msg, hdr); |
1036 | 1045 | ||
1037 | nla_put_failure: | 1046 | nla_put_failure: |
@@ -4413,6 +4422,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
4413 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; | 4422 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; |
4414 | int err, ssid_len, ie_len = 0; | 4423 | int err, ssid_len, ie_len = 0; |
4415 | bool use_mfp = false; | 4424 | bool use_mfp = false; |
4425 | u32 flags = 0; | ||
4426 | struct ieee80211_ht_cap *ht_capa = NULL; | ||
4427 | struct ieee80211_ht_cap *ht_capa_mask = NULL; | ||
4416 | 4428 | ||
4417 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 4429 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
4418 | return -EINVAL; | 4430 | return -EINVAL; |
@@ -4456,11 +4468,25 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
4456 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) | 4468 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) |
4457 | prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); | 4469 | prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); |
4458 | 4470 | ||
4471 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT])) | ||
4472 | flags |= ASSOC_REQ_DISABLE_HT; | ||
4473 | |||
4474 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) | ||
4475 | ht_capa_mask = | ||
4476 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]); | ||
4477 | |||
4478 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) { | ||
4479 | if (!ht_capa_mask) | ||
4480 | return -EINVAL; | ||
4481 | ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | ||
4482 | } | ||
4483 | |||
4459 | err = nl80211_crypto_settings(rdev, info, &crypto, 1); | 4484 | err = nl80211_crypto_settings(rdev, info, &crypto, 1); |
4460 | if (!err) | 4485 | if (!err) |
4461 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 4486 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, |
4462 | ssid, ssid_len, ie, ie_len, use_mfp, | 4487 | ssid, ssid_len, ie, ie_len, use_mfp, |
4463 | &crypto); | 4488 | &crypto, flags, ht_capa, |
4489 | ht_capa_mask); | ||
4464 | 4490 | ||
4465 | return err; | 4491 | return err; |
4466 | } | 4492 | } |
@@ -4950,6 +4976,22 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
4950 | return PTR_ERR(connkeys); | 4976 | return PTR_ERR(connkeys); |
4951 | } | 4977 | } |
4952 | 4978 | ||
4979 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT])) | ||
4980 | connect.flags |= ASSOC_REQ_DISABLE_HT; | ||
4981 | |||
4982 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) | ||
4983 | memcpy(&connect.ht_capa_mask, | ||
4984 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]), | ||
4985 | sizeof(connect.ht_capa_mask)); | ||
4986 | |||
4987 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) { | ||
4988 | if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) | ||
4989 | return -EINVAL; | ||
4990 | memcpy(&connect.ht_capa, | ||
4991 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]), | ||
4992 | sizeof(connect.ht_capa)); | ||
4993 | } | ||
4994 | |||
4953 | err = cfg80211_connect(rdev, dev, &connect, connkeys); | 4995 | err = cfg80211_connect(rdev, dev, &connect, connkeys); |
4954 | if (err) | 4996 | if (err) |
4955 | kfree(connkeys); | 4997 | kfree(connkeys); |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 6e86d5acf145..ed9d0e6f4a06 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -189,7 +189,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
189 | prev_bssid, | 189 | prev_bssid, |
190 | params->ssid, params->ssid_len, | 190 | params->ssid, params->ssid_len, |
191 | params->ie, params->ie_len, | 191 | params->ie, params->ie_len, |
192 | false, ¶ms->crypto); | 192 | false, ¶ms->crypto, |
193 | params->flags, ¶ms->ht_capa, | ||
194 | ¶ms->ht_capa_mask); | ||
193 | if (err) | 195 | if (err) |
194 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, | 196 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, |
195 | NULL, 0, | 197 | NULL, 0, |
@@ -773,6 +775,9 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
773 | wdev->connect_keys = NULL; | 775 | wdev->connect_keys = NULL; |
774 | } | 776 | } |
775 | 777 | ||
778 | cfg80211_oper_and_ht_capa(&connect->ht_capa_mask, | ||
779 | rdev->wiphy.ht_capa_mod_mask); | ||
780 | |||
776 | if (connkeys && connkeys->def >= 0) { | 781 | if (connkeys && connkeys->def >= 0) { |
777 | int idx; | 782 | int idx; |
778 | u32 cipher; | 783 | u32 cipher; |