Commit 37c73b5f323c973c1db6857494a6685260440be1
Committed by
Johannes Berg
1 parent
391e53e33f
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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 |
net/mac80211/rx.c
net/wireless/core.c
... | ... | @@ -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(®->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); |
net/wireless/core.h
... | ... | @@ -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(®->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(); |