mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-30 21:44:27 -04: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) \
 |