diff options
author | Arik Nemtsov <arik@wizery.com> | 2011-09-28 07:12:50 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-09-30 15:57:05 -0400 |
commit | 109086ce0b0f94760bdb0e8e2566ff8a2d673639 (patch) | |
tree | 217a3d18f203fe1cf8652f9b33c4ade1f61594c2 | |
parent | a76011e2cbb6915f60488477311e0f269cee6496 (diff) |
nl80211: support sending TDLS commands/frames
Add support for sending high-level TDLS commands and TDLS frames via
NL80211_CMD_TDLS_OPER and NL80211_CMD_TDLS_MGMT, respectively. Add
appropriate cfg80211 callbacks for lower level drivers.
Add wiphy capability flags for TDLS support and advertise them via
nl80211.
Signed-off-by: Arik Nemtsov <arik@wizery.com>
Cc: Kalyan C Gaddam <chakkal@iit.edu>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | include/linux/nl80211.h | 42 | ||||
-rw-r--r-- | include/net/cfg80211.h | 17 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 81 |
3 files changed, 139 insertions, 1 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index c73582fb9d20..a5ab23df5b17 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -506,6 +506,9 @@ | |||
506 | * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace | 506 | * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace |
507 | * of PMKSA caching dandidates. | 507 | * of PMKSA caching dandidates. |
508 | * | 508 | * |
509 | * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup). | ||
510 | * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. | ||
511 | * | ||
509 | * @NL80211_CMD_MAX: highest used command number | 512 | * @NL80211_CMD_MAX: highest used command number |
510 | * @__NL80211_CMD_AFTER_LAST: internal use | 513 | * @__NL80211_CMD_AFTER_LAST: internal use |
511 | */ | 514 | */ |
@@ -632,6 +635,9 @@ enum nl80211_commands { | |||
632 | 635 | ||
633 | NL80211_CMD_PMKSA_CANDIDATE, | 636 | NL80211_CMD_PMKSA_CANDIDATE, |
634 | 637 | ||
638 | NL80211_CMD_TDLS_OPER, | ||
639 | NL80211_CMD_TDLS_MGMT, | ||
640 | |||
635 | /* add new commands above here */ | 641 | /* add new commands above here */ |
636 | 642 | ||
637 | /* used to define NL80211_CMD_MAX below */ | 643 | /* used to define NL80211_CMD_MAX below */ |
@@ -1089,6 +1095,20 @@ enum nl80211_commands { | |||
1089 | * This attribute is used with %NL80211_CMD_TRIGGER_SCAN and | 1095 | * This attribute is used with %NL80211_CMD_TRIGGER_SCAN and |
1090 | * %NL80211_CMD_FRAME commands. | 1096 | * %NL80211_CMD_FRAME commands. |
1091 | * | 1097 | * |
1098 | * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup | ||
1099 | * request, link setup confirm, link teardown, etc.). Values are | ||
1100 | * described in the TDLS (802.11z) specification. | ||
1101 | * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a | ||
1102 | * TDLS conversation between two devices. | ||
1103 | * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see | ||
1104 | * &enum nl80211_tdls_operation, represented as a u8. | ||
1105 | * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate | ||
1106 | * as a TDLS peer sta. | ||
1107 | * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown | ||
1108 | * procedures should be performed by sending TDLS packets via | ||
1109 | * %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be | ||
1110 | * used for asking the driver to perform a TDLS operation. | ||
1111 | * | ||
1092 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 1112 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
1093 | * @__NL80211_ATTR_AFTER_LAST: internal use | 1113 | * @__NL80211_ATTR_AFTER_LAST: internal use |
1094 | */ | 1114 | */ |
@@ -1311,6 +1331,12 @@ enum nl80211_attrs { | |||
1311 | 1331 | ||
1312 | NL80211_ATTR_TX_NO_CCK_RATE, | 1332 | NL80211_ATTR_TX_NO_CCK_RATE, |
1313 | 1333 | ||
1334 | NL80211_ATTR_TDLS_ACTION, | ||
1335 | NL80211_ATTR_TDLS_DIALOG_TOKEN, | ||
1336 | NL80211_ATTR_TDLS_OPERATION, | ||
1337 | NL80211_ATTR_TDLS_SUPPORT, | ||
1338 | NL80211_ATTR_TDLS_EXTERNAL_SETUP, | ||
1339 | |||
1314 | /* add attributes here, update the policy in nl80211.c */ | 1340 | /* add attributes here, update the policy in nl80211.c */ |
1315 | 1341 | ||
1316 | __NL80211_ATTR_AFTER_LAST, | 1342 | __NL80211_ATTR_AFTER_LAST, |
@@ -2604,4 +2630,20 @@ enum nl80211_pmksa_candidate_attr { | |||
2604 | MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1 | 2630 | MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1 |
2605 | }; | 2631 | }; |
2606 | 2632 | ||
2633 | /** | ||
2634 | * enum nl80211_tdls_operation - values for %NL80211_ATTR_TDLS_OPERATION | ||
2635 | * @NL80211_TDLS_DISCOVERY_REQ: Send a TDLS discovery request | ||
2636 | * @NL80211_TDLS_SETUP: Setup TDLS link | ||
2637 | * @NL80211_TDLS_TEARDOWN: Teardown a TDLS link which is already established | ||
2638 | * @NL80211_TDLS_ENABLE_LINK: Enable TDLS link | ||
2639 | * @NL80211_TDLS_DISABLE_LINK: Disable TDLS link | ||
2640 | */ | ||
2641 | enum nl80211_tdls_operation { | ||
2642 | NL80211_TDLS_DISCOVERY_REQ, | ||
2643 | NL80211_TDLS_SETUP, | ||
2644 | NL80211_TDLS_TEARDOWN, | ||
2645 | NL80211_TDLS_ENABLE_LINK, | ||
2646 | NL80211_TDLS_DISABLE_LINK, | ||
2647 | }; | ||
2648 | |||
2607 | #endif /* __LINUX_NL80211_H */ | 2649 | #endif /* __LINUX_NL80211_H */ |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 34b8f269976b..74f4f85be32f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -1422,6 +1422,9 @@ struct cfg80211_gtk_rekey_data { | |||
1422 | * @set_ringparam: Set tx and rx ring sizes. | 1422 | * @set_ringparam: Set tx and rx ring sizes. |
1423 | * | 1423 | * |
1424 | * @get_ringparam: Get tx and rx ring current and maximum sizes. | 1424 | * @get_ringparam: Get tx and rx ring current and maximum sizes. |
1425 | * | ||
1426 | * @tdls_mgmt: Transmit a TDLS management frame. | ||
1427 | * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup). | ||
1425 | */ | 1428 | */ |
1426 | struct cfg80211_ops { | 1429 | struct cfg80211_ops { |
1427 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); | 1430 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); |
@@ -1605,6 +1608,12 @@ struct cfg80211_ops { | |||
1605 | 1608 | ||
1606 | int (*set_rekey_data)(struct wiphy *wiphy, struct net_device *dev, | 1609 | int (*set_rekey_data)(struct wiphy *wiphy, struct net_device *dev, |
1607 | struct cfg80211_gtk_rekey_data *data); | 1610 | struct cfg80211_gtk_rekey_data *data); |
1611 | |||
1612 | int (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev, | ||
1613 | u8 *peer, u8 action_code, u8 dialog_token, | ||
1614 | u16 status_code, const u8 *buf, size_t len); | ||
1615 | int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev, | ||
1616 | u8 *peer, enum nl80211_tdls_operation oper); | ||
1608 | }; | 1617 | }; |
1609 | 1618 | ||
1610 | /* | 1619 | /* |
@@ -1657,6 +1666,12 @@ struct cfg80211_ops { | |||
1657 | * @WIPHY_FLAG_SUPPORTS_FW_ROAM: The device supports roaming feature in the | 1666 | * @WIPHY_FLAG_SUPPORTS_FW_ROAM: The device supports roaming feature in the |
1658 | * firmware. | 1667 | * firmware. |
1659 | * @WIPHY_FLAG_AP_UAPSD: The device supports uapsd on AP. | 1668 | * @WIPHY_FLAG_AP_UAPSD: The device supports uapsd on AP. |
1669 | * @WIPHY_FLAG_SUPPORTS_TDLS: The device supports TDLS (802.11z) operation. | ||
1670 | * @WIPHY_FLAG_TDLS_EXTERNAL_SETUP: The device does not handle TDLS (802.11z) | ||
1671 | * link setup/discovery operations internally. Setup, discovery and | ||
1672 | * teardown packets should be sent through the @NL80211_CMD_TDLS_MGMT | ||
1673 | * command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be | ||
1674 | * used for asking the driver/firmware to perform a TDLS operation. | ||
1660 | */ | 1675 | */ |
1661 | enum wiphy_flags { | 1676 | enum wiphy_flags { |
1662 | WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), | 1677 | WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), |
@@ -1673,6 +1688,8 @@ enum wiphy_flags { | |||
1673 | WIPHY_FLAG_ENFORCE_COMBINATIONS = BIT(12), | 1688 | WIPHY_FLAG_ENFORCE_COMBINATIONS = BIT(12), |
1674 | WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13), | 1689 | WIPHY_FLAG_SUPPORTS_FW_ROAM = BIT(13), |
1675 | WIPHY_FLAG_AP_UAPSD = BIT(14), | 1690 | WIPHY_FLAG_AP_UAPSD = BIT(14), |
1691 | WIPHY_FLAG_SUPPORTS_TDLS = BIT(15), | ||
1692 | WIPHY_FLAG_TDLS_EXTERNAL_SETUP = BIT(16), | ||
1676 | }; | 1693 | }; |
1677 | 1694 | ||
1678 | /** | 1695 | /** |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3799623e7f46..25a37fc951e3 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 | ||
@@ -4966,6 +4978,57 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) | |||
4966 | return rdev->ops->flush_pmksa(&rdev->wiphy, dev); | 4978 | return rdev->ops->flush_pmksa(&rdev->wiphy, dev); |
4967 | } | 4979 | } |
4968 | 4980 | ||
4981 | static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) | ||
4982 | { | ||
4983 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
4984 | struct net_device *dev = info->user_ptr[1]; | ||
4985 | u8 action_code, dialog_token; | ||
4986 | u16 status_code; | ||
4987 | u8 *peer; | ||
4988 | |||
4989 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) || | ||
4990 | !rdev->ops->tdls_mgmt) | ||
4991 | return -EOPNOTSUPP; | ||
4992 | |||
4993 | if (!info->attrs[NL80211_ATTR_TDLS_ACTION] || | ||
4994 | !info->attrs[NL80211_ATTR_STATUS_CODE] || | ||
4995 | !info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN] || | ||
4996 | !info->attrs[NL80211_ATTR_IE] || | ||
4997 | !info->attrs[NL80211_ATTR_MAC]) | ||
4998 | return -EINVAL; | ||
4999 | |||
5000 | peer = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
5001 | action_code = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_ACTION]); | ||
5002 | status_code = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); | ||
5003 | dialog_token = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_DIALOG_TOKEN]); | ||
5004 | |||
5005 | return rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, | ||
5006 | dialog_token, status_code, | ||
5007 | nla_data(info->attrs[NL80211_ATTR_IE]), | ||
5008 | nla_len(info->attrs[NL80211_ATTR_IE])); | ||
5009 | } | ||
5010 | |||
5011 | static int nl80211_tdls_oper(struct sk_buff *skb, struct genl_info *info) | ||
5012 | { | ||
5013 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5014 | struct net_device *dev = info->user_ptr[1]; | ||
5015 | enum nl80211_tdls_operation operation; | ||
5016 | u8 *peer; | ||
5017 | |||
5018 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) || | ||
5019 | !rdev->ops->tdls_oper) | ||
5020 | return -EOPNOTSUPP; | ||
5021 | |||
5022 | if (!info->attrs[NL80211_ATTR_TDLS_OPERATION] || | ||
5023 | !info->attrs[NL80211_ATTR_MAC]) | ||
5024 | return -EINVAL; | ||
5025 | |||
5026 | operation = nla_get_u8(info->attrs[NL80211_ATTR_TDLS_OPERATION]); | ||
5027 | peer = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
5028 | |||
5029 | return rdev->ops->tdls_oper(&rdev->wiphy, dev, peer, operation); | ||
5030 | } | ||
5031 | |||
4969 | static int nl80211_remain_on_channel(struct sk_buff *skb, | 5032 | static int nl80211_remain_on_channel(struct sk_buff *skb, |
4970 | struct genl_info *info) | 5033 | struct genl_info *info) |
4971 | { | 5034 | { |
@@ -6281,6 +6344,22 @@ static struct genl_ops nl80211_ops[] = { | |||
6281 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 6344 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
6282 | NL80211_FLAG_NEED_RTNL, | 6345 | NL80211_FLAG_NEED_RTNL, |
6283 | }, | 6346 | }, |
6347 | { | ||
6348 | .cmd = NL80211_CMD_TDLS_MGMT, | ||
6349 | .doit = nl80211_tdls_mgmt, | ||
6350 | .policy = nl80211_policy, | ||
6351 | .flags = GENL_ADMIN_PERM, | ||
6352 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
6353 | NL80211_FLAG_NEED_RTNL, | ||
6354 | }, | ||
6355 | { | ||
6356 | .cmd = NL80211_CMD_TDLS_OPER, | ||
6357 | .doit = nl80211_tdls_oper, | ||
6358 | .policy = nl80211_policy, | ||
6359 | .flags = GENL_ADMIN_PERM, | ||
6360 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
6361 | NL80211_FLAG_NEED_RTNL, | ||
6362 | }, | ||
6284 | }; | 6363 | }; |
6285 | 6364 | ||
6286 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 6365 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |