aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
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 /net/wireless/nl80211.c
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>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c88
1 files changed, 60 insertions, 28 deletions
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();