Commit 37c73b5f323c973c1db6857494a6685260440be1

Authored by Ben Greear
Committed by Johannes Berg
1 parent 391e53e33f

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>

Showing 5 changed files with 75 additions and 32 deletions Side-by-side Diff

include/net/cfg80211.h
... ... @@ -3560,7 +3560,6 @@
3560 3560 * @len: length of the frame
3561 3561 * @freq: frequency the frame was received on
3562 3562 * @sig_dbm: signal strength in mBm, or 0 if unknown
3563   - * @gfp: allocation flags
3564 3563 *
3565 3564 * Use this function to report to userspace when a beacon was
3566 3565 * received. It is not useful to call this when there is no
... ... @@ -3568,7 +3567,7 @@
3568 3567 */
3569 3568 void cfg80211_report_obss_beacon(struct wiphy *wiphy,
3570 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 3573 * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used
... ... @@ -2200,7 +2200,7 @@
2200 2200  
2201 2201 cfg80211_report_obss_beacon(rx->local->hw.wiphy,
2202 2202 rx->skb->data, rx->skb->len,
2203   - status->freq, sig, GFP_ATOMIC);
  2203 + status->freq, sig);
2204 2204 rx->flags |= IEEE80211_RX_BEACON_REPORTED;
2205 2205 }
2206 2206  
... ... @@ -326,6 +326,8 @@
326 326 mutex_init(&rdev->devlist_mtx);
327 327 mutex_init(&rdev->sched_scan_mtx);
328 328 INIT_LIST_HEAD(&rdev->wdev_list);
  329 + INIT_LIST_HEAD(&rdev->beacon_registrations);
  330 + spin_lock_init(&rdev->beacon_registrations_lock);
329 331 spin_lock_init(&rdev->bss_lock);
330 332 INIT_LIST_HEAD(&rdev->bss_list);
331 333 INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
332 334  
... ... @@ -698,10 +700,15 @@
698 700 void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
699 701 {
700 702 struct cfg80211_internal_bss *scan, *tmp;
  703 + struct cfg80211_beacon_registration *reg, *treg;
701 704 rfkill_destroy(rdev->rfkill);
702 705 mutex_destroy(&rdev->mtx);
703 706 mutex_destroy(&rdev->devlist_mtx);
704 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 712 list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
706 713 cfg80211_put_bss(&scan->pub);
707 714 kfree(rdev);
... ... @@ -55,7 +55,8 @@
55 55 int opencount; /* also protected by devlist_mtx */
56 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 61 /* protected by RTNL only */
61 62 int num_running_ifaces;
... ... @@ -260,6 +261,10 @@
260 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 269 /* free object */
265 270 extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
net/wireless/nl80211.c
... ... @@ -6934,16 +6934,35 @@
6934 6934 static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
6935 6935 {
6936 6936 struct cfg80211_registered_device *rdev = info->user_ptr[0];
  6937 + struct cfg80211_beacon_registration *reg, *nreg;
  6938 + int rv;
6937 6939  
6938 6940 if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
6939 6941 return -EOPNOTSUPP;
6940 6942  
6941   - if (rdev->ap_beacons_nlportid)
6942   - return -EBUSY;
  6943 + nreg = kzalloc(sizeof(*nreg), GFP_KERNEL);
  6944 + if (!nreg)
  6945 + return -ENOMEM;
6943 6946  
6944   - rdev->ap_beacons_nlportid = info->snd_portid;
  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);
6945 6958  
  6959 + spin_unlock_bh(&rdev->beacon_registrations_lock);
  6960 +
6946 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 6968 static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
6950 6969  
6951 6970  
6952 6971  
6953 6972  
6954 6973  
6955 6974  
6956 6975  
... ... @@ -8957,43 +8976,46 @@
8957 8976  
8958 8977 void cfg80211_report_obss_beacon(struct wiphy *wiphy,
8959 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 8981 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
8963 8982 struct sk_buff *msg;
8964 8983 void *hdr;
8965   - u32 nlportid = ACCESS_ONCE(rdev->ap_beacons_nlportid);
  8984 + struct cfg80211_beacon_registration *reg;
8966 8985  
8967 8986 trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);
8968 8987  
8969   - if (!nlportid)
8970   - return;
  8988 + spin_lock_bh(&rdev->beacon_registrations_lock);
  8989 + list_for_each_entry(reg, &rdev->beacon_registrations, list) {
  8990 + msg = nlmsg_new(len + 100, GFP_ATOMIC);
  8991 + if (!msg) {
  8992 + spin_unlock_bh(&rdev->beacon_registrations_lock);
  8993 + return;
  8994 + }
8971 8995  
8972   - msg = nlmsg_new(len + 100, gfp);
8973   - if (!msg)
8974   - return;
  8996 + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
  8997 + if (!hdr)
  8998 + goto nla_put_failure;
8975 8999  
8976   - hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
8977   - if (!hdr) {
8978   - nlmsg_free(msg);
8979   - return;
8980   - }
  9000 + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
  9001 + (freq &&
  9002 + nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
  9003 + (sig_dbm &&
  9004 + nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
  9005 + nla_put(msg, NL80211_ATTR_FRAME, len, frame))
  9006 + goto nla_put_failure;
8981 9007  
8982   - if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
8983   - (freq &&
8984   - nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
8985   - (sig_dbm &&
8986   - nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
8987   - nla_put(msg, NL80211_ATTR_FRAME, len, frame))
8988   - goto nla_put_failure;
  9008 + genlmsg_end(msg, hdr);
8989 9009  
8990   - genlmsg_end(msg, hdr);
8991   -
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 9013 return;
8994 9014  
8995 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 9019 nlmsg_free(msg);
8998 9020 }
8999 9021 EXPORT_SYMBOL(cfg80211_report_obss_beacon);
... ... @@ -9005,6 +9027,7 @@
9005 9027 struct netlink_notify *notify = _notify;
9006 9028 struct cfg80211_registered_device *rdev;
9007 9029 struct wireless_dev *wdev;
  9030 + struct cfg80211_beacon_registration *reg, *tmp;
9008 9031  
9009 9032 if (state != NETLINK_URELEASE)
9010 9033 return NOTIFY_DONE;
... ... @@ -9014,8 +9037,17 @@
9014 9037 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
9015 9038 list_for_each_entry_rcu(wdev, &rdev->wdev_list, list)
9016 9039 cfg80211_mlme_unregister_socket(wdev, notify->portid);
9017   - if (rdev->ap_beacons_nlportid == notify->portid)
9018   - rdev->ap_beacons_nlportid = 0;
  9040 +
  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 9053 rcu_read_unlock();