diff options
-rw-r--r-- | net/mac80211/mlme.c | 59 | ||||
-rw-r--r-- | net/mac80211/rx.c | 21 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 186 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 30 |
4 files changed, 236 insertions, 60 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d6470c7fd6ce..60a6f273cd30 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1482,10 +1482,14 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1482 | 1482 | ||
1483 | ifmgd->aid = aid; | 1483 | ifmgd->aid = aid; |
1484 | 1484 | ||
1485 | sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL); | 1485 | mutex_lock(&sdata->local->sta_mtx); |
1486 | if (!sta) { | 1486 | /* |
1487 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" | 1487 | * station info was already allocated and inserted before |
1488 | " the AP\n", sdata->name); | 1488 | * the association and should be available to us |
1489 | */ | ||
1490 | sta = sta_info_get_rx(sdata, cbss->bssid); | ||
1491 | if (WARN_ON(!sta)) { | ||
1492 | mutex_unlock(&sdata->local->sta_mtx); | ||
1489 | return false; | 1493 | return false; |
1490 | } | 1494 | } |
1491 | 1495 | ||
@@ -1556,7 +1560,8 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1556 | if (elems.wmm_param) | 1560 | if (elems.wmm_param) |
1557 | set_sta_flags(sta, WLAN_STA_WME); | 1561 | set_sta_flags(sta, WLAN_STA_WME); |
1558 | 1562 | ||
1559 | err = sta_info_insert(sta); | 1563 | /* sta_info_reinsert will also unlock the mutex lock */ |
1564 | err = sta_info_reinsert(sta); | ||
1560 | sta = NULL; | 1565 | sta = NULL; |
1561 | if (err) { | 1566 | if (err) { |
1562 | printk(KERN_DEBUG "%s: failed to insert STA entry for" | 1567 | printk(KERN_DEBUG "%s: failed to insert STA entry for" |
@@ -2429,6 +2434,32 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
2429 | return 0; | 2434 | return 0; |
2430 | } | 2435 | } |
2431 | 2436 | ||
2437 | /* create and insert a dummy station entry */ | ||
2438 | static int ieee80211_pre_assoc(struct ieee80211_sub_if_data *sdata, | ||
2439 | u8 *bssid) { | ||
2440 | struct sta_info *sta; | ||
2441 | int err; | ||
2442 | |||
2443 | sta = sta_info_alloc(sdata, bssid, GFP_KERNEL); | ||
2444 | if (!sta) { | ||
2445 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" | ||
2446 | " the AP\n", sdata->name); | ||
2447 | return -ENOMEM; | ||
2448 | } | ||
2449 | |||
2450 | sta->dummy = true; | ||
2451 | |||
2452 | err = sta_info_insert(sta); | ||
2453 | sta = NULL; | ||
2454 | if (err) { | ||
2455 | printk(KERN_DEBUG "%s: failed to insert Dummy STA entry for" | ||
2456 | " the AP (error %d)\n", sdata->name, err); | ||
2457 | return err; | ||
2458 | } | ||
2459 | |||
2460 | return 0; | ||
2461 | } | ||
2462 | |||
2432 | static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | 2463 | static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, |
2433 | struct sk_buff *skb) | 2464 | struct sk_buff *skb) |
2434 | { | 2465 | { |
@@ -2436,9 +2467,11 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | |||
2436 | struct ieee80211_mgmt *mgmt; | 2467 | struct ieee80211_mgmt *mgmt; |
2437 | struct ieee80211_rx_status *rx_status; | 2468 | struct ieee80211_rx_status *rx_status; |
2438 | struct ieee802_11_elems elems; | 2469 | struct ieee802_11_elems elems; |
2470 | struct cfg80211_bss *cbss = wk->assoc.bss; | ||
2439 | u16 status; | 2471 | u16 status; |
2440 | 2472 | ||
2441 | if (!skb) { | 2473 | if (!skb) { |
2474 | sta_info_destroy_addr(wk->sdata, cbss->bssid); | ||
2442 | cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); | 2475 | cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); |
2443 | goto destroy; | 2476 | goto destroy; |
2444 | } | 2477 | } |
@@ -2468,12 +2501,16 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | |||
2468 | if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { | 2501 | if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { |
2469 | mutex_unlock(&wk->sdata->u.mgd.mtx); | 2502 | mutex_unlock(&wk->sdata->u.mgd.mtx); |
2470 | /* oops -- internal error -- send timeout for now */ | 2503 | /* oops -- internal error -- send timeout for now */ |
2504 | sta_info_destroy_addr(wk->sdata, cbss->bssid); | ||
2471 | cfg80211_send_assoc_timeout(wk->sdata->dev, | 2505 | cfg80211_send_assoc_timeout(wk->sdata->dev, |
2472 | wk->filter_ta); | 2506 | wk->filter_ta); |
2473 | return WORK_DONE_DESTROY; | 2507 | return WORK_DONE_DESTROY; |
2474 | } | 2508 | } |
2475 | 2509 | ||
2476 | mutex_unlock(&wk->sdata->u.mgd.mtx); | 2510 | mutex_unlock(&wk->sdata->u.mgd.mtx); |
2511 | } else { | ||
2512 | /* assoc failed - destroy the dummy station entry */ | ||
2513 | sta_info_destroy_addr(wk->sdata, cbss->bssid); | ||
2477 | } | 2514 | } |
2478 | 2515 | ||
2479 | cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); | 2516 | cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); |
@@ -2492,7 +2529,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2492 | struct ieee80211_bss *bss = (void *)req->bss->priv; | 2529 | struct ieee80211_bss *bss = (void *)req->bss->priv; |
2493 | struct ieee80211_work *wk; | 2530 | struct ieee80211_work *wk; |
2494 | const u8 *ssid; | 2531 | const u8 *ssid; |
2495 | int i; | 2532 | int i, err; |
2496 | 2533 | ||
2497 | mutex_lock(&ifmgd->mtx); | 2534 | mutex_lock(&ifmgd->mtx); |
2498 | if (ifmgd->associated) { | 2535 | if (ifmgd->associated) { |
@@ -2517,6 +2554,16 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2517 | if (!wk) | 2554 | if (!wk) |
2518 | return -ENOMEM; | 2555 | return -ENOMEM; |
2519 | 2556 | ||
2557 | /* | ||
2558 | * create a dummy station info entry in order | ||
2559 | * to start accepting incoming EAPOL packets from the station | ||
2560 | */ | ||
2561 | err = ieee80211_pre_assoc(sdata, req->bss->bssid); | ||
2562 | if (err) { | ||
2563 | kfree(wk); | ||
2564 | return err; | ||
2565 | } | ||
2566 | |||
2520 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; | 2567 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; |
2521 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | 2568 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; |
2522 | 2569 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c4453fdd6e11..edd46193af6f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -850,8 +850,21 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
850 | ieee80211_is_pspoll(hdr->frame_control)) && | 850 | ieee80211_is_pspoll(hdr->frame_control)) && |
851 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && | 851 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && |
852 | rx->sdata->vif.type != NL80211_IFTYPE_WDS && | 852 | rx->sdata->vif.type != NL80211_IFTYPE_WDS && |
853 | (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) | 853 | (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) { |
854 | if (rx->sta && rx->sta->dummy && | ||
855 | ieee80211_is_data_present(hdr->frame_control)) { | ||
856 | u16 ethertype; | ||
857 | u8 *payload; | ||
858 | |||
859 | payload = rx->skb->data + | ||
860 | ieee80211_hdrlen(hdr->frame_control); | ||
861 | ethertype = (payload[6] << 8) | payload[7]; | ||
862 | if (cpu_to_be16(ethertype) == | ||
863 | rx->sdata->control_port_protocol) | ||
864 | return RX_CONTINUE; | ||
865 | } | ||
854 | return RX_DROP_MONITOR; | 866 | return RX_DROP_MONITOR; |
867 | } | ||
855 | 868 | ||
856 | return RX_CONTINUE; | 869 | return RX_CONTINUE; |
857 | } | 870 | } |
@@ -2808,7 +2821,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2808 | if (ieee80211_is_data(fc)) { | 2821 | if (ieee80211_is_data(fc)) { |
2809 | prev_sta = NULL; | 2822 | prev_sta = NULL; |
2810 | 2823 | ||
2811 | for_each_sta_info(local, hdr->addr2, sta, tmp) { | 2824 | for_each_sta_info_rx(local, hdr->addr2, sta, tmp) { |
2812 | if (!prev_sta) { | 2825 | if (!prev_sta) { |
2813 | prev_sta = sta; | 2826 | prev_sta = sta; |
2814 | continue; | 2827 | continue; |
@@ -2852,7 +2865,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2852 | continue; | 2865 | continue; |
2853 | } | 2866 | } |
2854 | 2867 | ||
2855 | rx.sta = sta_info_get_bss(prev, hdr->addr2); | 2868 | rx.sta = sta_info_get_bss_rx(prev, hdr->addr2); |
2856 | rx.sdata = prev; | 2869 | rx.sdata = prev; |
2857 | ieee80211_prepare_and_rx_handle(&rx, skb, false); | 2870 | ieee80211_prepare_and_rx_handle(&rx, skb, false); |
2858 | 2871 | ||
@@ -2860,7 +2873,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2860 | } | 2873 | } |
2861 | 2874 | ||
2862 | if (prev) { | 2875 | if (prev) { |
2863 | rx.sta = sta_info_get_bss(prev, hdr->addr2); | 2876 | rx.sta = sta_info_get_bss_rx(prev, hdr->addr2); |
2864 | rx.sdata = prev; | 2877 | rx.sdata = prev; |
2865 | 2878 | ||
2866 | if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) | 2879 | if (ieee80211_prepare_and_rx_handle(&rx, skb, true)) |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index d469d9d2b499..17caba27040b 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -100,6 +100,27 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, | |||
100 | lockdep_is_held(&local->sta_lock) || | 100 | lockdep_is_held(&local->sta_lock) || |
101 | lockdep_is_held(&local->sta_mtx)); | 101 | lockdep_is_held(&local->sta_mtx)); |
102 | while (sta) { | 102 | while (sta) { |
103 | if (sta->sdata == sdata && !sta->dummy && | ||
104 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | ||
105 | break; | ||
106 | sta = rcu_dereference_check(sta->hnext, | ||
107 | lockdep_is_held(&local->sta_lock) || | ||
108 | lockdep_is_held(&local->sta_mtx)); | ||
109 | } | ||
110 | return sta; | ||
111 | } | ||
112 | |||
113 | /* get a station info entry even if it is a dummy station*/ | ||
114 | struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata, | ||
115 | const u8 *addr) | ||
116 | { | ||
117 | struct ieee80211_local *local = sdata->local; | ||
118 | struct sta_info *sta; | ||
119 | |||
120 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], | ||
121 | lockdep_is_held(&local->sta_lock) || | ||
122 | lockdep_is_held(&local->sta_mtx)); | ||
123 | while (sta) { | ||
103 | if (sta->sdata == sdata && | 124 | if (sta->sdata == sdata && |
104 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | 125 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) |
105 | break; | 126 | break; |
@@ -126,6 +147,32 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, | |||
126 | while (sta) { | 147 | while (sta) { |
127 | if ((sta->sdata == sdata || | 148 | if ((sta->sdata == sdata || |
128 | (sta->sdata->bss && sta->sdata->bss == sdata->bss)) && | 149 | (sta->sdata->bss && sta->sdata->bss == sdata->bss)) && |
150 | !sta->dummy && | ||
151 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | ||
152 | break; | ||
153 | sta = rcu_dereference_check(sta->hnext, | ||
154 | lockdep_is_held(&local->sta_lock) || | ||
155 | lockdep_is_held(&local->sta_mtx)); | ||
156 | } | ||
157 | return sta; | ||
158 | } | ||
159 | |||
160 | /* | ||
161 | * Get sta info either from the specified interface | ||
162 | * or from one of its vlans (including dummy stations) | ||
163 | */ | ||
164 | struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata, | ||
165 | const u8 *addr) | ||
166 | { | ||
167 | struct ieee80211_local *local = sdata->local; | ||
168 | struct sta_info *sta; | ||
169 | |||
170 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], | ||
171 | lockdep_is_held(&local->sta_lock) || | ||
172 | lockdep_is_held(&local->sta_mtx)); | ||
173 | while (sta) { | ||
174 | if ((sta->sdata == sdata || | ||
175 | (sta->sdata->bss && sta->sdata->bss == sdata->bss)) && | ||
129 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | 176 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) |
130 | break; | 177 | break; |
131 | sta = rcu_dereference_check(sta->hnext, | 178 | sta = rcu_dereference_check(sta->hnext, |
@@ -280,7 +327,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
280 | return sta; | 327 | return sta; |
281 | } | 328 | } |
282 | 329 | ||
283 | static int sta_info_finish_insert(struct sta_info *sta, bool async) | 330 | static int sta_info_finish_insert(struct sta_info *sta, |
331 | bool async, bool dummy_reinsert) | ||
284 | { | 332 | { |
285 | struct ieee80211_local *local = sta->local; | 333 | struct ieee80211_local *local = sta->local; |
286 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 334 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
@@ -290,51 +338,58 @@ static int sta_info_finish_insert(struct sta_info *sta, bool async) | |||
290 | 338 | ||
291 | lockdep_assert_held(&local->sta_mtx); | 339 | lockdep_assert_held(&local->sta_mtx); |
292 | 340 | ||
293 | /* notify driver */ | 341 | if (!sta->dummy || dummy_reinsert) { |
294 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 342 | /* notify driver */ |
295 | sdata = container_of(sdata->bss, | 343 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
296 | struct ieee80211_sub_if_data, | 344 | sdata = container_of(sdata->bss, |
297 | u.ap); | 345 | struct ieee80211_sub_if_data, |
298 | err = drv_sta_add(local, sdata, &sta->sta); | 346 | u.ap); |
299 | if (err) { | 347 | err = drv_sta_add(local, sdata, &sta->sta); |
300 | if (!async) | 348 | if (err) { |
301 | return err; | 349 | if (!async) |
302 | printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to driver (%d)" | 350 | return err; |
303 | " - keeping it anyway.\n", | 351 | printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to " |
304 | sdata->name, sta->sta.addr, err); | 352 | "driver (%d) - keeping it anyway.\n", |
305 | } else { | 353 | sdata->name, sta->sta.addr, err); |
306 | sta->uploaded = true; | 354 | } else { |
355 | sta->uploaded = true; | ||
307 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 356 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
308 | if (async) | 357 | if (async) |
309 | wiphy_debug(local->hw.wiphy, | 358 | wiphy_debug(local->hw.wiphy, |
310 | "Finished adding IBSS STA %pM\n", | 359 | "Finished adding IBSS STA %pM\n", |
311 | sta->sta.addr); | 360 | sta->sta.addr); |
312 | #endif | 361 | #endif |
362 | } | ||
363 | |||
364 | sdata = sta->sdata; | ||
313 | } | 365 | } |
314 | 366 | ||
315 | sdata = sta->sdata; | 367 | if (!dummy_reinsert) { |
368 | if (!async) { | ||
369 | local->num_sta++; | ||
370 | local->sta_generation++; | ||
371 | smp_mb(); | ||
316 | 372 | ||
317 | if (!async) { | 373 | /* make the station visible */ |
318 | local->num_sta++; | 374 | spin_lock_irqsave(&local->sta_lock, flags); |
319 | local->sta_generation++; | 375 | sta_info_hash_add(local, sta); |
320 | smp_mb(); | 376 | spin_unlock_irqrestore(&local->sta_lock, flags); |
377 | } | ||
321 | 378 | ||
322 | /* make the station visible */ | 379 | list_add(&sta->list, &local->sta_list); |
323 | spin_lock_irqsave(&local->sta_lock, flags); | 380 | } else { |
324 | sta_info_hash_add(local, sta); | 381 | sta->dummy = false; |
325 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
326 | } | 382 | } |
327 | 383 | ||
328 | list_add(&sta->list, &local->sta_list); | 384 | if (!sta->dummy) { |
329 | 385 | ieee80211_sta_debugfs_add(sta); | |
330 | ieee80211_sta_debugfs_add(sta); | 386 | rate_control_add_sta_debugfs(sta); |
331 | rate_control_add_sta_debugfs(sta); | ||
332 | |||
333 | memset(&sinfo, 0, sizeof(sinfo)); | ||
334 | sinfo.filled = 0; | ||
335 | sinfo.generation = local->sta_generation; | ||
336 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); | ||
337 | 387 | ||
388 | memset(&sinfo, 0, sizeof(sinfo)); | ||
389 | sinfo.filled = 0; | ||
390 | sinfo.generation = local->sta_generation; | ||
391 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); | ||
392 | } | ||
338 | 393 | ||
339 | return 0; | 394 | return 0; |
340 | } | 395 | } |
@@ -351,7 +406,7 @@ static void sta_info_finish_pending(struct ieee80211_local *local) | |||
351 | list_del(&sta->list); | 406 | list_del(&sta->list); |
352 | spin_unlock_irqrestore(&local->sta_lock, flags); | 407 | spin_unlock_irqrestore(&local->sta_lock, flags); |
353 | 408 | ||
354 | sta_info_finish_insert(sta, true); | 409 | sta_info_finish_insert(sta, true, false); |
355 | 410 | ||
356 | spin_lock_irqsave(&local->sta_lock, flags); | 411 | spin_lock_irqsave(&local->sta_lock, flags); |
357 | } | 412 | } |
@@ -395,7 +450,7 @@ static int sta_info_insert_ibss(struct sta_info *sta) __acquires(RCU) | |||
395 | 450 | ||
396 | spin_lock_irqsave(&local->sta_lock, flags); | 451 | spin_lock_irqsave(&local->sta_lock, flags); |
397 | /* check if STA exists already */ | 452 | /* check if STA exists already */ |
398 | if (sta_info_get_bss(sdata, sta->sta.addr)) { | 453 | if (sta_info_get_bss_rx(sdata, sta->sta.addr)) { |
399 | spin_unlock_irqrestore(&local->sta_lock, flags); | 454 | spin_unlock_irqrestore(&local->sta_lock, flags); |
400 | rcu_read_lock(); | 455 | rcu_read_lock(); |
401 | return -EEXIST; | 456 | return -EEXIST; |
@@ -431,6 +486,8 @@ static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU) | |||
431 | struct ieee80211_local *local = sta->local; | 486 | struct ieee80211_local *local = sta->local; |
432 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 487 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
433 | unsigned long flags; | 488 | unsigned long flags; |
489 | struct sta_info *exist_sta; | ||
490 | bool dummy_reinsert = false; | ||
434 | int err = 0; | 491 | int err = 0; |
435 | 492 | ||
436 | lockdep_assert_held(&local->sta_mtx); | 493 | lockdep_assert_held(&local->sta_mtx); |
@@ -446,17 +503,28 @@ static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU) | |||
446 | */ | 503 | */ |
447 | 504 | ||
448 | spin_lock_irqsave(&local->sta_lock, flags); | 505 | spin_lock_irqsave(&local->sta_lock, flags); |
449 | /* check if STA exists already */ | 506 | /* |
450 | if (sta_info_get_bss(sdata, sta->sta.addr)) { | 507 | * check if STA exists already. |
451 | spin_unlock_irqrestore(&local->sta_lock, flags); | 508 | * only accept a scenario of a second call to sta_info_insert_non_ibss |
452 | mutex_unlock(&local->sta_mtx); | 509 | * with a dummy station entry that was inserted earlier |
453 | rcu_read_lock(); | 510 | * in that case - assume that the dummy station flag should |
454 | return -EEXIST; | 511 | * be removed. |
512 | */ | ||
513 | exist_sta = sta_info_get_bss_rx(sdata, sta->sta.addr); | ||
514 | if (exist_sta) { | ||
515 | if (exist_sta == sta && sta->dummy) { | ||
516 | dummy_reinsert = true; | ||
517 | } else { | ||
518 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
519 | mutex_unlock(&local->sta_mtx); | ||
520 | rcu_read_lock(); | ||
521 | return -EEXIST; | ||
522 | } | ||
455 | } | 523 | } |
456 | 524 | ||
457 | spin_unlock_irqrestore(&local->sta_lock, flags); | 525 | spin_unlock_irqrestore(&local->sta_lock, flags); |
458 | 526 | ||
459 | err = sta_info_finish_insert(sta, false); | 527 | err = sta_info_finish_insert(sta, false, dummy_reinsert); |
460 | if (err) { | 528 | if (err) { |
461 | mutex_unlock(&local->sta_mtx); | 529 | mutex_unlock(&local->sta_mtx); |
462 | rcu_read_lock(); | 530 | rcu_read_lock(); |
@@ -464,7 +532,8 @@ static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU) | |||
464 | } | 532 | } |
465 | 533 | ||
466 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 534 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
467 | wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr); | 535 | wiphy_debug(local->hw.wiphy, "Inserted %sSTA %pM\n", |
536 | sta->dummy ? "dummy " : "", sta->sta.addr); | ||
468 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 537 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
469 | 538 | ||
470 | /* move reference to rcu-protected */ | 539 | /* move reference to rcu-protected */ |
@@ -535,6 +604,25 @@ int sta_info_insert(struct sta_info *sta) | |||
535 | return err; | 604 | return err; |
536 | } | 605 | } |
537 | 606 | ||
607 | /* Caller must hold sta->local->sta_mtx */ | ||
608 | int sta_info_reinsert(struct sta_info *sta) | ||
609 | { | ||
610 | struct ieee80211_local *local = sta->local; | ||
611 | int err = 0; | ||
612 | |||
613 | err = sta_info_insert_check(sta); | ||
614 | if (err) { | ||
615 | mutex_unlock(&local->sta_mtx); | ||
616 | return err; | ||
617 | } | ||
618 | |||
619 | might_sleep(); | ||
620 | |||
621 | err = sta_info_insert_non_ibss(sta); | ||
622 | rcu_read_unlock(); | ||
623 | return err; | ||
624 | } | ||
625 | |||
538 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) | 626 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) |
539 | { | 627 | { |
540 | /* | 628 | /* |
@@ -775,7 +863,7 @@ int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr) | |||
775 | int ret; | 863 | int ret; |
776 | 864 | ||
777 | mutex_lock(&sdata->local->sta_mtx); | 865 | mutex_lock(&sdata->local->sta_mtx); |
778 | sta = sta_info_get(sdata, addr); | 866 | sta = sta_info_get_rx(sdata, addr); |
779 | ret = __sta_info_destroy(sta); | 867 | ret = __sta_info_destroy(sta); |
780 | mutex_unlock(&sdata->local->sta_mtx); | 868 | mutex_unlock(&sdata->local->sta_mtx); |
781 | 869 | ||
@@ -789,7 +877,7 @@ int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, | |||
789 | int ret; | 877 | int ret; |
790 | 878 | ||
791 | mutex_lock(&sdata->local->sta_mtx); | 879 | mutex_lock(&sdata->local->sta_mtx); |
792 | sta = sta_info_get_bss(sdata, addr); | 880 | sta = sta_info_get_bss_rx(sdata, addr); |
793 | ret = __sta_info_destroy(sta); | 881 | ret = __sta_info_destroy(sta); |
794 | mutex_unlock(&sdata->local->sta_mtx); | 882 | mutex_unlock(&sdata->local->sta_mtx); |
795 | 883 | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 28beb78e601e..e9eb565506da 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -238,10 +238,12 @@ struct sta_ampdu_mlme { | |||
238 | * @plink_timer: peer link watch timer | 238 | * @plink_timer: peer link watch timer |
239 | * @plink_timer_was_running: used by suspend/resume to restore timers | 239 | * @plink_timer_was_running: used by suspend/resume to restore timers |
240 | * @debugfs: debug filesystem info | 240 | * @debugfs: debug filesystem info |
241 | * @sta: station information we share with the driver | ||
242 | * @dead: set to true when sta is unlinked | 241 | * @dead: set to true when sta is unlinked |
243 | * @uploaded: set to true when sta is uploaded to the driver | 242 | * @uploaded: set to true when sta is uploaded to the driver |
244 | * @lost_packets: number of consecutive lost packets | 243 | * @lost_packets: number of consecutive lost packets |
244 | * @dummy: indicate a dummy station created for receiving | ||
245 | * EAP frames before association | ||
246 | * @sta: station information we share with the driver | ||
245 | */ | 247 | */ |
246 | struct sta_info { | 248 | struct sta_info { |
247 | /* General information, mostly static */ | 249 | /* General information, mostly static */ |
@@ -336,6 +338,9 @@ struct sta_info { | |||
336 | 338 | ||
337 | unsigned int lost_packets; | 339 | unsigned int lost_packets; |
338 | 340 | ||
341 | /* should be right in front of sta to be in the same cache line */ | ||
342 | bool dummy; | ||
343 | |||
339 | /* keep last! */ | 344 | /* keep last! */ |
340 | struct ieee80211_sta sta; | 345 | struct ieee80211_sta sta; |
341 | }; | 346 | }; |
@@ -436,9 +441,15 @@ rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid) | |||
436 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, | 441 | struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, |
437 | const u8 *addr); | 442 | const u8 *addr); |
438 | 443 | ||
444 | struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata, | ||
445 | const u8 *addr); | ||
446 | |||
439 | struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, | 447 | struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, |
440 | const u8 *addr); | 448 | const u8 *addr); |
441 | 449 | ||
450 | struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata, | ||
451 | const u8 *addr); | ||
452 | |||
442 | static inline | 453 | static inline |
443 | void for_each_sta_info_type_check(struct ieee80211_local *local, | 454 | void for_each_sta_info_type_check(struct ieee80211_local *local, |
444 | const u8 *addr, | 455 | const u8 *addr, |
@@ -459,6 +470,22 @@ void for_each_sta_info_type_check(struct ieee80211_local *local, | |||
459 | _sta = nxt, \ | 470 | _sta = nxt, \ |
460 | nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \ | 471 | nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \ |
461 | ) \ | 472 | ) \ |
473 | /* run code only if address matches and it's not a dummy sta */ \ | ||
474 | if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0 && \ | ||
475 | !_sta->dummy) | ||
476 | |||
477 | #define for_each_sta_info_rx(local, _addr, _sta, nxt) \ | ||
478 | for ( /* initialise loop */ \ | ||
479 | _sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\ | ||
480 | nxt = _sta ? rcu_dereference(_sta->hnext) : NULL; \ | ||
481 | /* typecheck */ \ | ||
482 | for_each_sta_info_type_check(local, (_addr), _sta, nxt),\ | ||
483 | /* continue condition */ \ | ||
484 | _sta; \ | ||
485 | /* advance loop */ \ | ||
486 | _sta = nxt, \ | ||
487 | nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \ | ||
488 | ) \ | ||
462 | /* compare address and run code only if it matches */ \ | 489 | /* compare address and run code only if it matches */ \ |
463 | if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0) | 490 | if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0) |
464 | 491 | ||
@@ -484,6 +511,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
484 | int sta_info_insert(struct sta_info *sta); | 511 | int sta_info_insert(struct sta_info *sta); |
485 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU); | 512 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU); |
486 | int sta_info_insert_atomic(struct sta_info *sta); | 513 | int sta_info_insert_atomic(struct sta_info *sta); |
514 | int sta_info_reinsert(struct sta_info *sta); | ||
487 | 515 | ||
488 | int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, | 516 | int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, |
489 | const u8 *addr); | 517 | const u8 *addr); |