diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-02-25 10:27:46 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-03-06 15:30:46 -0500 |
commit | d0709a65181beb787ef3f58cfe45536a2bb254c8 (patch) | |
tree | 29e5f36583b0e0a3f11b291347e57672eab41dad /net/mac80211/mesh_plink.c | |
parent | 5cf121c3cdb955583bf0c5d28c992b7968a4aa1a (diff) |
mac80211: RCU-ify STA info structure access
This makes access to the STA hash table/list use RCU to protect
against freeing of items. However, it's not a true RCU, the
copy step is missing: whenever somebody changes a STA item it
is simply updated. This is an existing race condition that is
now somewhat understandable.
This patch also fixes the race key freeing vs. STA destruction
by making sure that sta_info_destroy() is always called under
RTNL and frees the key.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mesh_plink.c')
-rw-r--r-- | net/mac80211/mesh_plink.c | 101 |
1 files changed, 52 insertions, 49 deletions
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index b5fbe970e48f..c2b80500ae72 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -65,14 +65,14 @@ static inline | |||
65 | void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) | 65 | void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) |
66 | { | 66 | { |
67 | atomic_inc(&sdata->u.sta.mshstats.estab_plinks); | 67 | atomic_inc(&sdata->u.sta.mshstats.estab_plinks); |
68 | mesh_accept_plinks_update(sdata->dev); | 68 | mesh_accept_plinks_update(sdata); |
69 | } | 69 | } |
70 | 70 | ||
71 | static inline | 71 | static inline |
72 | void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) | 72 | void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) |
73 | { | 73 | { |
74 | atomic_dec(&sdata->u.sta.mshstats.estab_plinks); | 74 | atomic_dec(&sdata->u.sta.mshstats.estab_plinks); |
75 | mesh_accept_plinks_update(sdata->dev); | 75 | mesh_accept_plinks_update(sdata); |
76 | } | 76 | } |
77 | 77 | ||
78 | /** | 78 | /** |
@@ -99,12 +99,13 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta) | |||
99 | * | 99 | * |
100 | * Returns: non-NULL on success, ERR_PTR() on error. | 100 | * Returns: non-NULL on success, ERR_PTR() on error. |
101 | */ | 101 | */ |
102 | struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) | 102 | struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, |
103 | struct ieee80211_sub_if_data *sdata) | ||
103 | { | 104 | { |
104 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 105 | struct ieee80211_local *local = sdata->local; |
105 | struct sta_info *sta; | 106 | struct sta_info *sta; |
106 | 107 | ||
107 | if (memcmp(hw_addr, dev->dev_addr, ETH_ALEN) == 0) | 108 | if (compare_ether_addr(hw_addr, sdata->dev->dev_addr) == 0) |
108 | /* never add ourselves as neighbours */ | 109 | /* never add ourselves as neighbours */ |
109 | return ERR_PTR(-EINVAL); | 110 | return ERR_PTR(-EINVAL); |
110 | 111 | ||
@@ -114,7 +115,7 @@ struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) | |||
114 | if (local->num_sta >= MESH_MAX_PLINKS) | 115 | if (local->num_sta >= MESH_MAX_PLINKS) |
115 | return ERR_PTR(-ENOSPC); | 116 | return ERR_PTR(-ENOSPC); |
116 | 117 | ||
117 | sta = sta_info_add(local, dev, hw_addr, GFP_KERNEL); | 118 | sta = sta_info_add(sdata, hw_addr); |
118 | if (IS_ERR(sta)) | 119 | if (IS_ERR(sta)) |
119 | return sta; | 120 | return sta; |
120 | 121 | ||
@@ -125,7 +126,7 @@ struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) | |||
125 | sta->supp_rates[local->hw.conf.channel->band] = rates; | 126 | sta->supp_rates[local->hw.conf.channel->band] = rates; |
126 | rate_control_rate_init(sta, local); | 127 | rate_control_rate_init(sta, local); |
127 | 128 | ||
128 | mesh_accept_plinks_update(dev); | 129 | mesh_accept_plinks_update(sdata); |
129 | 130 | ||
130 | return sta; | 131 | return sta; |
131 | } | 132 | } |
@@ -141,7 +142,8 @@ struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) | |||
141 | */ | 142 | */ |
142 | static void __mesh_plink_deactivate(struct sta_info *sta) | 143 | static void __mesh_plink_deactivate(struct sta_info *sta) |
143 | { | 144 | { |
144 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 145 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
146 | |||
145 | if (sta->plink_state == ESTAB) | 147 | if (sta->plink_state == ESTAB) |
146 | mesh_plink_dec_estab_count(sdata); | 148 | mesh_plink_dec_estab_count(sdata); |
147 | sta->plink_state = BLOCKED; | 149 | sta->plink_state = BLOCKED; |
@@ -246,11 +248,15 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, | |||
246 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 248 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
247 | struct sta_info *sta; | 249 | struct sta_info *sta; |
248 | 250 | ||
251 | rcu_read_lock(); | ||
252 | |||
249 | sta = sta_info_get(local, hw_addr); | 253 | sta = sta_info_get(local, hw_addr); |
250 | if (!sta) { | 254 | if (!sta) { |
251 | sta = mesh_plink_add(hw_addr, rates, dev); | 255 | sta = mesh_plink_add(hw_addr, rates, sdata); |
252 | if (IS_ERR(sta)) | 256 | if (IS_ERR(sta)) { |
257 | rcu_read_unlock(); | ||
253 | return; | 258 | return; |
259 | } | ||
254 | } | 260 | } |
255 | 261 | ||
256 | sta->last_rx = jiffies; | 262 | sta->last_rx = jiffies; |
@@ -260,7 +266,7 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, | |||
260 | sdata->u.sta.mshcfg.auto_open_plinks) | 266 | sdata->u.sta.mshcfg.auto_open_plinks) |
261 | mesh_plink_open(sta); | 267 | mesh_plink_open(sta); |
262 | 268 | ||
263 | sta_info_put(sta); | 269 | rcu_read_unlock(); |
264 | } | 270 | } |
265 | 271 | ||
266 | static void mesh_plink_timer(unsigned long data) | 272 | static void mesh_plink_timer(unsigned long data) |
@@ -273,6 +279,11 @@ static void mesh_plink_timer(unsigned long data) | |||
273 | DECLARE_MAC_BUF(mac); | 279 | DECLARE_MAC_BUF(mac); |
274 | #endif | 280 | #endif |
275 | 281 | ||
282 | /* | ||
283 | * This STA is valid because sta_info_destroy() will | ||
284 | * del_timer_sync() this timer after having made sure | ||
285 | * it cannot be readded (by deleting the plink.) | ||
286 | */ | ||
276 | sta = (struct sta_info *) data; | 287 | sta = (struct sta_info *) data; |
277 | 288 | ||
278 | spin_lock_bh(&sta->plink_lock); | 289 | spin_lock_bh(&sta->plink_lock); |
@@ -286,8 +297,8 @@ static void mesh_plink_timer(unsigned long data) | |||
286 | reason = 0; | 297 | reason = 0; |
287 | llid = sta->llid; | 298 | llid = sta->llid; |
288 | plid = sta->plid; | 299 | plid = sta->plid; |
289 | dev = sta->dev; | 300 | sdata = sta->sdata; |
290 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 301 | dev = sdata->dev; |
291 | 302 | ||
292 | switch (sta->plink_state) { | 303 | switch (sta->plink_state) { |
293 | case OPN_RCVD: | 304 | case OPN_RCVD: |
@@ -302,8 +313,7 @@ static void mesh_plink_timer(unsigned long data) | |||
302 | sta->plink_timeout = sta->plink_timeout + | 313 | sta->plink_timeout = sta->plink_timeout + |
303 | rand % sta->plink_timeout; | 314 | rand % sta->plink_timeout; |
304 | ++sta->plink_retries; | 315 | ++sta->plink_retries; |
305 | if (!mod_plink_timer(sta, sta->plink_timeout)) | 316 | mod_plink_timer(sta, sta->plink_timeout); |
306 | __sta_info_get(sta); | ||
307 | spin_unlock_bh(&sta->plink_lock); | 317 | spin_unlock_bh(&sta->plink_lock); |
308 | mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid, | 318 | mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid, |
309 | 0, 0); | 319 | 0, 0); |
@@ -316,16 +326,14 @@ static void mesh_plink_timer(unsigned long data) | |||
316 | if (!reason) | 326 | if (!reason) |
317 | reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); | 327 | reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); |
318 | sta->plink_state = HOLDING; | 328 | sta->plink_state = HOLDING; |
319 | if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) | 329 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
320 | __sta_info_get(sta); | ||
321 | spin_unlock_bh(&sta->plink_lock); | 330 | spin_unlock_bh(&sta->plink_lock); |
322 | mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, | 331 | mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, |
323 | reason); | 332 | reason); |
324 | break; | 333 | break; |
325 | case HOLDING: | 334 | case HOLDING: |
326 | /* holding timer */ | 335 | /* holding timer */ |
327 | if (del_timer(&sta->plink_timer)) | 336 | del_timer(&sta->plink_timer); |
328 | sta_info_put(sta); | ||
329 | mesh_plink_fsm_restart(sta); | 337 | mesh_plink_fsm_restart(sta); |
330 | spin_unlock_bh(&sta->plink_lock); | 338 | spin_unlock_bh(&sta->plink_lock); |
331 | break; | 339 | break; |
@@ -333,8 +341,6 @@ static void mesh_plink_timer(unsigned long data) | |||
333 | spin_unlock_bh(&sta->plink_lock); | 341 | spin_unlock_bh(&sta->plink_lock); |
334 | break; | 342 | break; |
335 | } | 343 | } |
336 | |||
337 | sta_info_put(sta); | ||
338 | } | 344 | } |
339 | 345 | ||
340 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) | 346 | static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) |
@@ -343,14 +349,13 @@ static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) | |||
343 | sta->plink_timer.data = (unsigned long) sta; | 349 | sta->plink_timer.data = (unsigned long) sta; |
344 | sta->plink_timer.function = mesh_plink_timer; | 350 | sta->plink_timer.function = mesh_plink_timer; |
345 | sta->plink_timeout = timeout; | 351 | sta->plink_timeout = timeout; |
346 | __sta_info_get(sta); | ||
347 | add_timer(&sta->plink_timer); | 352 | add_timer(&sta->plink_timer); |
348 | } | 353 | } |
349 | 354 | ||
350 | int mesh_plink_open(struct sta_info *sta) | 355 | int mesh_plink_open(struct sta_info *sta) |
351 | { | 356 | { |
352 | __le16 llid; | 357 | __le16 llid; |
353 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 358 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
354 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | 359 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG |
355 | DECLARE_MAC_BUF(mac); | 360 | DECLARE_MAC_BUF(mac); |
356 | #endif | 361 | #endif |
@@ -360,7 +365,6 @@ int mesh_plink_open(struct sta_info *sta) | |||
360 | sta->llid = llid; | 365 | sta->llid = llid; |
361 | if (sta->plink_state != LISTEN) { | 366 | if (sta->plink_state != LISTEN) { |
362 | spin_unlock_bh(&sta->plink_lock); | 367 | spin_unlock_bh(&sta->plink_lock); |
363 | sta_info_put(sta); | ||
364 | return -EBUSY; | 368 | return -EBUSY; |
365 | } | 369 | } |
366 | sta->plink_state = OPN_SNT; | 370 | sta->plink_state = OPN_SNT; |
@@ -369,7 +373,8 @@ int mesh_plink_open(struct sta_info *sta) | |||
369 | mpl_dbg("Mesh plink: starting establishment with %s\n", | 373 | mpl_dbg("Mesh plink: starting establishment with %s\n", |
370 | print_mac(mac, sta->addr)); | 374 | print_mac(mac, sta->addr)); |
371 | 375 | ||
372 | return mesh_plink_frame_tx(sta->dev, PLINK_OPEN, sta->addr, llid, 0, 0); | 376 | return mesh_plink_frame_tx(sdata->dev, PLINK_OPEN, |
377 | sta->addr, llid, 0, 0); | ||
373 | } | 378 | } |
374 | 379 | ||
375 | void mesh_plink_block(struct sta_info *sta) | 380 | void mesh_plink_block(struct sta_info *sta) |
@@ -386,7 +391,7 @@ void mesh_plink_block(struct sta_info *sta) | |||
386 | 391 | ||
387 | int mesh_plink_close(struct sta_info *sta) | 392 | int mesh_plink_close(struct sta_info *sta) |
388 | { | 393 | { |
389 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 394 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
390 | int llid, plid, reason; | 395 | int llid, plid, reason; |
391 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | 396 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG |
392 | DECLARE_MAC_BUF(mac); | 397 | DECLARE_MAC_BUF(mac); |
@@ -401,13 +406,11 @@ int mesh_plink_close(struct sta_info *sta) | |||
401 | if (sta->plink_state == LISTEN || sta->plink_state == BLOCKED) { | 406 | if (sta->plink_state == LISTEN || sta->plink_state == BLOCKED) { |
402 | mesh_plink_fsm_restart(sta); | 407 | mesh_plink_fsm_restart(sta); |
403 | spin_unlock_bh(&sta->plink_lock); | 408 | spin_unlock_bh(&sta->plink_lock); |
404 | sta_info_put(sta); | ||
405 | return 0; | 409 | return 0; |
406 | } else if (sta->plink_state == ESTAB) { | 410 | } else if (sta->plink_state == ESTAB) { |
407 | __mesh_plink_deactivate(sta); | 411 | __mesh_plink_deactivate(sta); |
408 | /* The timer should not be running */ | 412 | /* The timer should not be running */ |
409 | if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) | 413 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
410 | __sta_info_get(sta); | ||
411 | } else if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) | 414 | } else if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) |
412 | sta->ignore_plink_timer = true; | 415 | sta->ignore_plink_timer = true; |
413 | 416 | ||
@@ -415,15 +418,16 @@ int mesh_plink_close(struct sta_info *sta) | |||
415 | llid = sta->llid; | 418 | llid = sta->llid; |
416 | plid = sta->plid; | 419 | plid = sta->plid; |
417 | spin_unlock_bh(&sta->plink_lock); | 420 | spin_unlock_bh(&sta->plink_lock); |
418 | mesh_plink_frame_tx(sta->dev, PLINK_CLOSE, sta->addr, llid, plid, | 421 | mesh_plink_frame_tx(sta->sdata->dev, PLINK_CLOSE, sta->addr, llid, |
419 | reason); | 422 | plid, reason); |
420 | return 0; | 423 | return 0; |
421 | } | 424 | } |
422 | 425 | ||
423 | void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | 426 | void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, |
424 | size_t len, struct ieee80211_rx_status *rx_status) | 427 | size_t len, struct ieee80211_rx_status *rx_status) |
425 | { | 428 | { |
426 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 429 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
430 | struct ieee80211_local *local = sdata->local; | ||
427 | struct ieee802_11_elems elems; | 431 | struct ieee802_11_elems elems; |
428 | struct sta_info *sta; | 432 | struct sta_info *sta; |
429 | enum plink_event event; | 433 | enum plink_event event; |
@@ -435,7 +439,6 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
435 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | 439 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG |
436 | DECLARE_MAC_BUF(mac); | 440 | DECLARE_MAC_BUF(mac); |
437 | #endif | 441 | #endif |
438 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
439 | 442 | ||
440 | if (is_multicast_ether_addr(mgmt->da)) { | 443 | if (is_multicast_ether_addr(mgmt->da)) { |
441 | mpl_dbg("Mesh plink: ignore frame from multicast address"); | 444 | mpl_dbg("Mesh plink: ignore frame from multicast address"); |
@@ -474,14 +477,17 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
474 | if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7)) | 477 | if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7)) |
475 | memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); | 478 | memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); |
476 | 479 | ||
480 | rcu_read_lock(); | ||
481 | |||
477 | sta = sta_info_get(local, mgmt->sa); | 482 | sta = sta_info_get(local, mgmt->sa); |
478 | if (!sta && ftype != PLINK_OPEN) { | 483 | if (!sta && ftype != PLINK_OPEN) { |
479 | mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); | 484 | mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); |
485 | rcu_read_unlock(); | ||
480 | return; | 486 | return; |
481 | } | 487 | } |
482 | 488 | ||
483 | if (sta && sta->plink_state == BLOCKED) { | 489 | if (sta && sta->plink_state == BLOCKED) { |
484 | sta_info_put(sta); | 490 | rcu_read_unlock(); |
485 | return; | 491 | return; |
486 | } | 492 | } |
487 | 493 | ||
@@ -505,13 +511,15 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
505 | u64 rates; | 511 | u64 rates; |
506 | if (!mesh_plink_free_count(sdata)) { | 512 | if (!mesh_plink_free_count(sdata)) { |
507 | mpl_dbg("Mesh plink error: no more free plinks\n"); | 513 | mpl_dbg("Mesh plink error: no more free plinks\n"); |
514 | rcu_read_unlock(); | ||
508 | return; | 515 | return; |
509 | } | 516 | } |
510 | 517 | ||
511 | rates = ieee80211_sta_get_rates(local, &elems, rx_status->band); | 518 | rates = ieee80211_sta_get_rates(local, &elems, rx_status->band); |
512 | sta = mesh_plink_add(mgmt->sa, rates, dev); | 519 | sta = mesh_plink_add(mgmt->sa, rates, sdata); |
513 | if (IS_ERR(sta)) { | 520 | if (IS_ERR(sta)) { |
514 | mpl_dbg("Mesh plink error: plink table full\n"); | 521 | mpl_dbg("Mesh plink error: plink table full\n"); |
522 | rcu_read_unlock(); | ||
515 | return; | 523 | return; |
516 | } | 524 | } |
517 | event = OPN_ACPT; | 525 | event = OPN_ACPT; |
@@ -521,14 +529,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
521 | switch (ftype) { | 529 | switch (ftype) { |
522 | case PLINK_OPEN: | 530 | case PLINK_OPEN: |
523 | if (!mesh_plink_free_count(sdata) || | 531 | if (!mesh_plink_free_count(sdata) || |
524 | (sta->plid && sta->plid != plid)) | 532 | (sta->plid && sta->plid != plid)) |
525 | event = OPN_IGNR; | 533 | event = OPN_IGNR; |
526 | else | 534 | else |
527 | event = OPN_ACPT; | 535 | event = OPN_ACPT; |
528 | break; | 536 | break; |
529 | case PLINK_CONFIRM: | 537 | case PLINK_CONFIRM: |
530 | if (!mesh_plink_free_count(sdata) || | 538 | if (!mesh_plink_free_count(sdata) || |
531 | (sta->llid != llid || sta->plid != plid)) | 539 | (sta->llid != llid || sta->plid != plid)) |
532 | event = CNF_IGNR; | 540 | event = CNF_IGNR; |
533 | else | 541 | else |
534 | event = CNF_ACPT; | 542 | event = CNF_ACPT; |
@@ -555,7 +563,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
555 | default: | 563 | default: |
556 | mpl_dbg("Mesh plink: unknown frame subtype\n"); | 564 | mpl_dbg("Mesh plink: unknown frame subtype\n"); |
557 | spin_unlock_bh(&sta->plink_lock); | 565 | spin_unlock_bh(&sta->plink_lock); |
558 | sta_info_put(sta); | 566 | rcu_read_unlock(); |
559 | return; | 567 | return; |
560 | } | 568 | } |
561 | } | 569 | } |
@@ -659,8 +667,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
659 | plid, 0); | 667 | plid, 0); |
660 | break; | 668 | break; |
661 | case CNF_ACPT: | 669 | case CNF_ACPT: |
662 | if (del_timer(&sta->plink_timer)) | 670 | del_timer(&sta->plink_timer); |
663 | sta_info_put(sta); | ||
664 | sta->plink_state = ESTAB; | 671 | sta->plink_state = ESTAB; |
665 | mesh_plink_inc_estab_count(sdata); | 672 | mesh_plink_inc_estab_count(sdata); |
666 | spin_unlock_bh(&sta->plink_lock); | 673 | spin_unlock_bh(&sta->plink_lock); |
@@ -693,8 +700,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
693 | plid, reason); | 700 | plid, reason); |
694 | break; | 701 | break; |
695 | case OPN_ACPT: | 702 | case OPN_ACPT: |
696 | if (del_timer(&sta->plink_timer)) | 703 | del_timer(&sta->plink_timer); |
697 | sta_info_put(sta); | ||
698 | sta->plink_state = ESTAB; | 704 | sta->plink_state = ESTAB; |
699 | mesh_plink_inc_estab_count(sdata); | 705 | mesh_plink_inc_estab_count(sdata); |
700 | spin_unlock_bh(&sta->plink_lock); | 706 | spin_unlock_bh(&sta->plink_lock); |
@@ -717,9 +723,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
717 | __mesh_plink_deactivate(sta); | 723 | __mesh_plink_deactivate(sta); |
718 | sta->plink_state = HOLDING; | 724 | sta->plink_state = HOLDING; |
719 | llid = sta->llid; | 725 | llid = sta->llid; |
720 | if (!mod_plink_timer(sta, | 726 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
721 | dot11MeshHoldingTimeout(sdata))) | ||
722 | __sta_info_get(sta); | ||
723 | spin_unlock_bh(&sta->plink_lock); | 727 | spin_unlock_bh(&sta->plink_lock); |
724 | mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, | 728 | mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, |
725 | plid, reason); | 729 | plid, reason); |
@@ -738,10 +742,8 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
738 | case HOLDING: | 742 | case HOLDING: |
739 | switch (event) { | 743 | switch (event) { |
740 | case CLS_ACPT: | 744 | case CLS_ACPT: |
741 | if (del_timer(&sta->plink_timer)) { | 745 | if (del_timer(&sta->plink_timer)) |
742 | sta->ignore_plink_timer = 1; | 746 | sta->ignore_plink_timer = 1; |
743 | sta_info_put(sta); | ||
744 | } | ||
745 | mesh_plink_fsm_restart(sta); | 747 | mesh_plink_fsm_restart(sta); |
746 | spin_unlock_bh(&sta->plink_lock); | 748 | spin_unlock_bh(&sta->plink_lock); |
747 | break; | 749 | break; |
@@ -766,5 +768,6 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, | |||
766 | spin_unlock_bh(&sta->plink_lock); | 768 | spin_unlock_bh(&sta->plink_lock); |
767 | break; | 769 | break; |
768 | } | 770 | } |
769 | sta_info_put(sta); | 771 | |
772 | rcu_read_unlock(); | ||
770 | } | 773 | } |