aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/nl80211.h10
-rw-r--r--include/net/cfg80211.h17
-rw-r--r--net/wireless/nl80211.c104
3 files changed, 131 insertions, 0 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index ff39e4b234d4..901a70d327d1 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -519,6 +519,14 @@
519 * If used as the command it must have an interface index and you can 519 * If used as the command it must have an interface index and you can
520 * only unsubscribe from the event by closing the socket. 520 * only unsubscribe from the event by closing the socket.
521 * 521 *
522 * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface
523 * by sending a null data frame to it and reporting when the frame is
524 * acknowleged. This is used to allow timing out inactive clients. Uses
525 * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a
526 * direct reply with an %NL80211_ATTR_COOKIE that is later used to match
527 * up the event with the request. The event includes the same data and
528 * has %NL80211_ATTR_ACK set if the frame was ACKed.
529 *
522 * @NL80211_CMD_MAX: highest used command number 530 * @NL80211_CMD_MAX: highest used command number
523 * @__NL80211_CMD_AFTER_LAST: internal use 531 * @__NL80211_CMD_AFTER_LAST: internal use
524 */ 532 */
@@ -650,6 +658,8 @@ enum nl80211_commands {
650 658
651 NL80211_CMD_UNEXPECTED_FRAME, 659 NL80211_CMD_UNEXPECTED_FRAME,
652 660
661 NL80211_CMD_PROBE_CLIENT,
662
653 /* add new commands above here */ 663 /* add new commands above here */
654 664
655 /* used to define NL80211_CMD_MAX below */ 665 /* used to define NL80211_CMD_MAX below */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 86d207da6cce..389e85e8c03d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1432,6 +1432,9 @@ struct cfg80211_gtk_rekey_data {
1432 * 1432 *
1433 * @tdls_mgmt: Transmit a TDLS management frame. 1433 * @tdls_mgmt: Transmit a TDLS management frame.
1434 * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup). 1434 * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup).
1435 *
1436 * @probe_client: probe an associated client, must return a cookie that it
1437 * later passes to cfg80211_probe_status().
1435 */ 1438 */
1436struct cfg80211_ops { 1439struct cfg80211_ops {
1437 int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); 1440 int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1621,6 +1624,9 @@ struct cfg80211_ops {
1621 u16 status_code, const u8 *buf, size_t len); 1624 u16 status_code, const u8 *buf, size_t len);
1622 int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev, 1625 int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
1623 u8 *peer, enum nl80211_tdls_operation oper); 1626 u8 *peer, enum nl80211_tdls_operation oper);
1627
1628 int (*probe_client)(struct wiphy *wiphy, struct net_device *dev,
1629 const u8 *peer, u64 *cookie);
1624}; 1630};
1625 1631
1626/* 1632/*
@@ -3216,6 +3222,17 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
3216bool cfg80211_rx_spurious_frame(struct net_device *dev, 3222bool cfg80211_rx_spurious_frame(struct net_device *dev,
3217 const u8 *addr, gfp_t gfp); 3223 const u8 *addr, gfp_t gfp);
3218 3224
3225/**
3226 * cfg80211_probe_status - notify userspace about probe status
3227 * @dev: the device the probe was sent on
3228 * @addr: the address of the peer
3229 * @cookie: the cookie filled in @probe_client previously
3230 * @acked: indicates whether probe was acked or not
3231 * @gfp: allocation flags
3232 */
3233void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
3234 u64 cookie, bool acked, gfp_t gfp);
3235
3219/* Logging, debugging and troubleshooting/diagnostic helpers. */ 3236/* Logging, debugging and troubleshooting/diagnostic helpers. */
3220 3237
3221/* wiphy_printk helpers, similar to dev_printk */ 3238/* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 2094c8468d78..a8eda12b46a8 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -890,6 +890,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
890 } 890 }
891 if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) 891 if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
892 CMD(sched_scan_start, START_SCHED_SCAN); 892 CMD(sched_scan_start, START_SCHED_SCAN);
893 CMD(probe_client, PROBE_CLIENT);
893 894
894#undef CMD 895#undef CMD
895 896
@@ -5853,6 +5854,59 @@ static int nl80211_register_unexpected_frame(struct sk_buff *skb,
5853 return 0; 5854 return 0;
5854} 5855}
5855 5856
5857static int nl80211_probe_client(struct sk_buff *skb,
5858 struct genl_info *info)
5859{
5860 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5861 struct net_device *dev = info->user_ptr[1];
5862 struct wireless_dev *wdev = dev->ieee80211_ptr;
5863 struct sk_buff *msg;
5864 void *hdr;
5865 const u8 *addr;
5866 u64 cookie;
5867 int err;
5868
5869 if (wdev->iftype != NL80211_IFTYPE_AP &&
5870 wdev->iftype != NL80211_IFTYPE_P2P_GO)
5871 return -EOPNOTSUPP;
5872
5873 if (!info->attrs[NL80211_ATTR_MAC])
5874 return -EINVAL;
5875
5876 if (!rdev->ops->probe_client)
5877 return -EOPNOTSUPP;
5878
5879 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5880 if (!msg)
5881 return -ENOMEM;
5882
5883 hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
5884 NL80211_CMD_PROBE_CLIENT);
5885
5886 if (IS_ERR(hdr)) {
5887 err = PTR_ERR(hdr);
5888 goto free_msg;
5889 }
5890
5891 addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
5892
5893 err = rdev->ops->probe_client(&rdev->wiphy, dev, addr, &cookie);
5894 if (err)
5895 goto free_msg;
5896
5897 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
5898
5899 genlmsg_end(msg, hdr);
5900
5901 return genlmsg_reply(msg, info);
5902
5903 nla_put_failure:
5904 err = -ENOBUFS;
5905 free_msg:
5906 nlmsg_free(msg);
5907 return err;
5908}
5909
5856#define NL80211_FLAG_NEED_WIPHY 0x01 5910#define NL80211_FLAG_NEED_WIPHY 0x01
5857#define NL80211_FLAG_NEED_NETDEV 0x02 5911#define NL80211_FLAG_NEED_NETDEV 0x02
5858#define NL80211_FLAG_NEED_RTNL 0x04 5912#define NL80211_FLAG_NEED_RTNL 0x04
@@ -6416,6 +6470,14 @@ static struct genl_ops nl80211_ops[] = {
6416 .internal_flags = NL80211_FLAG_NEED_NETDEV | 6470 .internal_flags = NL80211_FLAG_NEED_NETDEV |
6417 NL80211_FLAG_NEED_RTNL, 6471 NL80211_FLAG_NEED_RTNL,
6418 }, 6472 },
6473 {
6474 .cmd = NL80211_CMD_PROBE_CLIENT,
6475 .doit = nl80211_probe_client,
6476 .policy = nl80211_policy,
6477 .flags = GENL_ADMIN_PERM,
6478 .internal_flags = NL80211_FLAG_NEED_NETDEV |
6479 NL80211_FLAG_NEED_RTNL,
6480 },
6419}; 6481};
6420 6482
6421static struct genl_multicast_group nl80211_mlme_mcgrp = { 6483static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -7478,6 +7540,48 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
7478 nlmsg_free(msg); 7540 nlmsg_free(msg);
7479} 7541}
7480 7542
7543void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
7544 u64 cookie, bool acked, gfp_t gfp)
7545{
7546 struct wireless_dev *wdev = dev->ieee80211_ptr;
7547 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
7548 struct sk_buff *msg;
7549 void *hdr;
7550 int err;
7551
7552 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
7553 if (!msg)
7554 return;
7555
7556 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
7557 if (!hdr) {
7558 nlmsg_free(msg);
7559 return;
7560 }
7561
7562 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
7563 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
7564 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
7565 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
7566 if (acked)
7567 NLA_PUT_FLAG(msg, NL80211_ATTR_ACK);
7568
7569 err = genlmsg_end(msg, hdr);
7570 if (err < 0) {
7571 nlmsg_free(msg);
7572 return;
7573 }
7574
7575 genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
7576 nl80211_mlme_mcgrp.id, gfp);
7577 return;
7578
7579 nla_put_failure:
7580 genlmsg_cancel(msg, hdr);
7581 nlmsg_free(msg);
7582}
7583EXPORT_SYMBOL(cfg80211_probe_status);
7584
7481static int nl80211_netlink_notify(struct notifier_block * nb, 7585static int nl80211_netlink_notify(struct notifier_block * nb,
7482 unsigned long state, 7586 unsigned long state,
7483 void *_notify) 7587 void *_notify)