cfg80211: allow registering more than one beacon listener

The commit:

commit 5e760230e4
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: Ben Greear <greearb@candelatech.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
このコミットが含まれているのは:
Ben Greear
2012-10-26 14:49:25 -07:00
committed by Johannes Berg
コミット 37c73b5f32
5個のファイルの変更76行の追加33行の削除

ファイルの表示

@@ -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,43 +8976,46 @@ 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;
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;
}
msg = nlmsg_new(len + 100, gfp);
if (!msg)
return;
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
if (!hdr)
goto nla_put_failure;
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
if (!hdr) {
nlmsg_free(msg);
return;
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
(freq &&
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
(sig_dbm &&
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
nla_put(msg, NL80211_ATTR_FRAME, len, frame))
goto nla_put_failure;
genlmsg_end(msg, hdr);
genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid);
}
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
(freq &&
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
(sig_dbm &&
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
nla_put(msg, NL80211_ATTR_FRAME, len, frame))
goto nla_put_failure;
genlmsg_end(msg, hdr);
genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
spin_unlock_bh(&rdev->beacon_registrations_lock);
return;
nla_put_failure:
genlmsg_cancel(msg, hdr);
spin_unlock_bh(&rdev->beacon_registrations_lock);
if (hdr)
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
}
EXPORT_SYMBOL(cfg80211_report_obss_beacon);
@@ -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();