diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-11-04 06:18:15 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-09 16:12:39 -0500 |
commit | 7f6cf311a594c1e7ca8120367dd1d4c685aabff1 (patch) | |
tree | 60308101541ba278a4dabd8a5884b5a0de3722eb /net/wireless | |
parent | 562a74803f4881772ba2375ec4e5aa0ad90f4caa (diff) |
nl80211: add API to probe a client
When the AP SME in hostapd is used it wants to
probe the clients when they have been idle for
some time. Add explicit API to support this.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/nl80211.c | 104 |
1 files changed, 104 insertions, 0 deletions
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 | ||
5857 | static 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 | ||
6421 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 6483 | static 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 | ||
7543 | void 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 | } | ||
7583 | EXPORT_SYMBOL(cfg80211_probe_status); | ||
7584 | |||
7481 | static int nl80211_netlink_notify(struct notifier_block * nb, | 7585 | static int nl80211_netlink_notify(struct notifier_block * nb, |
7482 | unsigned long state, | 7586 | unsigned long state, |
7483 | void *_notify) | 7587 | void *_notify) |