aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Greear <greearb@candelatech.com>2012-10-26 17:49:25 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-11-05 10:33:45 -0500
commit37c73b5f323c973c1db6857494a6685260440be1 (patch)
tree5f9e2b055552c6e5053f8a2ab2ebb686b3af5411
parent391e53e33f0028f52ce5eedee1026830571f0d76 (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.h3
-rw-r--r--net/mac80211/rx.c2
-rw-r--r--net/wireless/core.c7
-rw-r--r--net/wireless/core.h7
-rw-r--r--net/wireless/nl80211.c88
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 */
3569void cfg80211_report_obss_beacon(struct wiphy *wiphy, 3568void 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);
698void cfg80211_dev_free(struct cfg80211_registered_device *rdev) 700void 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(&reg->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
264struct cfg80211_beacon_registration {
265 struct list_head list;
266 u32 nlportid;
267};
263 268
264/* free object */ 269/* free object */
265extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); 270extern 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,
6934static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) 6934static 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;
6962out_err:
6963 spin_unlock_bh(&rdev->beacon_registrations_lock);
6964 kfree(nreg);
6965 return rv;
6947} 6966}
6948 6967
6949static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info) 6968static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
@@ -8957,43 +8976,46 @@ EXPORT_SYMBOL(cfg80211_probe_status);
8957 8976
8958void cfg80211_report_obss_beacon(struct wiphy *wiphy, 8977void 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}
8999EXPORT_SYMBOL(cfg80211_report_obss_beacon); 9021EXPORT_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(&reg->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();