mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-03 22:44:27 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			117 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			117 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
fixes ACL race condition caused by acl list modifications at run time
 | 
						|
 | 
						|
Signed-off-by: Sebastian Gottschall <brainslayer@dd-wrt.com>
 | 
						|
 | 
						|
--- a/net80211/ieee80211_acl.c
 | 
						|
+++ b/net80211/ieee80211_acl.c
 | 
						|
@@ -112,9 +112,9 @@ acl_detach(struct ieee80211vap *vap)
 | 
						|
 {
 | 
						|
 	struct aclstate *as = vap->iv_as;
 | 
						|
 
 | 
						|
-	ACL_LOCK(as);
 | 
						|
+	ACL_LOCK_IRQ(as);
 | 
						|
 	acl_free_all_locked(as);
 | 
						|
-	ACL_UNLOCK(as);
 | 
						|
+	ACL_UNLOCK_IRQ(as);
 | 
						|
 	vap->iv_as = NULL;
 | 
						|
 	ACL_LOCK_DESTROY(as);
 | 
						|
 	FREE(as, M_DEVBUF);
 | 
						|
@@ -128,11 +128,18 @@ _find_acl(struct aclstate *as, const u_i
 | 
						|
 	struct acl *acl;
 | 
						|
 	int hash;
 | 
						|
 
 | 
						|
+	/* locking needed, as inserts are not atomic */
 | 
						|
+	ACL_LOCK_IRQ(as);
 | 
						|
 	hash = ACL_HASH(macaddr);
 | 
						|
 	LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
 | 
						|
-		if (IEEE80211_ADDR_EQ(acl->acl_macaddr, macaddr))
 | 
						|
-			return acl;
 | 
						|
+		if (!IEEE80211_ADDR_EQ(acl->acl_macaddr, macaddr))
 | 
						|
+			continue;
 | 
						|
+
 | 
						|
+		ACL_UNLOCK_IRQ_EARLY(as);
 | 
						|
+		return acl;
 | 
						|
 	}
 | 
						|
+	ACL_UNLOCK_IRQ(as);
 | 
						|
+
 | 
						|
 	return NULL;
 | 
						|
 }
 | 
						|
 
 | 
						|
@@ -176,11 +183,11 @@ acl_add(struct ieee80211vap *vap, const
 | 
						|
 		return -ENOMEM;
 | 
						|
 	}
 | 
						|
 
 | 
						|
-	ACL_LOCK(as);
 | 
						|
+	ACL_LOCK_IRQ(as);
 | 
						|
 	hash = ACL_HASH(mac);
 | 
						|
 	LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
 | 
						|
 		if (IEEE80211_ADDR_EQ(acl->acl_macaddr, mac)) {
 | 
						|
-			ACL_UNLOCK_EARLY(as);
 | 
						|
+			ACL_UNLOCK_IRQ_EARLY(as);
 | 
						|
 			FREE(new, M_80211_ACL);
 | 
						|
 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
 | 
						|
 				"ACL: add " MAC_FMT " failed, already present\n",
 | 
						|
@@ -191,7 +198,7 @@ acl_add(struct ieee80211vap *vap, const
 | 
						|
 	IEEE80211_ADDR_COPY(new->acl_macaddr, mac);
 | 
						|
 	TAILQ_INSERT_TAIL(&as->as_list, new, acl_list);
 | 
						|
 	LIST_INSERT_HEAD(&as->as_hash[hash], new, acl_hash);
 | 
						|
-	ACL_UNLOCK(as);
 | 
						|
+	ACL_UNLOCK_IRQ(as);
 | 
						|
 
 | 
						|
 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
 | 
						|
 		"ACL: add " MAC_FMT "\n", MAC_ADDR(mac));
 | 
						|
@@ -204,11 +211,11 @@ acl_remove(struct ieee80211vap *vap, con
 | 
						|
 	struct aclstate *as = vap->iv_as;
 | 
						|
 	struct acl *acl;
 | 
						|
 
 | 
						|
-	ACL_LOCK(as);
 | 
						|
+	ACL_LOCK_IRQ(as);
 | 
						|
 	acl = _find_acl(as, mac);
 | 
						|
 	if (acl != NULL)
 | 
						|
 		_acl_free(as, acl);
 | 
						|
-	ACL_UNLOCK(as);
 | 
						|
+	ACL_UNLOCK_IRQ(as);
 | 
						|
 
 | 
						|
 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
 | 
						|
 		"ACL: remove " MAC_FMT "%s\n", MAC_ADDR(mac),
 | 
						|
@@ -235,9 +242,9 @@ acl_free_all(struct ieee80211vap *vap)
 | 
						|
 
 | 
						|
 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL, "ACL: %s\n", "free all");
 | 
						|
 
 | 
						|
-	ACL_LOCK(as);
 | 
						|
+	ACL_LOCK_IRQ(as);
 | 
						|
 	acl_free_all_locked(vap->iv_as);
 | 
						|
-	ACL_UNLOCK(as);
 | 
						|
+	ACL_UNLOCK_IRQ(as);
 | 
						|
 
 | 
						|
 	return 0;
 | 
						|
 }
 | 
						|
--- a/net80211/ieee80211_linux.h
 | 
						|
+++ b/net80211/ieee80211_linux.h
 | 
						|
@@ -319,16 +319,15 @@ typedef spinlock_t ieee80211_scan_lock_t
 | 
						|
 typedef spinlock_t acl_lock_t;
 | 
						|
 #define	ACL_LOCK_INIT(_as, _name)	spin_lock_init(&(_as)->as_lock)
 | 
						|
 #define	ACL_LOCK_DESTROY(_as)
 | 
						|
-#define	ACL_LOCK(_as)			do { 	\
 | 
						|
-	ACL_LOCK_CHECK(_as); 		\
 | 
						|
-	spin_lock(&(_as)->as_lock);
 | 
						|
-#define	ACL_UNLOCK(_as)				\
 | 
						|
-	ACL_LOCK_ASSERT(_as); 			\
 | 
						|
-	spin_unlock(&(_as)->as_lock); 		\
 | 
						|
-} while(0)
 | 
						|
-#define ACL_UNLOCK_EARLY(_as)			\
 | 
						|
-	ACL_LOCK_ASSERT(_as); 			\
 | 
						|
-	spin_unlock(&(_as)->as_lock);
 | 
						|
+#define	ACL_LOCK_IRQ(_as)	do {	\
 | 
						|
+	unsigned long __acl_lockflags;		\
 | 
						|
+	spin_lock_irqsave(&(_as)->as_lock, __acl_lockflags);
 | 
						|
+#define	ACL_UNLOCK_IRQ(_as) \
 | 
						|
+	spin_unlock_irqrestore(&(_as)->as_lock, __acl_lockflags); \
 | 
						|
+} while (0)
 | 
						|
+#define	ACL_UNLOCK_IRQ_EARLY(_as)	do { \
 | 
						|
+	spin_unlock_irqrestore(&(_as)->as_lock, __acl_lockflags); \
 | 
						|
+} while (0)
 | 
						|
 
 | 
						|
 #if (defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)) && defined(spin_is_locked)
 | 
						|
 #define	ACL_LOCK_ASSERT(_as) \
 |