Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 37c73b5f authored by Ben Greear's avatar Ben Greear Committed by Johannes Berg
Browse files

cfg80211: allow registering more than one beacon listener



The commit:

commit 5e760230
Author: Johannes Berg <johannes.berg@intel.com>
Date:   Fri Nov 4 11:18:17 2011 +0100

    cfg80211: allow registering to beacons

allowed only a single process to register for beacon events
per wiphy.  This breaks cases where a user may want two or
more VIFs on a wiphy and run a seperate hostapd process on
each vif.

This patch allows multiple beacon listeners, fixing the
regression.

Signed-off-by: default avatarBen Greear <greearb@candelatech.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 391e53e3
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -3560,7 +3560,6 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
 * @len: length of the frame
 * @freq: frequency the frame was received on
 * @sig_dbm: signal strength in mBm, or 0 if unknown
 * @gfp: allocation flags
 *
 * Use this function to report to userspace when a beacon was
 * received. It is not useful to call this when there is no
@@ -3568,7 +3567,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
 */
void cfg80211_report_obss_beacon(struct wiphy *wiphy,
				 const u8 *frame, size_t len,
				 int freq, int sig_dbm, gfp_t gfp);
				 int freq, int sig_dbm);

/**
 * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used
+1 −1
Original line number Diff line number Diff line
@@ -2200,7 +2200,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)

		cfg80211_report_obss_beacon(rx->local->hw.wiphy,
					    rx->skb->data, rx->skb->len,
					    status->freq, sig, GFP_ATOMIC);
					    status->freq, sig);
		rx->flags |= IEEE80211_RX_BEACON_REPORTED;
	}

+7 −0
Original line number Diff line number Diff line
@@ -326,6 +326,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
	mutex_init(&rdev->devlist_mtx);
	mutex_init(&rdev->sched_scan_mtx);
	INIT_LIST_HEAD(&rdev->wdev_list);
	INIT_LIST_HEAD(&rdev->beacon_registrations);
	spin_lock_init(&rdev->beacon_registrations_lock);
	spin_lock_init(&rdev->bss_lock);
	INIT_LIST_HEAD(&rdev->bss_list);
	INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
@@ -698,10 +700,15 @@ EXPORT_SYMBOL(wiphy_unregister);
void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
{
	struct cfg80211_internal_bss *scan, *tmp;
	struct cfg80211_beacon_registration *reg, *treg;
	rfkill_destroy(rdev->rfkill);
	mutex_destroy(&rdev->mtx);
	mutex_destroy(&rdev->devlist_mtx);
	mutex_destroy(&rdev->sched_scan_mtx);
	list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) {
		list_del(&reg->list);
		kfree(reg);
	}
	list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
		cfg80211_put_bss(&scan->pub);
	kfree(rdev);
+6 −1
Original line number Diff line number Diff line
@@ -55,7 +55,8 @@ struct cfg80211_registered_device {
	int opencount; /* also protected by devlist_mtx */
	wait_queue_head_t dev_wait;

	u32 ap_beacons_nlportid;
	struct list_head beacon_registrations;
	spinlock_t beacon_registrations_lock;

	/* protected by RTNL only */
	int num_running_ifaces;
@@ -260,6 +261,10 @@ enum cfg80211_chan_mode {
	CHAN_MODE_EXCLUSIVE,
};

struct cfg80211_beacon_registration {
	struct list_head list;
	u32 nlportid;
};

/* free object */
extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
+60 −28
Original line number Diff line number Diff line
@@ -6934,16 +6934,35 @@ static int nl80211_probe_client(struct sk_buff *skb,
static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
{
	struct cfg80211_registered_device *rdev = info->user_ptr[0];
	struct cfg80211_beacon_registration *reg, *nreg;
	int rv;

	if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
		return -EOPNOTSUPP;

	if (rdev->ap_beacons_nlportid)
		return -EBUSY;
	nreg = kzalloc(sizeof(*nreg), GFP_KERNEL);
	if (!nreg)
		return -ENOMEM;

	rdev->ap_beacons_nlportid = info->snd_portid;
	/* First, check if already registered. */
	spin_lock_bh(&rdev->beacon_registrations_lock);
	list_for_each_entry(reg, &rdev->beacon_registrations, list) {
		if (reg->nlportid == info->snd_portid) {
			rv = -EALREADY;
			goto out_err;
		}
	}
	/* Add it to the list */
	nreg->nlportid = info->snd_portid;
	list_add(&nreg->list, &rdev->beacon_registrations);

	spin_unlock_bh(&rdev->beacon_registrations_lock);

	return 0;
out_err:
	spin_unlock_bh(&rdev->beacon_registrations_lock);
	kfree(nreg);
	return rv;
}

static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
@@ -8957,27 +8976,26 @@ EXPORT_SYMBOL(cfg80211_probe_status);

void cfg80211_report_obss_beacon(struct wiphy *wiphy,
				 const u8 *frame, size_t len,
				 int freq, int sig_dbm, gfp_t gfp)
				 int freq, int sig_dbm)
{
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
	struct sk_buff *msg;
	void *hdr;
	u32 nlportid = ACCESS_ONCE(rdev->ap_beacons_nlportid);
	struct cfg80211_beacon_registration *reg;

	trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);

	if (!nlportid)
		return;

	msg = nlmsg_new(len + 100, gfp);
	if (!msg)
	spin_lock_bh(&rdev->beacon_registrations_lock);
	list_for_each_entry(reg, &rdev->beacon_registrations, list) {
		msg = nlmsg_new(len + 100, GFP_ATOMIC);
		if (!msg) {
			spin_unlock_bh(&rdev->beacon_registrations_lock);
			return;
		}

		hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
	if (!hdr) {
		nlmsg_free(msg);
		return;
	}
		if (!hdr)
			goto nla_put_failure;

		if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
		    (freq &&
@@ -8989,10 +9007,14 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,

		genlmsg_end(msg, hdr);

	genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
		genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid);
	}
	spin_unlock_bh(&rdev->beacon_registrations_lock);
	return;

 nla_put_failure:
	spin_unlock_bh(&rdev->beacon_registrations_lock);
	if (hdr)
		genlmsg_cancel(msg, hdr);
	nlmsg_free(msg);
}
@@ -9005,6 +9027,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
	struct netlink_notify *notify = _notify;
	struct cfg80211_registered_device *rdev;
	struct wireless_dev *wdev;
	struct cfg80211_beacon_registration *reg, *tmp;

	if (state != NETLINK_URELEASE)
		return NOTIFY_DONE;
@@ -9014,8 +9037,17 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
	list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
		list_for_each_entry_rcu(wdev, &rdev->wdev_list, list)
			cfg80211_mlme_unregister_socket(wdev, notify->portid);
		if (rdev->ap_beacons_nlportid == notify->portid)
			rdev->ap_beacons_nlportid = 0;

		spin_lock_bh(&rdev->beacon_registrations_lock);
		list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
					 list) {
			if (reg->nlportid == notify->portid) {
				list_del(&reg->list);
				kfree(reg);
				break;
			}
		}
		spin_unlock_bh(&rdev->beacon_registrations_lock);
	}

	rcu_read_unlock();