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 /net/wireless/nl80211.c | |
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>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 88 |
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, | |||
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(); |