diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-02-21 11:36:01 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-03-06 10:35:47 -0500 |
commit | ee2aca343c9aa64d277a75a5df043299dc84cfd9 (patch) | |
tree | 697ac55d4d0119e97ead3a530ebac8cf37922f78 /net | |
parent | c8bb93f5f5d478a01db66127844d1d2dd30abec7 (diff) |
cfg80211: add ability to override VHT capabilities
For testing it's sometimes useful to be able to
override certain VHT capability advertisement,
add the ability to do that in cfg80211.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/wireless/core.h | 10 | ||||
-rw-r--r-- | net/wireless/mlme.c | 35 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 47 | ||||
-rw-r--r-- | net/wireless/sme.c | 4 |
4 files changed, 88 insertions, 8 deletions
diff --git a/net/wireless/core.h b/net/wireless/core.h index 3aec0e429d8a..c2f94f22bb22 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -335,7 +335,9 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
335 | const u8 *ie, int ie_len, bool use_mfp, | 335 | const u8 *ie, int ie_len, bool use_mfp, |
336 | struct cfg80211_crypto_settings *crypt, | 336 | struct cfg80211_crypto_settings *crypt, |
337 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | 337 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, |
338 | struct ieee80211_ht_cap *ht_capa_mask); | 338 | struct ieee80211_ht_cap *ht_capa_mask, |
339 | struct ieee80211_vht_cap *vht_capa, | ||
340 | struct ieee80211_vht_cap *vht_capa_mask); | ||
339 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 341 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
340 | struct net_device *dev, struct ieee80211_channel *chan, | 342 | struct net_device *dev, struct ieee80211_channel *chan, |
341 | const u8 *bssid, const u8 *prev_bssid, | 343 | const u8 *bssid, const u8 *prev_bssid, |
@@ -343,7 +345,9 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
343 | const u8 *ie, int ie_len, bool use_mfp, | 345 | const u8 *ie, int ie_len, bool use_mfp, |
344 | struct cfg80211_crypto_settings *crypt, | 346 | struct cfg80211_crypto_settings *crypt, |
345 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | 347 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, |
346 | struct ieee80211_ht_cap *ht_capa_mask); | 348 | struct ieee80211_ht_cap *ht_capa_mask, |
349 | struct ieee80211_vht_cap *vht_capa, | ||
350 | struct ieee80211_vht_cap *vht_capa_mask); | ||
347 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | 351 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, |
348 | struct net_device *dev, const u8 *bssid, | 352 | struct net_device *dev, const u8 *bssid, |
349 | const u8 *ie, int ie_len, u16 reason, | 353 | const u8 *ie, int ie_len, u16 reason, |
@@ -375,6 +379,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
375 | bool no_cck, bool dont_wait_for_ack, u64 *cookie); | 379 | bool no_cck, bool dont_wait_for_ack, u64 *cookie); |
376 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | 380 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, |
377 | const struct ieee80211_ht_cap *ht_capa_mask); | 381 | const struct ieee80211_ht_cap *ht_capa_mask); |
382 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, | ||
383 | const struct ieee80211_vht_cap *vht_capa_mask); | ||
378 | 384 | ||
379 | /* SME */ | 385 | /* SME */ |
380 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 386 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 5a97ce6d283b..c82adfee7697 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -343,6 +343,23 @@ void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | |||
343 | p1[i] &= p2[i]; | 343 | p1[i] &= p2[i]; |
344 | } | 344 | } |
345 | 345 | ||
346 | /* Do a logical ht_capa &= ht_capa_mask. */ | ||
347 | void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa, | ||
348 | const struct ieee80211_vht_cap *vht_capa_mask) | ||
349 | { | ||
350 | int i; | ||
351 | u8 *p1, *p2; | ||
352 | if (!vht_capa_mask) { | ||
353 | memset(vht_capa, 0, sizeof(*vht_capa)); | ||
354 | return; | ||
355 | } | ||
356 | |||
357 | p1 = (u8*)(vht_capa); | ||
358 | p2 = (u8*)(vht_capa_mask); | ||
359 | for (i = 0; i < sizeof(*vht_capa); i++) | ||
360 | p1[i] &= p2[i]; | ||
361 | } | ||
362 | |||
346 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 363 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
347 | struct net_device *dev, | 364 | struct net_device *dev, |
348 | struct ieee80211_channel *chan, | 365 | struct ieee80211_channel *chan, |
@@ -351,7 +368,9 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
351 | const u8 *ie, int ie_len, bool use_mfp, | 368 | const u8 *ie, int ie_len, bool use_mfp, |
352 | struct cfg80211_crypto_settings *crypt, | 369 | struct cfg80211_crypto_settings *crypt, |
353 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | 370 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, |
354 | struct ieee80211_ht_cap *ht_capa_mask) | 371 | struct ieee80211_ht_cap *ht_capa_mask, |
372 | struct ieee80211_vht_cap *vht_capa, | ||
373 | struct ieee80211_vht_cap *vht_capa_mask) | ||
355 | { | 374 | { |
356 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 375 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
357 | struct cfg80211_assoc_request req; | 376 | struct cfg80211_assoc_request req; |
@@ -388,6 +407,13 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
388 | sizeof(req.ht_capa_mask)); | 407 | sizeof(req.ht_capa_mask)); |
389 | cfg80211_oper_and_ht_capa(&req.ht_capa_mask, | 408 | cfg80211_oper_and_ht_capa(&req.ht_capa_mask, |
390 | rdev->wiphy.ht_capa_mod_mask); | 409 | rdev->wiphy.ht_capa_mod_mask); |
410 | if (vht_capa) | ||
411 | memcpy(&req.vht_capa, vht_capa, sizeof(req.vht_capa)); | ||
412 | if (vht_capa_mask) | ||
413 | memcpy(&req.vht_capa_mask, vht_capa_mask, | ||
414 | sizeof(req.vht_capa_mask)); | ||
415 | cfg80211_oper_and_vht_capa(&req.vht_capa_mask, | ||
416 | rdev->wiphy.vht_capa_mod_mask); | ||
391 | 417 | ||
392 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, | 418 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, |
393 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | 419 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); |
@@ -422,7 +448,9 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
422 | const u8 *ie, int ie_len, bool use_mfp, | 448 | const u8 *ie, int ie_len, bool use_mfp, |
423 | struct cfg80211_crypto_settings *crypt, | 449 | struct cfg80211_crypto_settings *crypt, |
424 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | 450 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, |
425 | struct ieee80211_ht_cap *ht_capa_mask) | 451 | struct ieee80211_ht_cap *ht_capa_mask, |
452 | struct ieee80211_vht_cap *vht_capa, | ||
453 | struct ieee80211_vht_cap *vht_capa_mask) | ||
426 | { | 454 | { |
427 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 455 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
428 | int err; | 456 | int err; |
@@ -431,7 +459,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
431 | wdev_lock(wdev); | 459 | wdev_lock(wdev); |
432 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 460 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, |
433 | ssid, ssid_len, ie, ie_len, use_mfp, crypt, | 461 | ssid, ssid_len, ie, ie_len, use_mfp, crypt, |
434 | assoc_flags, ht_capa, ht_capa_mask); | 462 | assoc_flags, ht_capa, ht_capa_mask, |
463 | vht_capa, vht_capa_mask); | ||
435 | wdev_unlock(wdev); | 464 | wdev_unlock(wdev); |
436 | mutex_unlock(&rdev->devlist_mtx); | 465 | mutex_unlock(&rdev->devlist_mtx); |
437 | 466 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0e5176784b42..6a5893f5e481 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -371,6 +371,10 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
371 | [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 }, | 371 | [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 }, |
372 | [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, }, | 372 | [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, }, |
373 | [NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, }, | 373 | [NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, }, |
374 | [NL80211_ATTR_DISABLE_VHT] = { .type = NLA_FLAG }, | ||
375 | [NL80211_ATTR_VHT_CAPABILITY_MASK] = { | ||
376 | .len = NL80211_VHT_CAPABILITY_LEN, | ||
377 | }, | ||
374 | }; | 378 | }; |
375 | 379 | ||
376 | /* policy for the key attributes */ | 380 | /* policy for the key attributes */ |
@@ -1522,6 +1526,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev, | |||
1522 | dev->wiphy.extended_capabilities_mask))) | 1526 | dev->wiphy.extended_capabilities_mask))) |
1523 | goto nla_put_failure; | 1527 | goto nla_put_failure; |
1524 | 1528 | ||
1529 | if (dev->wiphy.vht_capa_mod_mask && | ||
1530 | nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, | ||
1531 | sizeof(*dev->wiphy.vht_capa_mod_mask), | ||
1532 | dev->wiphy.vht_capa_mod_mask)) | ||
1533 | goto nla_put_failure; | ||
1534 | |||
1525 | /* done */ | 1535 | /* done */ |
1526 | *split_start = 0; | 1536 | *split_start = 0; |
1527 | break; | 1537 | break; |
@@ -5982,6 +5992,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
5982 | u32 flags = 0; | 5992 | u32 flags = 0; |
5983 | struct ieee80211_ht_cap *ht_capa = NULL; | 5993 | struct ieee80211_ht_cap *ht_capa = NULL; |
5984 | struct ieee80211_ht_cap *ht_capa_mask = NULL; | 5994 | struct ieee80211_ht_cap *ht_capa_mask = NULL; |
5995 | struct ieee80211_vht_cap *vht_capa = NULL; | ||
5996 | struct ieee80211_vht_cap *vht_capa_mask = NULL; | ||
5985 | 5997 | ||
5986 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 5998 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
5987 | return -EINVAL; | 5999 | return -EINVAL; |
@@ -6038,12 +6050,25 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
6038 | ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 6050 | ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); |
6039 | } | 6051 | } |
6040 | 6052 | ||
6053 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT])) | ||
6054 | flags |= ASSOC_REQ_DISABLE_VHT; | ||
6055 | |||
6056 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) | ||
6057 | vht_capa_mask = | ||
6058 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]); | ||
6059 | |||
6060 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) { | ||
6061 | if (!vht_capa_mask) | ||
6062 | return -EINVAL; | ||
6063 | vht_capa = nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); | ||
6064 | } | ||
6065 | |||
6041 | err = nl80211_crypto_settings(rdev, info, &crypto, 1); | 6066 | err = nl80211_crypto_settings(rdev, info, &crypto, 1); |
6042 | if (!err) | 6067 | if (!err) |
6043 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 6068 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, |
6044 | ssid, ssid_len, ie, ie_len, use_mfp, | 6069 | ssid, ssid_len, ie, ie_len, use_mfp, |
6045 | &crypto, flags, ht_capa, | 6070 | &crypto, flags, ht_capa, ht_capa_mask, |
6046 | ht_capa_mask); | 6071 | vht_capa, vht_capa_mask); |
6047 | 6072 | ||
6048 | return err; | 6073 | return err; |
6049 | } | 6074 | } |
@@ -6623,6 +6648,24 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
6623 | sizeof(connect.ht_capa)); | 6648 | sizeof(connect.ht_capa)); |
6624 | } | 6649 | } |
6625 | 6650 | ||
6651 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT])) | ||
6652 | connect.flags |= ASSOC_REQ_DISABLE_VHT; | ||
6653 | |||
6654 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) | ||
6655 | memcpy(&connect.vht_capa_mask, | ||
6656 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]), | ||
6657 | sizeof(connect.vht_capa_mask)); | ||
6658 | |||
6659 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) { | ||
6660 | if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) { | ||
6661 | kfree(connkeys); | ||
6662 | return -EINVAL; | ||
6663 | } | ||
6664 | memcpy(&connect.vht_capa, | ||
6665 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]), | ||
6666 | sizeof(connect.vht_capa)); | ||
6667 | } | ||
6668 | |||
6626 | err = cfg80211_connect(rdev, dev, &connect, connkeys); | 6669 | err = cfg80211_connect(rdev, dev, &connect, connkeys); |
6627 | if (err) | 6670 | if (err) |
6628 | kfree(connkeys); | 6671 | kfree(connkeys); |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f432bd3755b1..7da118c034f0 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -195,7 +195,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
195 | params->mfp != NL80211_MFP_NO, | 195 | params->mfp != NL80211_MFP_NO, |
196 | ¶ms->crypto, | 196 | ¶ms->crypto, |
197 | params->flags, ¶ms->ht_capa, | 197 | params->flags, ¶ms->ht_capa, |
198 | ¶ms->ht_capa_mask); | 198 | ¶ms->ht_capa_mask, |
199 | ¶ms->vht_capa, | ||
200 | ¶ms->vht_capa_mask); | ||
199 | if (err) | 201 | if (err) |
200 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, | 202 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, |
201 | NULL, 0, | 203 | NULL, 0, |