madwifi: fix the long standing bug that is triggered by nodes getting a timeout on...
[openwrt/openwrt.git] / package / madwifi / patches / 393-mbss_vap_auth.patch
1 --- a/net80211/ieee80211_node.c
2 +++ b/net80211/ieee80211_node.c
3 @@ -123,6 +123,9 @@ static void ieee80211_node_table_cleanup
4 static void ieee80211_node_table_reset(struct ieee80211_node_table *,
5 struct ieee80211vap *);
6
7 +static struct ieee80211_node *
8 +lookup_rxnode(struct ieee80211com *ic, struct ieee80211vap *vap, const u_int8_t *addr);
9 +
10 MALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state");
11
12 void
13 @@ -697,7 +700,7 @@ ieee80211_sta_join(struct ieee80211vap *
14 struct ieee80211com *ic = vap->iv_ic;
15 struct ieee80211_node *ni;
16
17 - ni = ieee80211_find_node(&ic->ic_sta, se->se_macaddr);
18 + ni = lookup_rxnode(ic, vap, se->se_macaddr);
19 if (ni == NULL) {
20 ni = ieee80211_alloc_node_table(vap, se->se_macaddr);
21 IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
22 @@ -1391,6 +1394,53 @@ ieee80211_add_neighbor(struct ieee80211v
23 return ni;
24 }
25
26 +struct ieee80211vap *
27 +ieee80211_find_rxvap(struct ieee80211com *ic, const u_int8_t *mac)
28 +{
29 + struct ieee80211vap *vap;
30 +
31 + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
32 + if (IEEE80211_ADDR_EQ(vap->iv_myaddr, mac))
33 + return vap;
34 + }
35 + return NULL;
36 +}
37 +EXPORT_SYMBOL(ieee80211_find_rxvap);
38 +
39 +static struct ieee80211_node *
40 +lookup_rxnode(struct ieee80211com *ic, struct ieee80211vap *vap,
41 + const u_int8_t *addr)
42 +{
43 + struct ieee80211_node_table *nt;
44 + struct ieee80211_node *ni = NULL;
45 + int use_bss = 0;
46 + int hash;
47 +
48 + nt = &ic->ic_sta;
49 + IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
50 + hash = IEEE80211_NODE_HASH(addr);
51 + LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
52 + if (IEEE80211_ADDR_EQ(ni->ni_macaddr, addr)) {
53 + /* allow multiple nodes on different vaps */
54 + if (vap && (ni->ni_vap != vap))
55 + continue;
56 +
57 + ieee80211_ref_node(ni);
58 + goto out;
59 + }
60 + }
61 +
62 + /* no match found */
63 + ni = NULL;
64 +
65 +out:
66 + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
67 + return ni;
68 +#undef IS_PSPOLL
69 +#undef IS_CTL
70 +}
71 +
72 +
73 /*
74 * Return the node for the sender of a frame; if the sender is unknown return
75 * NULL. The caller is expected to deal with this. (The frame is sent to all
76 @@ -1400,10 +1450,10 @@ ieee80211_add_neighbor(struct ieee80211v
77 */
78 struct ieee80211_node *
79 #ifdef IEEE80211_DEBUG_REFCNT
80 -ieee80211_find_rxnode_debug(struct ieee80211com *ic,
81 +ieee80211_find_rxnode_debug(struct ieee80211com *ic, struct ieee80211vap *vap,
82 const struct ieee80211_frame_min *wh, const char *func, int line)
83 #else
84 -ieee80211_find_rxnode(struct ieee80211com *ic,
85 +ieee80211_find_rxnode(struct ieee80211com *ic, struct ieee80211vap *vap,
86 const struct ieee80211_frame_min *wh)
87 #endif
88 {
89 @@ -1411,9 +1461,8 @@ ieee80211_find_rxnode(struct ieee80211co
90 ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
91 #define IS_PSPOLL(wh) \
92 ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL)
93 - struct ieee80211_node_table *nt;
94 - struct ieee80211_node *ni;
95 - struct ieee80211vap *vap, *avp;
96 + struct ieee80211_node *ni = NULL;
97 + struct ieee80211vap *avp;
98 const u_int8_t *addr;
99
100 if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/)
101 @@ -1426,32 +1475,21 @@ ieee80211_find_rxnode(struct ieee80211co
102
103 /* XXX check ic_bss first in station mode */
104 /* XXX 4-address frames? */
105 - nt = &ic->ic_sta;
106 - IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
107 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) {
108 - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
109 + if (vap) { /* assume unicast if vap is set, mcast not supported for wds */
110 TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) {
111 - if (!IEEE80211_ADDR_EQ(addr, avp->wds_mac))
112 + if (!IEEE80211_ADDR_EQ(addr, avp->wds_mac) ||
113 + !IEEE80211_ADDR_EQ(wh->i_addr1, avp->iv_myaddr))
114 continue;
115
116 if (avp->iv_wdsnode)
117 - return ieee80211_ref_node(avp->iv_wdsnode);
118 - else
119 - return NULL;
120 + ni = ieee80211_ref_node(avp->iv_wdsnode);
121 }
122 }
123 + return ni;
124 }
125
126 -#ifdef IEEE80211_DEBUG_REFCNT
127 - ni = ieee80211_find_node_locked_debug(nt, addr, func, line);
128 -#else
129 - ni = ieee80211_find_node_locked(nt, addr);
130 -#endif
131 - IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
132 -
133 - return ni;
134 -#undef IS_PSPOLL
135 -#undef IS_CTL
136 + return lookup_rxnode(ic, vap, addr);
137 }
138 #ifdef IEEE80211_DEBUG_REFCNT
139 EXPORT_SYMBOL(ieee80211_find_rxnode_debug);
140 @@ -1476,15 +1514,14 @@ ieee80211_find_txnode(struct ieee80211va
141 struct ieee80211com *ic = vap->iv_ic;
142 struct ieee80211_node_table *nt;
143 struct ieee80211_node *ni = NULL;
144 + int hash;
145
146 - IEEE80211_LOCK_IRQ(ic);
147 if (vap->iv_opmode == IEEE80211_M_WDS) {
148 if (vap->iv_wdsnode && (vap->iv_state == IEEE80211_S_RUN))
149 return ieee80211_ref_node(vap->iv_wdsnode);
150 else
151 return NULL;
152 }
153 - IEEE80211_UNLOCK_IRQ(ic);
154
155 /*
156 * The destination address should be in the node table
157 @@ -1502,11 +1539,22 @@ ieee80211_find_txnode(struct ieee80211va
158 /* XXX: Can't hold lock across dup_bss due to recursive locking. */
159 nt = &vap->iv_ic->ic_sta;
160 IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
161 + hash = IEEE80211_NODE_HASH(mac);
162 + LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
163 + if (ni->ni_vap != vap)
164 + continue;
165 +
166 + if (IEEE80211_ADDR_EQ(ni->ni_macaddr, mac)) {
167 #ifdef IEEE80211_DEBUG_REFCNT
168 - ni = ieee80211_find_node_locked_debug(nt, mac, func, line);
169 + ieee80211_ref_node_debug(ni, func, line);
170 #else
171 - ni = ieee80211_find_node_locked(nt, mac);
172 + ieee80211_ref_node(ni);
173 #endif
174 + goto found;
175 + }
176 + }
177 + ni = NULL;
178 +found:
179 IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
180
181 if (ni == NULL) {
182 @@ -1961,13 +2009,29 @@ remove_worse_nodes(void *arg, struct iee
183 }
184 }
185
186 +static void
187 +remove_duplicate_nodes(void *arg, struct ieee80211_node *ni)
188 +{
189 + struct ieee80211_node *rni = arg;
190 +
191 + if (ni == rni)
192 + return;
193 +
194 + if (ni->ni_vap == rni->ni_vap)
195 + return;
196 +
197 + ieee80211_node_leave(ni);
198 +}
199 +
200 void
201 ieee80211_node_join(struct ieee80211_node *ni, int resp)
202 {
203 struct ieee80211com *ic = ni->ni_ic;
204 struct ieee80211vap *vap = ni->ni_vap;
205 + struct ieee80211_node *tni;
206 int newassoc;
207
208 + ieee80211_iterate_nodes(&ic->ic_sta, remove_duplicate_nodes, ni);
209 if (ni->ni_associd == 0) {
210 u_int16_t aid;
211
212 --- a/net80211/ieee80211_input.c
213 +++ b/net80211/ieee80211_input.c
214 @@ -227,15 +227,22 @@ ieee80211_input(struct ieee80211vap * va
215 if (!dev)
216 goto out;
217
218 + if ((vap->iv_dev->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
219 + goto out;
220 +
221 + if (!vap->iv_bss)
222 + goto out;
223 +
224 /* initialize ni as in the previous API */
225 if (ni_or_null == NULL) {
226 /* This function does not 'own' vap->iv_bss, so we cannot
227 * guarantee its existence during the following call, hence
228 * briefly grab our own reference. */
229 ni = ieee80211_ref_node(vap->iv_bss);
230 + KASSERT(ni != NULL, ("null node"));
231 + } else {
232 + ni->ni_inact = ni->ni_inact_reload;
233 }
234 - KASSERT(ni != NULL, ("null node"));
235 - ni->ni_inact = ni->ni_inact_reload;
236
237 KASSERT(skb->len >= sizeof(struct ieee80211_frame_min),
238 ("frame length too short: %u", skb->len));
239 @@ -933,16 +940,23 @@ int
240 ieee80211_input_all(struct ieee80211com *ic,
241 struct sk_buff *skb, int rssi, u_int64_t rtsf)
242 {
243 + struct ieee80211_frame_min *wh = (struct ieee80211_frame_min *) skb->data;
244 struct ieee80211vap *vap;
245 int type = -1;
246
247 /* XXX locking */
248 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
249 + struct ieee80211_node *ni = NULL;
250 struct sk_buff *skb1;
251
252 if ((vap->iv_dev->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
253 continue;
254
255 + if ((vap->iv_opmode == IEEE80211_M_HOSTAP) &&
256 + !IEEE80211_IS_MULTICAST(wh->i_addr1))
257 + continue;
258 +
259 + ni = ieee80211_find_rxnode(ic, vap, wh);
260 if (TAILQ_NEXT(vap, iv_next) != NULL) {
261 skb1 = skb_copy(skb, GFP_ATOMIC);
262 if (skb1 == NULL) {
263 @@ -954,8 +968,10 @@ ieee80211_input_all(struct ieee80211com
264 skb1 = skb;
265 skb = NULL;
266 }
267 - type = ieee80211_input(vap, NULL, skb1, rssi, rtsf);
268 + type = ieee80211_input(vap, ni, skb1, rssi, rtsf);
269 }
270 +
271 +out:
272 if (skb != NULL) /* no vaps, reclaim skb */
273 ieee80211_dev_kfree_skb(&skb);
274 return type;
275 @@ -1146,11 +1162,9 @@ ieee80211_deliver_data(struct ieee80211_
276 * sending it will not work; just let it be
277 * delivered normally.
278 */
279 - struct ieee80211_node *ni1 = ieee80211_find_node(
280 - &vap->iv_ic->ic_sta, eh->ether_dhost);
281 + struct ieee80211_node *ni1 = ieee80211_find_txnode(vap, eh->ether_dhost);
282 if (ni1 != NULL) {
283 - if (ni1->ni_vap == vap &&
284 - ieee80211_node_is_authorized(ni1) &&
285 + if (ieee80211_node_is_authorized(ni1) &&
286 !ni1->ni_subif &&
287 ni1 != vap->iv_bss) {
288
289 --- a/ath/if_ath.c
290 +++ b/ath/if_ath.c
291 @@ -6577,9 +6577,8 @@ ath_recv_mgmt(struct ieee80211vap * vap,
292
293 sc->sc_recv_mgmt(vap, ni_or_null, skb, subtype, rssi, rtsf);
294
295 -
296 /* Lookup the new node if any (this grabs a reference to it) */
297 - ni = ieee80211_find_rxnode(vap->iv_ic,
298 + ni = ieee80211_find_rxnode(vap->iv_ic, vap,
299 (const struct ieee80211_frame_min *)skb->data);
300 if (ni == NULL) {
301 DPRINTF(sc, ATH_DEBUG_BEACON, "Dropping; node unknown.\n");
302 @@ -6734,7 +6733,9 @@ ath_rx_poll(struct net_device *dev, int
303 struct ath_desc *ds;
304 struct ath_rx_status *rs;
305 struct sk_buff *skb = NULL;
306 + struct ieee80211vap *vap;
307 struct ieee80211_node *ni;
308 + const struct ieee80211_frame_min *wh;
309 unsigned int len;
310 int type;
311 u_int phyerr;
312 @@ -6889,12 +6890,15 @@ rx_accept:
313 skb_trim(skb, skb->len - IEEE80211_CRC_LEN);
314
315 if (mic_fail) {
316 + wh = (const struct ieee80211_frame_min *) skb->data;
317 +
318 /* Ignore control frames which are reported with mic error */
319 - if ((((struct ieee80211_frame *)skb->data)->i_fc[0] &
320 + if ((wh->i_fc[0] &
321 IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
322 goto drop_micfail;
323
324 - ni = ieee80211_find_rxnode(ic, (const struct ieee80211_frame_min *) skb->data);
325 + vap = ieee80211_find_rxvap(ic, wh->i_addr1);
326 + ni = ieee80211_find_rxnode(ic, vap, wh);
327
328 if (ni && ni->ni_table) {
329 ieee80211_check_mic(ni, skb);
330 @@ -6956,11 +6960,24 @@ drop_micfail:
331 * for its use. If the sender is unknown spam the
332 * frame; it'll be dropped where it's not wanted.
333 */
334 - if (rs->rs_keyix != HAL_RXKEYIX_INVALID &&
335 + wh = (const struct ieee80211_frame_min *) skb->data;
336 + if ((rs->rs_keyix != HAL_RXKEYIX_INVALID) &&
337 (ni = sc->sc_keyixmap[rs->rs_keyix]) != NULL) {
338 /* Fast path: node is present in the key map;
339 * grab a reference for processing the frame. */
340 - ni = ieee80211_ref_node(ni);
341 + ieee80211_ref_node(ni);
342 + if ((ATH_GET_VAP_ID(wh->i_addr1) !=
343 + ATH_GET_VAP_ID(ni->ni_vap->iv_myaddr)) ||
344 + ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) ==
345 + IEEE80211_FC1_DIR_DSTODS)) {
346 + /* key cache node lookup is fast, but it can
347 + * lead to problems in multi-bss (foreign vap
348 + * node reference) or wds (wdsap node ref instead
349 + * of base ap node ref).
350 + * use slowpath lookup in both cases
351 + */
352 + goto lookup_slowpath;
353 + }
354 ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi);
355 type = ieee80211_input(ni->ni_vap, ni, skb, rs->rs_rssi, bf->bf_tsf);
356 ieee80211_unref_node(&ni);
357 @@ -6969,24 +6986,35 @@ drop_micfail:
358 * No key index or no entry, do a lookup and
359 * add the node to the mapping table if possible.
360 */
361 - ni = ieee80211_find_rxnode(ic,
362 - (const struct ieee80211_frame_min *)skb->data);
363 +
364 +lookup_slowpath:
365 + vap = ieee80211_find_rxvap(ic, wh->i_addr1);
366 + if (vap)
367 + ni = ieee80211_find_rxnode(ic, vap, wh);
368 + else
369 + ni = NULL;
370 +
371 if (ni != NULL) {
372 ieee80211_keyix_t keyix;
373
374 ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi);
375 - type = ieee80211_input(ni->ni_vap, ni, skb, rs->rs_rssi, bf->bf_tsf);
376 + type = ieee80211_input(vap, ni, skb, rs->rs_rssi, bf->bf_tsf);
377 /*
378 * If the station has a key cache slot assigned
379 * update the key->node mapping table.
380 */
381 keyix = ni->ni_ucastkey.wk_keyix;
382 if (keyix != IEEE80211_KEYIX_NONE &&
383 - sc->sc_keyixmap[keyix] == NULL)
384 + sc->sc_keyixmap[keyix] == NULL) {
385 sc->sc_keyixmap[keyix] = ieee80211_ref_node(ni);
386 + }
387 ieee80211_unref_node(&ni);
388 - } else
389 - type = ieee80211_input_all(ic, skb, rs->rs_rssi, bf->bf_tsf);
390 + } else {
391 + if (vap)
392 + type = ieee80211_input(vap, NULL, skb, rs->rs_rssi, bf->bf_tsf);
393 + else
394 + type = ieee80211_input_all(ic, skb, rs->rs_rssi, bf->bf_tsf);
395 + }
396 }
397
398 if (sc->sc_diversity) {
399 --- a/net80211/ieee80211_node.h
400 +++ b/net80211/ieee80211_node.h
401 @@ -286,15 +286,18 @@ struct ieee80211_node *ieee80211_find_no
402 const u_int8_t *);
403 #endif /* #ifdef IEEE80211_DEBUG_REFCNT */
404
405 +struct ieee80211vap *
406 +ieee80211_find_rxvap(struct ieee80211com *ic, const u_int8_t *mac);
407 +
408 /* Returns a ieee80211_node* with refcount incremented, if found */
409 #ifdef IEEE80211_DEBUG_REFCNT
410 -#define ieee80211_find_rxnode(_nt, _wh) \
411 - ieee80211_find_rxnode_debug(_nt, _wh, __func__, __LINE__)
412 +#define ieee80211_find_rxnode(_nt, _vap, _wh) \
413 + ieee80211_find_rxnode_debug(_nt, _vap, _wh, __func__, __LINE__)
414 struct ieee80211_node *ieee80211_find_rxnode_debug(struct ieee80211com *,
415 - const struct ieee80211_frame_min *, const char *, int);
416 + struct ieee80211vap *, const struct ieee80211_frame_min *, const char *, int);
417 #else
418 struct ieee80211_node *ieee80211_find_rxnode(struct ieee80211com *,
419 - const struct ieee80211_frame_min *);
420 + struct ieee80211vap *, const struct ieee80211_frame_min *);
421 #endif /* #ifdef IEEE80211_DEBUG_REFCNT */
422
423 /* Returns a ieee80211_node* with refcount incremented, if found */