diff options
author | Ben Greear <greearb@candelatech.com> | 2012-10-26 17:49:25 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-11-05 10:33:45 -0500 |
commit | 37c73b5f323c973c1db6857494a6685260440be1 (patch) | |
tree | 5f9e2b055552c6e5053f8a2ab2ebb686b3af5411 | |
parent | 391e53e33f0028f52ce5eedee1026830571f0d76 (diff) |
cfg80211: allow registering more than one beacon listener
The commit:
commit 5e760230e42cf759bd923457ca2753aacf2e656e
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>
-rw-r--r-- | include/net/cfg80211.h | 3 | ||||
-rw-r--r-- | net/mac80211/rx.c | 2 | ||||
-rw-r--r-- | net/wireless/core.c | 7 | ||||
-rw-r--r-- | net/wireless/core.h | 7 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 88 |
5 files changed, 75 insertions, 32 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index cee791fd4cff..10c9fc68d1af 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -3560,7 +3560,6 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, | |||
3560 | * @len: length of the frame | 3560 | * @len: length of the frame |
3561 | * @freq: frequency the frame was received on | 3561 | * @freq: frequency the frame was received on |
3562 | * @sig_dbm: signal strength in mBm, or 0 if unknown | 3562 | * @sig_dbm: signal strength in mBm, or 0 if unknown |
3563 | * @gfp: allocation flags | ||
3564 | * | 3563 | * |
3565 | * Use this function to report to userspace when a beacon was | 3564 | * Use this function to report to userspace when a beacon was |
3566 | * received. It is not useful to call this when there is no | 3565 | * 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, | |||
3568 | */ | 3567 | */ |
3569 | void cfg80211_report_obss_beacon(struct wiphy *wiphy, | 3568 | void cfg80211_report_obss_beacon(struct wiphy *wiphy, |
3570 | const u8 *frame, size_t len, | 3569 | const u8 *frame, size_t len, |
3571 | int freq, int sig_dbm, gfp_t gfp); | 3570 | int freq, int sig_dbm); |
3572 | 3571 | ||
3573 | /** | 3572 | /** |
3574 | * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used | 3573 | * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 38b382682cae..6ad330341b71 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -2200,7 +2200,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) | |||
2200 | 2200 | ||
2201 | cfg80211_report_obss_beacon(rx->local->hw.wiphy, | 2201 | cfg80211_report_obss_beacon(rx->local->hw.wiphy, |
2202 | rx->skb->data, rx->skb->len, | 2202 | rx->skb->data, rx->skb->len, |
2203 | status->freq, sig, GFP_ATOMIC); | 2203 | status->freq, sig); |
2204 | rx->flags |= IEEE80211_RX_BEACON_REPORTED; | 2204 | rx->flags |= IEEE80211_RX_BEACON_REPORTED; |
2205 | } | 2205 | } |
2206 | 2206 | ||
diff --git a/net/wireless/core.c b/net/wireless/core.c index 26711f46a3be..14d990400354 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -326,6 +326,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
326 | mutex_init(&rdev->devlist_mtx); | 326 | mutex_init(&rdev->devlist_mtx); |
327 | mutex_init(&rdev->sched_scan_mtx); | 327 | mutex_init(&rdev->sched_scan_mtx); |
328 | INIT_LIST_HEAD(&rdev->wdev_list); | 328 | INIT_LIST_HEAD(&rdev->wdev_list); |
329 | INIT_LIST_HEAD(&rdev->beacon_registrations); | ||
330 | spin_lock_init(&rdev->beacon_registrations_lock); | ||
329 | spin_lock_init(&rdev->bss_lock); | 331 | spin_lock_init(&rdev->bss_lock); |
330 | INIT_LIST_HEAD(&rdev->bss_list); | 332 | INIT_LIST_HEAD(&rdev->bss_list); |
331 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); | 333 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); |
@@ -698,10 +700,15 @@ EXPORT_SYMBOL(wiphy_unregister); | |||
698 | void cfg80211_dev_free(struct cfg80211_registered_device *rdev) | 700 | void cfg80211_dev_free(struct cfg80211_registered_device *rdev) |
699 | { | 701 | { |
700 | struct cfg80211_internal_bss *scan, *tmp; | 702 | struct cfg80211_internal_bss *scan, *tmp; |
703 | struct cfg80211_beacon_registration *reg, *treg; | ||
701 | rfkill_destroy(rdev->rfkill); | 704 | rfkill_destroy(rdev->rfkill); |
702 | mutex_destroy(&rdev->mtx); | 705 | mutex_destroy(&rdev->mtx); |
703 | mutex_destroy(&rdev->devlist_mtx); | 706 | mutex_destroy(&rdev->devlist_mtx); |
704 | mutex_destroy(&rdev->sched_scan_mtx); | 707 | mutex_destroy(&rdev->sched_scan_mtx); |
708 | list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) { | ||
709 | list_del(®->list); | ||
710 | kfree(reg); | ||
711 | } | ||
705 | list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) | 712 | list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) |
706 | cfg80211_put_bss(&scan->pub); | 713 | cfg80211_put_bss(&scan->pub); |
707 | kfree(rdev); | 714 | kfree(rdev); |
diff --git a/net/wireless/core.h b/net/wireless/core.h index b8eb743fe7da..e53831c876bb 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -55,7 +55,8 @@ struct cfg80211_registered_device { | |||
55 | int opencount; /* also protected by devlist_mtx */ | 55 | int opencount; /* also protected by devlist_mtx */ |
56 | wait_queue_head_t dev_wait; | 56 | wait_queue_head_t dev_wait; |
57 | 57 | ||
58 | u32 ap_beacons_nlportid; | 58 | struct list_head beacon_registrations; |
59 | spinlock_t beacon_registrations_lock; | ||
59 | 60 | ||
60 | /* protected by RTNL only */ | 61 | /* protected by RTNL only */ |
61 | int num_running_ifaces; | 62 | int num_running_ifaces; |
@@ -260,6 +261,10 @@ enum cfg80211_chan_mode { | |||
260 | CHAN_MODE_EXCLUSIVE, | 261 | CHAN_MODE_EXCLUSIVE, |
261 | }; | 262 | }; |
262 | 263 | ||
264 | struct cfg80211_beacon_registration { | ||
265 | struct list_head list; | ||
266 | u32 nlportid; | ||
267 | }; | ||
263 | 268 | ||
264 | /* free object */ | 269 | /* free object */ |
265 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); | 270 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 9b0a3b8fd20a..ba44f98c56d9 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -6934,16 +6934,35 @@ static int nl80211_probe_client(struct sk_buff *skb, | |||
6934 | static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) | 6934 | static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) |
6935 | { | 6935 | { |
6936 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6936 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6937 | struct cfg80211_beacon_registration *reg, *nreg; | ||
6938 | int rv; | ||
6937 | 6939 | ||
6938 | if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS)) | 6940 | if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS)) |
6939 | return -EOPNOTSUPP; | 6941 | return -EOPNOTSUPP; |
6940 | 6942 | ||
6941 | if (rdev->ap_beacons_nlportid) | 6943 | nreg = kzalloc(sizeof(*nreg), GFP_KERNEL); |
6942 | return -EBUSY; | 6944 | if (!nreg) |
6945 | return -ENOMEM; | ||
6946 | |||
6947 | /* First, check if already registered. */ | ||
6948 | spin_lock_bh(&rdev->beacon_registrations_lock); | ||
6949 | list_for_each_entry(reg, &rdev->beacon_registrations, list) { | ||
6950 | if (reg->nlportid == info->snd_portid) { | ||
6951 | rv = -EALREADY; | ||
6952 | goto out_err; | ||
6953 | } | ||
6954 | } | ||
6955 | /* Add it to the list */ | ||
6956 | nreg->nlportid = info->snd_portid; | ||
6957 | list_add(&nreg->list, &rdev->beacon_registrations); | ||
6943 | 6958 | ||
6944 | rdev->ap_beacons_nlportid = info->snd_portid; | 6959 | spin_unlock_bh(&rdev->beacon_registrations_lock); |
6945 | 6960 | ||
6946 | return 0; | 6961 | return 0; |
6962 | out_err: | ||
6963 | spin_unlock_bh(&rdev->beacon_registrations_lock); | ||
6964 | kfree(nreg); | ||
6965 | return rv; | ||
6947 | } | 6966 | } |
6948 | 6967 | ||
6949 | static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info) | 6968 | static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info) |
@@ -8957,43 +8976,46 @@ EXPORT_SYMBOL(cfg80211_probe_status); | |||
8957 | 8976 | ||
8958 | void cfg80211_report_obss_beacon(struct wiphy *wiphy, | 8977 | void cfg80211_report_obss_beacon(struct wiphy *wiphy, |
8959 | const u8 *frame, size_t len, | 8978 | const u8 *frame, size_t len, |
8960 | int freq, int sig_dbm, gfp_t gfp) | 8979 | int freq, int sig_dbm) |
8961 | { | 8980 | { |
8962 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 8981 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
8963 | struct sk_buff *msg; | 8982 | struct sk_buff *msg; |
8964 | void *hdr; | 8983 | void *hdr; |
8965 | u32 nlportid = ACCESS_ONCE(rdev->ap_beacons_nlportid); | 8984 | struct cfg80211_beacon_registration *reg; |
8966 | 8985 | ||
8967 | trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm); | 8986 | trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm); |
8968 | 8987 | ||
8969 | if (!nlportid) | 8988 | spin_lock_bh(&rdev->beacon_registrations_lock); |
8970 | return; | 8989 | list_for_each_entry(reg, &rdev->beacon_registrations, list) { |
8971 | 8990 | msg = nlmsg_new(len + 100, GFP_ATOMIC); | |
8972 | msg = nlmsg_new(len + 100, gfp); | 8991 | if (!msg) { |
8973 | if (!msg) | 8992 | spin_unlock_bh(&rdev->beacon_registrations_lock); |
8974 | return; | 8993 | return; |
8994 | } | ||
8975 | 8995 | ||
8976 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); | 8996 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); |
8977 | if (!hdr) { | 8997 | if (!hdr) |
8978 | nlmsg_free(msg); | 8998 | goto nla_put_failure; |
8979 | return; | ||
8980 | } | ||
8981 | 8999 | ||
8982 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 9000 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
8983 | (freq && | 9001 | (freq && |
8984 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) || | 9002 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) || |
8985 | (sig_dbm && | 9003 | (sig_dbm && |
8986 | nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || | 9004 | nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || |
8987 | nla_put(msg, NL80211_ATTR_FRAME, len, frame)) | 9005 | nla_put(msg, NL80211_ATTR_FRAME, len, frame)) |
8988 | goto nla_put_failure; | 9006 | goto nla_put_failure; |
8989 | 9007 | ||
8990 | genlmsg_end(msg, hdr); | 9008 | genlmsg_end(msg, hdr); |
8991 | 9009 | ||
8992 | genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid); | 9010 | genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid); |
9011 | } | ||
9012 | spin_unlock_bh(&rdev->beacon_registrations_lock); | ||
8993 | return; | 9013 | return; |
8994 | 9014 | ||
8995 | nla_put_failure: | 9015 | nla_put_failure: |
8996 | genlmsg_cancel(msg, hdr); | 9016 | spin_unlock_bh(&rdev->beacon_registrations_lock); |
9017 | if (hdr) | ||
9018 | genlmsg_cancel(msg, hdr); | ||
8997 | nlmsg_free(msg); | 9019 | nlmsg_free(msg); |
8998 | } | 9020 | } |
8999 | EXPORT_SYMBOL(cfg80211_report_obss_beacon); | 9021 | EXPORT_SYMBOL(cfg80211_report_obss_beacon); |
@@ -9005,6 +9027,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
9005 | struct netlink_notify *notify = _notify; | 9027 | struct netlink_notify *notify = _notify; |
9006 | struct cfg80211_registered_device *rdev; | 9028 | struct cfg80211_registered_device *rdev; |
9007 | struct wireless_dev *wdev; | 9029 | struct wireless_dev *wdev; |
9030 | struct cfg80211_beacon_registration *reg, *tmp; | ||
9008 | 9031 | ||
9009 | if (state != NETLINK_URELEASE) | 9032 | if (state != NETLINK_URELEASE) |
9010 | return NOTIFY_DONE; | 9033 | return NOTIFY_DONE; |
@@ -9014,8 +9037,17 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
9014 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { | 9037 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { |
9015 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) | 9038 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) |
9016 | cfg80211_mlme_unregister_socket(wdev, notify->portid); | 9039 | cfg80211_mlme_unregister_socket(wdev, notify->portid); |
9017 | if (rdev->ap_beacons_nlportid == notify->portid) | 9040 | |
9018 | rdev->ap_beacons_nlportid = 0; | 9041 | spin_lock_bh(&rdev->beacon_registrations_lock); |
9042 | list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations, | ||
9043 | list) { | ||
9044 | if (reg->nlportid == notify->portid) { | ||
9045 | list_del(®->list); | ||
9046 | kfree(reg); | ||
9047 | break; | ||
9048 | } | ||
9049 | } | ||
9050 | spin_unlock_bh(&rdev->beacon_registrations_lock); | ||
9019 | } | 9051 | } |
9020 | 9052 | ||
9021 | rcu_read_unlock(); | 9053 | rcu_read_unlock(); |