You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openwrt/package/madwifi/patches/386-acl_crashfix.patch

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) \