Search Linux Wireless

[PATCH] mac80211: Allow multiple listeners for management frames.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Benjamin Berg <benjamin@xxxxxxxxxxxxxxxx>

Previously it was not possible to have multiple listeners for management
frames in userspace. This is a bit weird as multiple processes in
userspace might try to request management frame reporting but only
the first request was accepted.

Signed-off-by: Benjamin Berg <benjamin@xxxxxxxxxxxxxxxx>
Signed-off-by: Sven Eckelmann <sven.eckelmann@xxxxxxxxxxxx>
---
It is currently unknown why Benjamin never forwarded it. I am doing this
now to have a chance that this private patch doesn't have to be rebased
anymore by OpenMesh.
---
 net/wireless/mlme.c | 30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 22b3d9990065..f8ce18dcaa61 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -467,6 +467,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 	struct cfg80211_mgmt_registration *reg, *nreg;
 	int err = 0;
+	int registered = 0;
 	u16 mgmt_type;
 
 	if (!wdev->wiphy->mgmt_stypes)
@@ -494,6 +495,12 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
 		if (frame_type != le16_to_cpu(reg->frame_type))
 			continue;
 
+		registered = 1;
+
+		/* Allow duplicate registrations on different ports */
+		if (snd_portid != reg->nlportid)
+			continue;
+
 		if (memcmp(reg->match, match_data, mlen) == 0) {
 			err = -EALREADY;
 			break;
@@ -516,7 +523,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid,
 	/* process all unregistrations to avoid driver confusion */
 	cfg80211_process_mlme_unregistrations(rdev);
 
-	if (rdev->ops->mgmt_frame_register)
+	if (rdev->ops->mgmt_frame_register && !registered)
 		rdev_mgmt_frame_register(rdev, wdev, frame_type, true);
 
 	return 0;
@@ -536,6 +543,26 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
 	spin_lock_bh(&wdev->mgmt_registrations_lock);
 
 	list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) {
+		struct cfg80211_mgmt_registration *inner;
+		int keep_registration = 0;
+
+		/* Do not remove registration as long as there is one other
+		 * registration for the frame type. Note that this registration
+		 * might even be on the same nlportid with a different match.
+		 */
+		list_for_each_entry(inner, &wdev->mgmt_registrations, list) {
+			if (inner == reg)
+				continue;
+
+			if (reg->frame_type == inner->frame_type) {
+				keep_registration = 1;
+				break;
+			}
+		}
+
+		if (keep_registration)
+			continue;
+
 		if (reg->nlportid != nlportid)
 			continue;
 
@@ -735,7 +762,6 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
 			continue;
 
 		result = true;
-		break;
 	}
 
 	spin_unlock_bh(&wdev->mgmt_registrations_lock);
-- 
2.11.0




[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux