|
@@ -891,6 +891,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
|
|
if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
|
|
|
CMD(sched_scan_start, START_SCHED_SCAN);
|
|
|
CMD(probe_client, PROBE_CLIENT);
|
|
|
+ if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
|
|
|
+ i++;
|
|
|
+ NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS);
|
|
|
+ }
|
|
|
|
|
|
#undef CMD
|
|
|
|
|
@@ -5907,6 +5911,21 @@ static int nl80211_probe_client(struct sk_buff *skb,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
|
|
|
+{
|
|
|
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
|
+
|
|
|
+ if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ if (rdev->ap_beacons_nlpid)
|
|
|
+ return -EBUSY;
|
|
|
+
|
|
|
+ rdev->ap_beacons_nlpid = info->snd_pid;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
#define NL80211_FLAG_NEED_WIPHY 0x01
|
|
|
#define NL80211_FLAG_NEED_NETDEV 0x02
|
|
|
#define NL80211_FLAG_NEED_RTNL 0x04
|
|
@@ -6478,6 +6497,14 @@ static struct genl_ops nl80211_ops[] = {
|
|
|
.internal_flags = NL80211_FLAG_NEED_NETDEV |
|
|
|
NL80211_FLAG_NEED_RTNL,
|
|
|
},
|
|
|
+ {
|
|
|
+ .cmd = NL80211_CMD_REGISTER_BEACONS,
|
|
|
+ .doit = nl80211_register_beacons,
|
|
|
+ .policy = nl80211_policy,
|
|
|
+ .flags = GENL_ADMIN_PERM,
|
|
|
+ .internal_flags = NL80211_FLAG_NEED_WIPHY |
|
|
|
+ NL80211_FLAG_NEED_RTNL,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
static struct genl_multicast_group nl80211_mlme_mcgrp = {
|
|
@@ -7582,6 +7609,44 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
|
|
|
}
|
|
|
EXPORT_SYMBOL(cfg80211_probe_status);
|
|
|
|
|
|
+void cfg80211_report_obss_beacon(struct wiphy *wiphy,
|
|
|
+ const u8 *frame, size_t len,
|
|
|
+ int freq, gfp_t gfp)
|
|
|
+{
|
|
|
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
|
|
+ struct sk_buff *msg;
|
|
|
+ void *hdr;
|
|
|
+ u32 nlpid = ACCESS_ONCE(rdev->ap_beacons_nlpid);
|
|
|
+
|
|
|
+ if (!nlpid)
|
|
|
+ return;
|
|
|
+
|
|
|
+ msg = nlmsg_new(len + 100, gfp);
|
|
|
+ if (!msg)
|
|
|
+ return;
|
|
|
+
|
|
|
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
|
|
|
+ if (!hdr) {
|
|
|
+ nlmsg_free(msg);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
|
|
|
+ if (freq)
|
|
|
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
|
|
|
+ NLA_PUT(msg, NL80211_ATTR_FRAME, len, frame);
|
|
|
+
|
|
|
+ genlmsg_end(msg, hdr);
|
|
|
+
|
|
|
+ genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
|
|
|
+ return;
|
|
|
+
|
|
|
+ nla_put_failure:
|
|
|
+ genlmsg_cancel(msg, hdr);
|
|
|
+ nlmsg_free(msg);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(cfg80211_report_obss_beacon);
|
|
|
+
|
|
|
static int nl80211_netlink_notify(struct notifier_block * nb,
|
|
|
unsigned long state,
|
|
|
void *_notify)
|
|
@@ -7595,9 +7660,12 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
|
- list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list)
|
|
|
+ list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
|
|
|
list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
|
|
|
cfg80211_mlme_unregister_socket(wdev, notify->pid);
|
|
|
+ if (rdev->ap_beacons_nlpid == notify->pid)
|
|
|
+ rdev->ap_beacons_nlpid = 0;
|
|
|
+ }
|
|
|
|
|
|
rcu_read_unlock();
|
|
|
|