aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2011-09-28 07:12:50 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-09-30 15:57:05 -0400
commit109086ce0b0f94760bdb0e8e2566ff8a2d673639 (patch)
tree217a3d18f203fe1cf8652f9b33c4ade1f61594c2
parenta76011e2cbb6915f60488477311e0f269cee6496 (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.h42
-rw-r--r--include/net/cfg80211.h17
-rw-r--r--net/wireless/nl80211.c81
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 */
2641enum 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 */
1426struct cfg80211_ops { 1429struct 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 */
1661enum wiphy_flags { 1676enum 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
4981static 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
5011static 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
4969static int nl80211_remain_on_channel(struct sk_buff *skb, 5032static 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
6286static struct genl_multicast_group nl80211_mlme_mcgrp = { 6365static struct genl_multicast_group nl80211_mlme_mcgrp = {