diff options
author | Jouni Malinen <jouni@qca.qualcomm.com> | 2013-02-14 14:10:54 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-02-15 03:41:43 -0500 |
commit | df881293c6ba9a12868491a717b25cb14ec1fa4a (patch) | |
tree | 37ac4ed0321ce4cf626108fff6afbf92beaf845d /net/wireless | |
parent | 9d62a98617298c1da288f50e84c5dd67732e79b7 (diff) |
cfg80211: Pass TDLS peer's QoS/HT/VHT information during set_station
The information of the peer's capabilities is required for the driver
to perform TDLS Peer UAPSD operations. This information of the peer is
passed by the supplicant using NL80211_CMD_SET_STATION command. This
commit enhances the function nl80211_set_station to pass this
information of the peer to the driver in case this command is used
with the TDLS peer STA.
In addition, make the HT/VHT capability configuration handled more
consistently for other STA cases (reject both instead of just HT).
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/nl80211.c | 90 |
1 files changed, 81 insertions, 9 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index be9f2b5a403f..580ffeaef3d5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -3409,6 +3409,63 @@ static struct net_device *get_vlan(struct genl_info *info, | |||
3409 | return ERR_PTR(ret); | 3409 | return ERR_PTR(ret); |
3410 | } | 3410 | } |
3411 | 3411 | ||
3412 | static struct nla_policy | ||
3413 | nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = { | ||
3414 | [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, | ||
3415 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, | ||
3416 | }; | ||
3417 | |||
3418 | static int nl80211_set_station_tdls(struct genl_info *info, | ||
3419 | struct station_parameters *params) | ||
3420 | { | ||
3421 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
3422 | struct nlattr *tb[NL80211_STA_WME_MAX + 1]; | ||
3423 | struct nlattr *nla; | ||
3424 | int err; | ||
3425 | |||
3426 | /* Can only set if TDLS ... */ | ||
3427 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS)) | ||
3428 | return -EOPNOTSUPP; | ||
3429 | |||
3430 | /* ... with external setup is supported */ | ||
3431 | if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)) | ||
3432 | return -EOPNOTSUPP; | ||
3433 | |||
3434 | /* Dummy STA entry gets updated once the peer capabilities are known */ | ||
3435 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | ||
3436 | params->ht_capa = | ||
3437 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | ||
3438 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3439 | params->vht_capa = | ||
3440 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); | ||
3441 | |||
3442 | /* parse WME attributes if present */ | ||
3443 | if (!info->attrs[NL80211_ATTR_STA_WME]) | ||
3444 | return 0; | ||
3445 | |||
3446 | nla = info->attrs[NL80211_ATTR_STA_WME]; | ||
3447 | err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla, | ||
3448 | nl80211_sta_wme_policy); | ||
3449 | if (err) | ||
3450 | return err; | ||
3451 | |||
3452 | if (tb[NL80211_STA_WME_UAPSD_QUEUES]) | ||
3453 | params->uapsd_queues = nla_get_u8( | ||
3454 | tb[NL80211_STA_WME_UAPSD_QUEUES]); | ||
3455 | if (params->uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) | ||
3456 | return -EINVAL; | ||
3457 | |||
3458 | if (tb[NL80211_STA_WME_MAX_SP]) | ||
3459 | params->max_sp = nla_get_u8(tb[NL80211_STA_WME_MAX_SP]); | ||
3460 | |||
3461 | if (params->max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) | ||
3462 | return -EINVAL; | ||
3463 | |||
3464 | params->sta_modify_mask |= STATION_PARAM_APPLY_UAPSD; | ||
3465 | |||
3466 | return 0; | ||
3467 | } | ||
3468 | |||
3412 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 3469 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
3413 | { | 3470 | { |
3414 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 3471 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -3450,8 +3507,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3450 | nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]); | 3507 | nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]); |
3451 | } | 3508 | } |
3452 | 3509 | ||
3453 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL] || | 3510 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) |
3454 | info->attrs[NL80211_ATTR_HT_CAPABILITY]) | ||
3455 | return -EINVAL; | 3511 | return -EINVAL; |
3456 | 3512 | ||
3457 | if (!rdev->ops->change_station) | 3513 | if (!rdev->ops->change_station) |
@@ -3524,6 +3580,9 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3524 | return -EINVAL; | 3580 | return -EINVAL; |
3525 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) | 3581 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) |
3526 | return -EINVAL; | 3582 | return -EINVAL; |
3583 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
3584 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3585 | return -EINVAL; | ||
3527 | 3586 | ||
3528 | /* must be last in here for error handling */ | 3587 | /* must be last in here for error handling */ |
3529 | params.vlan = get_vlan(info, rdev); | 3588 | params.vlan = get_vlan(info, rdev); |
@@ -3539,13 +3598,29 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3539 | * to change the flag. | 3598 | * to change the flag. |
3540 | */ | 3599 | */ |
3541 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | 3600 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); |
3542 | /* fall through */ | 3601 | /* Include parameters for TDLS peer (driver will check) */ |
3602 | err = nl80211_set_station_tdls(info, ¶ms); | ||
3603 | if (err) | ||
3604 | return err; | ||
3605 | /* disallow things sta doesn't support */ | ||
3606 | if (params.plink_action) | ||
3607 | return -EINVAL; | ||
3608 | if (params.local_pm) | ||
3609 | return -EINVAL; | ||
3610 | /* reject any changes other than AUTHORIZED or WME (for TDLS) */ | ||
3611 | if (params.sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
3612 | BIT(NL80211_STA_FLAG_WME))) | ||
3613 | return -EINVAL; | ||
3614 | break; | ||
3543 | case NL80211_IFTYPE_ADHOC: | 3615 | case NL80211_IFTYPE_ADHOC: |
3544 | /* disallow things sta doesn't support */ | 3616 | /* disallow things sta doesn't support */ |
3545 | if (params.plink_action) | 3617 | if (params.plink_action) |
3546 | return -EINVAL; | 3618 | return -EINVAL; |
3547 | if (params.local_pm) | 3619 | if (params.local_pm) |
3548 | return -EINVAL; | 3620 | return -EINVAL; |
3621 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
3622 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3623 | return -EINVAL; | ||
3549 | /* reject any changes other than AUTHORIZED */ | 3624 | /* reject any changes other than AUTHORIZED */ |
3550 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) | 3625 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) |
3551 | return -EINVAL; | 3626 | return -EINVAL; |
@@ -3560,6 +3635,9 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3560 | return -EINVAL; | 3635 | return -EINVAL; |
3561 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) | 3636 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) |
3562 | return -EINVAL; | 3637 | return -EINVAL; |
3638 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
3639 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3640 | return -EINVAL; | ||
3563 | /* | 3641 | /* |
3564 | * No special handling for TDLS here -- the userspace | 3642 | * No special handling for TDLS here -- the userspace |
3565 | * mesh code doesn't have this bug. | 3643 | * mesh code doesn't have this bug. |
@@ -3584,12 +3662,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3584 | return err; | 3662 | return err; |
3585 | } | 3663 | } |
3586 | 3664 | ||
3587 | static struct nla_policy | ||
3588 | nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = { | ||
3589 | [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, | ||
3590 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, | ||
3591 | }; | ||
3592 | |||
3593 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | 3665 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) |
3594 | { | 3666 | { |
3595 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 3667 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |