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>
This commit is contained in:
parent
391e53e33f
commit
37c73b5f32
|
@ -3560,7 +3560,6 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
|
||||||
* @len: length of the frame
|
* @len: length of the frame
|
||||||
* @freq: frequency the frame was received on
|
* @freq: frequency the frame was received on
|
||||||
* @sig_dbm: signal strength in mBm, or 0 if unknown
|
* @sig_dbm: signal strength in mBm, or 0 if unknown
|
||||||
* @gfp: allocation flags
|
|
||||||
*
|
*
|
||||||
* Use this function to report to userspace when a beacon was
|
* Use this function to report to userspace when a beacon was
|
||||||
* received. It is not useful to call this when there is no
|
* 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,
|
void cfg80211_report_obss_beacon(struct wiphy *wiphy,
|
||||||
const u8 *frame, size_t len,
|
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
|
* cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used
|
||||||
|
|
|
@ -2200,7 +2200,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
|
||||||
|
|
||||||
cfg80211_report_obss_beacon(rx->local->hw.wiphy,
|
cfg80211_report_obss_beacon(rx->local->hw.wiphy,
|
||||||
rx->skb->data, rx->skb->len,
|
rx->skb->data, rx->skb->len,
|
||||||
status->freq, sig, GFP_ATOMIC);
|
status->freq, sig);
|
||||||
rx->flags |= IEEE80211_RX_BEACON_REPORTED;
|
rx->flags |= IEEE80211_RX_BEACON_REPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -326,6 +326,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
|
||||||
mutex_init(&rdev->devlist_mtx);
|
mutex_init(&rdev->devlist_mtx);
|
||||||
mutex_init(&rdev->sched_scan_mtx);
|
mutex_init(&rdev->sched_scan_mtx);
|
||||||
INIT_LIST_HEAD(&rdev->wdev_list);
|
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);
|
spin_lock_init(&rdev->bss_lock);
|
||||||
INIT_LIST_HEAD(&rdev->bss_list);
|
INIT_LIST_HEAD(&rdev->bss_list);
|
||||||
INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
|
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)
|
void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
|
||||||
{
|
{
|
||||||
struct cfg80211_internal_bss *scan, *tmp;
|
struct cfg80211_internal_bss *scan, *tmp;
|
||||||
|
struct cfg80211_beacon_registration *reg, *treg;
|
||||||
rfkill_destroy(rdev->rfkill);
|
rfkill_destroy(rdev->rfkill);
|
||||||
mutex_destroy(&rdev->mtx);
|
mutex_destroy(&rdev->mtx);
|
||||||
mutex_destroy(&rdev->devlist_mtx);
|
mutex_destroy(&rdev->devlist_mtx);
|
||||||
mutex_destroy(&rdev->sched_scan_mtx);
|
mutex_destroy(&rdev->sched_scan_mtx);
|
||||||
|
list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) {
|
||||||
|
list_del(®->list);
|
||||||
|
kfree(reg);
|
||||||
|
}
|
||||||
list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
|
list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
|
||||||
cfg80211_put_bss(&scan->pub);
|
cfg80211_put_bss(&scan->pub);
|
||||||
kfree(rdev);
|
kfree(rdev);
|
||||||
|
|
|
@ -55,7 +55,8 @@ struct cfg80211_registered_device {
|
||||||
int opencount; /* also protected by devlist_mtx */
|
int opencount; /* also protected by devlist_mtx */
|
||||||
wait_queue_head_t dev_wait;
|
wait_queue_head_t dev_wait;
|
||||||
|
|
||||||
u32 ap_beacons_nlportid;
|
struct list_head beacon_registrations;
|
||||||
|
spinlock_t beacon_registrations_lock;
|
||||||
|
|
||||||
/* protected by RTNL only */
|
/* protected by RTNL only */
|
||||||
int num_running_ifaces;
|
int num_running_ifaces;
|
||||||
|
@ -260,6 +261,10 @@ enum cfg80211_chan_mode {
|
||||||
CHAN_MODE_EXCLUSIVE,
|
CHAN_MODE_EXCLUSIVE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct cfg80211_beacon_registration {
|
||||||
|
struct list_head list;
|
||||||
|
u32 nlportid;
|
||||||
|
};
|
||||||
|
|
||||||
/* free object */
|
/* free object */
|
||||||
extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
|
extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
|
||||||
|
|
|
@ -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)
|
static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
|
||||||
{
|
{
|
||||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
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))
|
if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
if (rdev->ap_beacons_nlportid)
|
nreg = kzalloc(sizeof(*nreg), GFP_KERNEL);
|
||||||
return -EBUSY;
|
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;
|
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)
|
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,
|
void cfg80211_report_obss_beacon(struct wiphy *wiphy,
|
||||||
const u8 *frame, size_t len,
|
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 cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||||
struct sk_buff *msg;
|
struct sk_buff *msg;
|
||||||
void *hdr;
|
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);
|
trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);
|
||||||
|
|
||||||
if (!nlportid)
|
spin_lock_bh(&rdev->beacon_registrations_lock);
|
||||||
return;
|
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);
|
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
|
||||||
if (!msg)
|
if (!hdr)
|
||||||
return;
|
goto nla_put_failure;
|
||||||
|
|
||||||
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
|
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
|
||||||
if (!hdr) {
|
(freq &&
|
||||||
nlmsg_free(msg);
|
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
|
||||||
return;
|
(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);
|
||||||
}
|
}
|
||||||
|
spin_unlock_bh(&rdev->beacon_registrations_lock);
|
||||||
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);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
genlmsg_cancel(msg, hdr);
|
spin_unlock_bh(&rdev->beacon_registrations_lock);
|
||||||
|
if (hdr)
|
||||||
|
genlmsg_cancel(msg, hdr);
|
||||||
nlmsg_free(msg);
|
nlmsg_free(msg);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(cfg80211_report_obss_beacon);
|
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 netlink_notify *notify = _notify;
|
||||||
struct cfg80211_registered_device *rdev;
|
struct cfg80211_registered_device *rdev;
|
||||||
struct wireless_dev *wdev;
|
struct wireless_dev *wdev;
|
||||||
|
struct cfg80211_beacon_registration *reg, *tmp;
|
||||||
|
|
||||||
if (state != NETLINK_URELEASE)
|
if (state != NETLINK_URELEASE)
|
||||||
return NOTIFY_DONE;
|
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(rdev, &cfg80211_rdev_list, list) {
|
||||||
list_for_each_entry_rcu(wdev, &rdev->wdev_list, list)
|
list_for_each_entry_rcu(wdev, &rdev->wdev_list, list)
|
||||||
cfg80211_mlme_unregister_socket(wdev, notify->portid);
|
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(®->list);
|
||||||
|
kfree(reg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&rdev->beacon_registrations_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
Loading…
Reference in New Issue