diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 109 |
1 files changed, 104 insertions, 5 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b85075761e24..edf655aeea00 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -192,6 +192,11 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
192 | [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG }, | 192 | [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG }, |
193 | [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED }, | 193 | [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED }, |
194 | [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG }, | 194 | [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG }, |
195 | [NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 }, | ||
196 | [NL80211_ATTR_TDLS_DIALOG_TOKEN] = { .type = NLA_U8 }, | ||
197 | [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 }, | ||
198 | [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG }, | ||
199 | [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG }, | ||
195 | }; | 200 | }; |
196 | 201 | ||
197 | /* policy for the key attributes */ | 202 | /* policy for the key attributes */ |
@@ -732,9 +737,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
732 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_MESH_AUTH); | 737 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_MESH_AUTH); |
733 | if (dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) | 738 | if (dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) |
734 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_AP_UAPSD); | 739 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_AP_UAPSD); |
735 | |||
736 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) | 740 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) |
737 | NLA_PUT_FLAG(msg, NL80211_ATTR_ROAM_SUPPORT); | 741 | NLA_PUT_FLAG(msg, NL80211_ATTR_ROAM_SUPPORT); |
742 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) | ||
743 | NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_SUPPORT); | ||
744 | if (dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) | ||
745 | NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP); | ||
738 | 746 | ||
739 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, | 747 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, |
740 | sizeof(u32) * dev->wiphy.n_cipher_suites, | 748 | sizeof(u32) * dev->wiphy.n_cipher_suites, |
@@ -877,6 +885,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
877 | } | 885 | } |
878 | CMD(set_channel, SET_CHANNEL); | 886 | CMD(set_channel, SET_CHANNEL); |
879 | CMD(set_wds_peer, SET_WDS_PEER); | 887 | CMD(set_wds_peer, SET_WDS_PEER); |
888 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { | ||
889 | CMD(tdls_mgmt, TDLS_MGMT); | ||
890 | CMD(tdls_oper, TDLS_OPER); | ||
891 | } | ||
880 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) | 892 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) |
881 | CMD(sched_scan_start, START_SCHED_SCAN); | 893 | CMD(sched_scan_start, START_SCHED_SCAN); |
882 | 894 | ||
@@ -2518,18 +2530,25 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2518 | break; | 2530 | break; |
2519 | case NL80211_IFTYPE_P2P_CLIENT: | 2531 | case NL80211_IFTYPE_P2P_CLIENT: |
2520 | case NL80211_IFTYPE_STATION: | 2532 | case NL80211_IFTYPE_STATION: |
2521 | /* disallow everything but AUTHORIZED flag */ | 2533 | /* disallow things sta doesn't support */ |
2522 | if (params.plink_action) | 2534 | if (params.plink_action) |
2523 | err = -EINVAL; | 2535 | err = -EINVAL; |
2524 | if (params.vlan) | 2536 | if (params.vlan) |
2525 | err = -EINVAL; | 2537 | err = -EINVAL; |
2526 | if (params.supported_rates) | 2538 | if (params.supported_rates && |
2539 | !(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) | ||
2527 | err = -EINVAL; | 2540 | err = -EINVAL; |
2528 | if (params.ht_capa) | 2541 | if (params.ht_capa) |
2529 | err = -EINVAL; | 2542 | err = -EINVAL; |
2530 | if (params.listen_interval >= 0) | 2543 | if (params.listen_interval >= 0) |
2531 | err = -EINVAL; | 2544 | err = -EINVAL; |
2532 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) | 2545 | if (params.sta_flags_mask & |
2546 | ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
2547 | BIT(NL80211_STA_FLAG_TDLS_PEER))) | ||
2548 | err = -EINVAL; | ||
2549 | /* can't change the TDLS bit */ | ||
2550 | if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) && | ||
2551 | (params.sta_flags_mask & BIT(NL80211_STA_FLAG_TDLS_PEER))) | ||
2533 | err = -EINVAL; | 2552 | err = -EINVAL; |
2534 | break; | 2553 | break; |
2535 | case NL80211_IFTYPE_MESH_POINT: | 2554 | case NL80211_IFTYPE_MESH_POINT: |
@@ -2643,12 +2662,25 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2643 | 2662 | ||
2644 | if (params.max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) | 2663 | if (params.max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) |
2645 | return -EINVAL; | 2664 | return -EINVAL; |
2665 | |||
2666 | params.sta_modify_mask |= STATION_PARAM_APPLY_UAPSD; | ||
2646 | } | 2667 | } |
2647 | 2668 | ||
2648 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2669 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2649 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 2670 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
2650 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | 2671 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && |
2651 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 2672 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO && |
2673 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) | ||
2674 | return -EINVAL; | ||
2675 | |||
2676 | /* | ||
2677 | * Only managed stations can add TDLS peers, and only when the | ||
2678 | * wiphy supports external TDLS setup. | ||
2679 | */ | ||
2680 | if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION && | ||
2681 | !((params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) && | ||
2682 | (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) && | ||
2683 | (rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))) | ||
2652 | return -EINVAL; | 2684 | return -EINVAL; |
2653 | 2685 | ||
2654 | err = get_vlan(info, rdev, ¶ms.vlan); | 2686 | err = get_vlan(info, rdev, ¶ms.vlan); |
@@ -4964,6 +4996,57 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) | |||
4964 | return rdev->ops->flush_pmksa(&rdev->wiphy, dev); | 4996 | return rdev->ops->flush_pmksa(&rdev->wiphy, dev); |
4965 | } | 4997 | } |
4966 | 4998 | ||
4999 | static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) | ||
5000 | { | ||
5001 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5002 | struct net_device *dev = info->user_ptr[1]; | ||
5003 | u8 action_code, dialog_token; | ||
5004 | u16 status_code; | ||
5005 | u8 *peer; | ||
5006 | |||
5007 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) || | ||
5008 | !rdev->ops->tdls_mgmt) | ||
5009 | return -EOPNOTSUPP; | ||
5010 | |||
5011 | if (!info->attrs[NL80211_ATTR_TDLS_ACTION] || | ||
5012 | !info->attrs[NL80211_ATTR_STATUS_CODE] || | ||
5013 | !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] || | ||
5014 | !info->attrs[NL80211_ATTR_IE] || | ||
5015 | !info->attrs[NL80211_ATTR_MAC]) | ||
5016 | return -EINVAL; | ||
5017 | |||
5018 | peer = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
5019 | action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]); | ||
5020 | status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); | ||
5021 | dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]); | ||
5022 | |||
5023 | return rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, | ||
5024 | dialog_token, status_code, | ||
5025 | nla_data(info->attrs[NL80211_ATTR_IE]), | ||
5026 | nla_len(info->attrs[NL80211_ATTR_IE])); | ||
5027 | } | ||
5028 | |||
5029 | static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info) | ||
5030 | { | ||
5031 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5032 | struct net_device *dev = info->user_ptr[1]; | ||
5033 | enum nl80211_tdls_operation operation; | ||
5034 | u8 *peer; | ||
5035 | |||
5036 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) || | ||
5037 | !rdev->ops->tdls_oper) | ||
5038 | return -EOPNOTSUPP; | ||
5039 | |||
5040 | if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] || | ||
5041 | !info->attrs[NL80211_ATTR_MAC]) | ||
5042 | return -EINVAL; | ||
5043 | |||
5044 | operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]); | ||
5045 | peer = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
5046 | |||
5047 | return rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, operation); | ||
5048 | } | ||
5049 | |||
4967 | static int nl80211_remain_on_channel(struct sk_buff *skb, | 5050 | static int nl80211_remain_on_channel(struct sk_buff *skb, |
4968 | struct genl_info *info) | 5051 | struct genl_info *info) |
4969 | { | 5052 | { |
@@ -6279,6 +6362,22 @@ static struct genl_ops nl80211_ops[] = { | |||
6279 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 6362 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
6280 | NL80211_FLAG_NEED_RTNL, | 6363 | NL80211_FLAG_NEED_RTNL, |
6281 | }, | 6364 | }, |
6365 | { | ||
6366 | .cmd = NL80211_CMD_TDLS_MGMT, | ||
6367 | .doit = nl80211_tdls_mgmt, | ||
6368 | .policy = nl80211_policy, | ||
6369 | .flags = GENL_ADMIN_PERM, | ||
6370 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
6371 | NL80211_FLAG_NEED_RTNL, | ||
6372 | }, | ||
6373 | { | ||
6374 | .cmd = NL80211_CMD_TDLS_OPER, | ||
6375 | .doit = nl80211_tdls_oper, | ||
6376 | .policy = nl80211_policy, | ||
6377 | .flags = GENL_ADMIN_PERM, | ||
6378 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
6379 | NL80211_FLAG_NEED_RTNL, | ||
6380 | }, | ||
6282 | }; | 6381 | }; |
6283 | 6382 | ||
6284 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 6383 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |