aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/nl80211.h7
-rw-r--r--include/net/cfg80211.h20
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/nl80211.c70
4 files changed, 98 insertions, 1 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 901a70d327d1..c29a284c27e6 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -527,6 +527,11 @@
527 * up the event with the request. The event includes the same data and 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. 528 * has %NL80211_ATTR_ACK set if the frame was ACKed.
529 * 529 *
530 * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from
531 * other BSSes when any interfaces are in AP mode. This helps implement
532 * OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME
533 * messages. Note that per PHY only one application may register.
534 *
530 * @NL80211_CMD_MAX: highest used command number 535 * @NL80211_CMD_MAX: highest used command number
531 * @__NL80211_CMD_AFTER_LAST: internal use 536 * @__NL80211_CMD_AFTER_LAST: internal use
532 */ 537 */
@@ -660,6 +665,8 @@ enum nl80211_commands {
660 665
661 NL80211_CMD_PROBE_CLIENT, 666 NL80211_CMD_PROBE_CLIENT,
662 667
668 NL80211_CMD_REGISTER_BEACONS,
669
663 /* add new commands above here */ 670 /* add new commands above here */
664 671
665 /* used to define NL80211_CMD_MAX below */ 672 /* used to define NL80211_CMD_MAX below */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 389e85e8c03d..d01307f54faa 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1686,6 +1686,9 @@ struct cfg80211_ops {
1686 * command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be 1686 * command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be
1687 * used for asking the driver/firmware to perform a TDLS operation. 1687 * used for asking the driver/firmware to perform a TDLS operation.
1688 * @WIPHY_FLAG_HAVE_AP_SME: device integrates AP SME 1688 * @WIPHY_FLAG_HAVE_AP_SME: device integrates AP SME
1689 * @WIPHY_FLAG_REPORTS_OBSS: the device will report beacons from other BSSes
1690 * when there are virtual interfaces in AP mode by calling
1691 * cfg80211_report_obss_beacon().
1689 */ 1692 */
1690enum wiphy_flags { 1693enum wiphy_flags {
1691 WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), 1694 WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
@@ -1705,6 +1708,7 @@ enum wiphy_flags {
1705 WIPHY_FLAG_SUPPORTS_TDLS = BIT(15), 1708 WIPHY_FLAG_SUPPORTS_TDLS = BIT(15),
1706 WIPHY_FLAG_TDLS_EXTERNAL_SETUP = BIT(16), 1709 WIPHY_FLAG_TDLS_EXTERNAL_SETUP = BIT(16),
1707 WIPHY_FLAG_HAVE_AP_SME = BIT(17), 1710 WIPHY_FLAG_HAVE_AP_SME = BIT(17),
1711 WIPHY_FLAG_REPORTS_OBSS = BIT(18),
1708}; 1712};
1709 1713
1710/** 1714/**
@@ -3233,6 +3237,22 @@ bool cfg80211_rx_spurious_frame(struct net_device *dev,
3233void cfg80211_probe_status(struct net_device *dev, const u8 *addr, 3237void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
3234 u64 cookie, bool acked, gfp_t gfp); 3238 u64 cookie, bool acked, gfp_t gfp);
3235 3239
3240/**
3241 * cfg80211_report_obss_beacon - report beacon from other APs
3242 * @wiphy: The wiphy that received the beacon
3243 * @frame: the frame
3244 * @len: length of the frame
3245 * @freq: frequency the frame was received on
3246 * @gfp: allocation flags
3247 *
3248 * Use this function to report to userspace when a beacon was
3249 * received. It is not useful to call this when there is no
3250 * netdev that is in AP/GO mode.
3251 */
3252void cfg80211_report_obss_beacon(struct wiphy *wiphy,
3253 const u8 *frame, size_t len,
3254 int freq, gfp_t gfp);
3255
3236/* Logging, debugging and troubleshooting/diagnostic helpers. */ 3256/* Logging, debugging and troubleshooting/diagnostic helpers. */
3237 3257
3238/* wiphy_printk helpers, similar to dev_printk */ 3258/* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/wireless/core.h b/net/wireless/core.h
index b9ec3061ed72..4c6ff4024356 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -54,6 +54,8 @@ struct cfg80211_registered_device {
54 int opencount; /* also protected by devlist_mtx */ 54 int opencount; /* also protected by devlist_mtx */
55 wait_queue_head_t dev_wait; 55 wait_queue_head_t dev_wait;
56 56
57 u32 ap_beacons_nlpid;
58
57 /* BSSes/scanning */ 59 /* BSSes/scanning */
58 spinlock_t bss_lock; 60 spinlock_t bss_lock;
59 struct list_head bss_list; 61 struct list_head bss_list;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a8eda12b46a8..68b6708b996f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -891,6 +891,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
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 CMD(probe_client, PROBE_CLIENT);
894 if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
895 i++;
896 NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS);
897 }
894 898
895#undef CMD 899#undef CMD
896 900
@@ -5907,6 +5911,21 @@ static int nl80211_probe_client(struct sk_buff *skb,
5907 return err; 5911 return err;
5908} 5912}
5909 5913
5914static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
5915{
5916 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5917
5918 if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
5919 return -EOPNOTSUPP;
5920
5921 if (rdev->ap_beacons_nlpid)
5922 return -EBUSY;
5923
5924 rdev->ap_beacons_nlpid = info->snd_pid;
5925
5926 return 0;
5927}
5928
5910#define NL80211_FLAG_NEED_WIPHY 0x01 5929#define NL80211_FLAG_NEED_WIPHY 0x01
5911#define NL80211_FLAG_NEED_NETDEV 0x02 5930#define NL80211_FLAG_NEED_NETDEV 0x02
5912#define NL80211_FLAG_NEED_RTNL 0x04 5931#define NL80211_FLAG_NEED_RTNL 0x04
@@ -6478,6 +6497,14 @@ static struct genl_ops nl80211_ops[] = {
6478 .internal_flags = NL80211_FLAG_NEED_NETDEV | 6497 .internal_flags = NL80211_FLAG_NEED_NETDEV |
6479 NL80211_FLAG_NEED_RTNL, 6498 NL80211_FLAG_NEED_RTNL,
6480 }, 6499 },
6500 {
6501 .cmd = NL80211_CMD_REGISTER_BEACONS,
6502 .doit = nl80211_register_beacons,
6503 .policy = nl80211_policy,
6504 .flags = GENL_ADMIN_PERM,
6505 .internal_flags = NL80211_FLAG_NEED_WIPHY |
6506 NL80211_FLAG_NEED_RTNL,
6507 },
6481}; 6508};
6482 6509
6483static struct genl_multicast_group nl80211_mlme_mcgrp = { 6510static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -7582,6 +7609,44 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
7582} 7609}
7583EXPORT_SYMBOL(cfg80211_probe_status); 7610EXPORT_SYMBOL(cfg80211_probe_status);
7584 7611
7612void cfg80211_report_obss_beacon(struct wiphy *wiphy,
7613 const u8 *frame, size_t len,
7614 int freq, gfp_t gfp)
7615{
7616 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
7617 struct sk_buff *msg;
7618 void *hdr;
7619 u32 nlpid = ACCESS_ONCE(rdev->ap_beacons_nlpid);
7620
7621 if (!nlpid)
7622 return;
7623
7624 msg = nlmsg_new(len + 100, gfp);
7625 if (!msg)
7626 return;
7627
7628 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
7629 if (!hdr) {
7630 nlmsg_free(msg);
7631 return;
7632 }
7633
7634 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
7635 if (freq)
7636 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
7637 NLA_PUT(msg, NL80211_ATTR_FRAME, len, frame);
7638
7639 genlmsg_end(msg, hdr);
7640
7641 genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
7642 return;
7643
7644 nla_put_failure:
7645 genlmsg_cancel(msg, hdr);
7646 nlmsg_free(msg);
7647}
7648EXPORT_SYMBOL(cfg80211_report_obss_beacon);
7649
7585static int nl80211_netlink_notify(struct notifier_block * nb, 7650static int nl80211_netlink_notify(struct notifier_block * nb,
7586 unsigned long state, 7651 unsigned long state,
7587 void *_notify) 7652 void *_notify)
@@ -7595,9 +7660,12 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
7595 7660
7596 rcu_read_lock(); 7661 rcu_read_lock();
7597 7662
7598 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) 7663 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
7599 list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) 7664 list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
7600 cfg80211_mlme_unregister_socket(wdev, notify->pid); 7665 cfg80211_mlme_unregister_socket(wdev, notify->pid);
7666 if (rdev->ap_beacons_nlpid == notify->pid)
7667 rdev->ap_beacons_nlpid = 0;
7668 }
7601 7669
7602 rcu_read_unlock(); 7670 rcu_read_unlock();
7603 7671