diff options
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r-- | net/mac80211/sta_info.c | 186 |
1 files changed, 137 insertions, 49 deletions
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 | ||