madwifi: fix ACL race condition (patch by Sebastian Gottschall)
[openwrt/svn-archive/archive.git] / package / madwifi / patches / 386-acl_crashfix.patch
1 fixes ACL race condition caused by acl list modifications at run time
2
3 Signed-off-by: Sebastian Gottschall <brainslayer@dd-wrt.com>
4
5 --- a/net80211/ieee80211_acl.c
6 +++ b/net80211/ieee80211_acl.c
7 @@ -112,9 +112,9 @@ acl_detach(struct ieee80211vap *vap)
8 {
9 struct aclstate *as = vap->iv_as;
10
11 - ACL_LOCK(as);
12 + ACL_LOCK_IRQ(as);
13 acl_free_all_locked(as);
14 - ACL_UNLOCK(as);
15 + ACL_UNLOCK_IRQ(as);
16 vap->iv_as = NULL;
17 ACL_LOCK_DESTROY(as);
18 FREE(as, M_DEVBUF);
19 @@ -128,11 +128,18 @@ _find_acl(struct aclstate *as, const u_i
20 struct acl *acl;
21 int hash;
22
23 + /* locking needed, as inserts are not atomic */
24 + ACL_LOCK_IRQ(as);
25 hash = ACL_HASH(macaddr);
26 LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
27 - if (IEEE80211_ADDR_EQ(acl->acl_macaddr, macaddr))
28 - return acl;
29 + if (!IEEE80211_ADDR_EQ(acl->acl_macaddr, macaddr))
30 + continue;
31 +
32 + ACL_UNLOCK_IRQ_EARLY(as);
33 + return acl;
34 }
35 + ACL_UNLOCK_IRQ(as);
36 +
37 return NULL;
38 }
39
40 @@ -176,11 +183,11 @@ acl_add(struct ieee80211vap *vap, const
41 return -ENOMEM;
42 }
43
44 - ACL_LOCK(as);
45 + ACL_LOCK_IRQ(as);
46 hash = ACL_HASH(mac);
47 LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
48 if (IEEE80211_ADDR_EQ(acl->acl_macaddr, mac)) {
49 - ACL_UNLOCK_EARLY(as);
50 + ACL_UNLOCK_IRQ_EARLY(as);
51 FREE(new, M_80211_ACL);
52 IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
53 "ACL: add " MAC_FMT " failed, already present\n",
54 @@ -191,7 +198,7 @@ acl_add(struct ieee80211vap *vap, const
55 IEEE80211_ADDR_COPY(new->acl_macaddr, mac);
56 TAILQ_INSERT_TAIL(&as->as_list, new, acl_list);
57 LIST_INSERT_HEAD(&as->as_hash[hash], new, acl_hash);
58 - ACL_UNLOCK(as);
59 + ACL_UNLOCK_IRQ(as);
60
61 IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
62 "ACL: add " MAC_FMT "\n", MAC_ADDR(mac));
63 @@ -204,11 +211,11 @@ acl_remove(struct ieee80211vap *vap, con
64 struct aclstate *as = vap->iv_as;
65 struct acl *acl;
66
67 - ACL_LOCK(as);
68 + ACL_LOCK_IRQ(as);
69 acl = _find_acl(as, mac);
70 if (acl != NULL)
71 _acl_free(as, acl);
72 - ACL_UNLOCK(as);
73 + ACL_UNLOCK_IRQ(as);
74
75 IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
76 "ACL: remove " MAC_FMT "%s\n", MAC_ADDR(mac),
77 @@ -235,9 +242,9 @@ acl_free_all(struct ieee80211vap *vap)
78
79 IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL, "ACL: %s\n", "free all");
80
81 - ACL_LOCK(as);
82 + ACL_LOCK_IRQ(as);
83 acl_free_all_locked(vap->iv_as);
84 - ACL_UNLOCK(as);
85 + ACL_UNLOCK_IRQ(as);
86
87 return 0;
88 }
89 --- a/net80211/ieee80211_linux.h
90 +++ b/net80211/ieee80211_linux.h
91 @@ -311,16 +311,15 @@ typedef spinlock_t ieee80211_scan_lock_t
92 typedef spinlock_t acl_lock_t;
93 #define ACL_LOCK_INIT(_as, _name) spin_lock_init(&(_as)->as_lock)
94 #define ACL_LOCK_DESTROY(_as)
95 -#define ACL_LOCK(_as) do { \
96 - ACL_LOCK_CHECK(_as); \
97 - spin_lock(&(_as)->as_lock);
98 -#define ACL_UNLOCK(_as) \
99 - ACL_LOCK_ASSERT(_as); \
100 - spin_unlock(&(_as)->as_lock); \
101 -} while(0)
102 -#define ACL_UNLOCK_EARLY(_as) \
103 - ACL_LOCK_ASSERT(_as); \
104 - spin_unlock(&(_as)->as_lock);
105 +#define ACL_LOCK_IRQ(_as) do { \
106 + unsigned long __acl_lockflags; \
107 + spin_lock_irqsave(&(_as)->as_lock, __acl_lockflags);
108 +#define ACL_UNLOCK_IRQ(_as) \
109 + spin_unlock_irqrestore(&(_as)->as_lock, __acl_lockflags); \
110 +} while (0)
111 +#define ACL_UNLOCK_IRQ_EARLY(_as) do { \
112 + spin_unlock_irqrestore(&(_as)->as_lock, __acl_lockflags); \
113 +} while (0)
114
115 #if (defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)) && defined(spin_is_locked)
116 #define ACL_LOCK_ASSERT(_as) \