diff options
Diffstat (limited to 'package/madwifi/patches/386-acl_crashfix.patch')
-rw-r--r-- | package/madwifi/patches/386-acl_crashfix.patch | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/package/madwifi/patches/386-acl_crashfix.patch b/package/madwifi/patches/386-acl_crashfix.patch new file mode 100644 index 0000000000..12f3273f68 --- /dev/null +++ b/package/madwifi/patches/386-acl_crashfix.patch @@ -0,0 +1,116 @@ +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 +@@ -311,16 +311,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) \ |