diff options
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r-- | net/mac80211/sta_info.c | 252 |
1 files changed, 116 insertions, 136 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index fa0823892b2d..4034ee616022 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -100,25 +100,6 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, | |||
100 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], | 100 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], |
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_mtx)); | ||
108 | } | ||
109 | return sta; | ||
110 | } | ||
111 | |||
112 | /* get a station info entry even if it is a dummy station*/ | ||
113 | struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata, | ||
114 | const u8 *addr) | ||
115 | { | ||
116 | struct ieee80211_local *local = sdata->local; | ||
117 | struct sta_info *sta; | ||
118 | |||
119 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], | ||
120 | lockdep_is_held(&local->sta_mtx)); | ||
121 | while (sta) { | ||
122 | if (sta->sdata == sdata && | 103 | if (sta->sdata == sdata && |
123 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | 104 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) |
124 | break; | 105 | break; |
@@ -143,30 +124,6 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, | |||
143 | while (sta) { | 124 | while (sta) { |
144 | if ((sta->sdata == sdata || | 125 | if ((sta->sdata == sdata || |
145 | (sta->sdata->bss && sta->sdata->bss == sdata->bss)) && | 126 | (sta->sdata->bss && sta->sdata->bss == sdata->bss)) && |
146 | !sta->dummy && | ||
147 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | ||
148 | break; | ||
149 | sta = rcu_dereference_check(sta->hnext, | ||
150 | lockdep_is_held(&local->sta_mtx)); | ||
151 | } | ||
152 | return sta; | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * Get sta info either from the specified interface | ||
157 | * or from one of its vlans (including dummy stations) | ||
158 | */ | ||
159 | struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata, | ||
160 | const u8 *addr) | ||
161 | { | ||
162 | struct ieee80211_local *local = sdata->local; | ||
163 | struct sta_info *sta; | ||
164 | |||
165 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], | ||
166 | lockdep_is_held(&local->sta_mtx)); | ||
167 | while (sta) { | ||
168 | if ((sta->sdata == sdata || | ||
169 | (sta->sdata->bss && sta->sdata->bss == sdata->bss)) && | ||
170 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | 127 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) |
171 | break; | 128 | break; |
172 | sta = rcu_dereference_check(sta->hnext, | 129 | sta = rcu_dereference_check(sta->hnext, |
@@ -293,6 +250,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
293 | sta->sdata = sdata; | 250 | sta->sdata = sdata; |
294 | sta->last_rx = jiffies; | 251 | sta->last_rx = jiffies; |
295 | 252 | ||
253 | sta->sta_state = IEEE80211_STA_NONE; | ||
254 | |||
296 | do_posix_clock_monotonic_gettime(&uptime); | 255 | do_posix_clock_monotonic_gettime(&uptime); |
297 | sta->last_connected = uptime.tv_sec; | 256 | sta->last_connected = uptime.tv_sec; |
298 | ewma_init(&sta->avg_signal, 1024, 8); | 257 | ewma_init(&sta->avg_signal, 1024, 8); |
@@ -349,6 +308,43 @@ static int sta_info_insert_check(struct sta_info *sta) | |||
349 | return 0; | 308 | return 0; |
350 | } | 309 | } |
351 | 310 | ||
311 | static int sta_info_insert_drv_state(struct ieee80211_local *local, | ||
312 | struct ieee80211_sub_if_data *sdata, | ||
313 | struct sta_info *sta) | ||
314 | { | ||
315 | enum ieee80211_sta_state state; | ||
316 | int err = 0; | ||
317 | |||
318 | for (state = IEEE80211_STA_NOTEXIST; state < sta->sta_state; state++) { | ||
319 | err = drv_sta_state(local, sdata, sta, state, state + 1); | ||
320 | if (err) | ||
321 | break; | ||
322 | } | ||
323 | |||
324 | if (!err) { | ||
325 | /* | ||
326 | * Drivers using legacy sta_add/sta_remove callbacks only | ||
327 | * get uploaded set to true after sta_add is called. | ||
328 | */ | ||
329 | if (!local->ops->sta_add) | ||
330 | sta->uploaded = true; | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
335 | printk(KERN_DEBUG | ||
336 | "%s: failed to move IBSS STA %pM to state %d (%d) - keeping it anyway.\n", | ||
337 | sdata->name, sta->sta.addr, state + 1, err); | ||
338 | err = 0; | ||
339 | } | ||
340 | |||
341 | /* unwind on error */ | ||
342 | for (; state > IEEE80211_STA_NOTEXIST; state--) | ||
343 | WARN_ON(drv_sta_state(local, sdata, sta, state, state - 1)); | ||
344 | |||
345 | return err; | ||
346 | } | ||
347 | |||
352 | /* | 348 | /* |
353 | * should be called with sta_mtx locked | 349 | * should be called with sta_mtx locked |
354 | * this function replaces the mutex lock | 350 | * this function replaces the mutex lock |
@@ -358,72 +354,43 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) | |||
358 | { | 354 | { |
359 | struct ieee80211_local *local = sta->local; | 355 | struct ieee80211_local *local = sta->local; |
360 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 356 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
361 | struct sta_info *exist_sta; | 357 | struct station_info sinfo; |
362 | bool dummy_reinsert = false; | ||
363 | int err = 0; | 358 | int err = 0; |
364 | 359 | ||
365 | lockdep_assert_held(&local->sta_mtx); | 360 | lockdep_assert_held(&local->sta_mtx); |
366 | 361 | ||
367 | /* | 362 | /* check if STA exists already */ |
368 | * check if STA exists already. | 363 | if (sta_info_get_bss(sdata, sta->sta.addr)) { |
369 | * only accept a scenario of a second call to sta_info_insert_finish | 364 | err = -EEXIST; |
370 | * with a dummy station entry that was inserted earlier | 365 | goto out_err; |
371 | * in that case - assume that the dummy station flag should | ||
372 | * be removed. | ||
373 | */ | ||
374 | exist_sta = sta_info_get_bss_rx(sdata, sta->sta.addr); | ||
375 | if (exist_sta) { | ||
376 | if (exist_sta == sta && sta->dummy) { | ||
377 | dummy_reinsert = true; | ||
378 | } else { | ||
379 | err = -EEXIST; | ||
380 | goto out_err; | ||
381 | } | ||
382 | } | ||
383 | |||
384 | if (!sta->dummy || dummy_reinsert) { | ||
385 | /* notify driver */ | ||
386 | err = drv_sta_add(local, sdata, &sta->sta); | ||
387 | if (err) { | ||
388 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
389 | goto out_err; | ||
390 | printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to " | ||
391 | "driver (%d) - keeping it anyway.\n", | ||
392 | sdata->name, sta->sta.addr, err); | ||
393 | } else | ||
394 | sta->uploaded = true; | ||
395 | } | 366 | } |
396 | 367 | ||
397 | if (!dummy_reinsert) { | 368 | /* notify driver */ |
398 | local->num_sta++; | 369 | err = sta_info_insert_drv_state(local, sdata, sta); |
399 | local->sta_generation++; | 370 | if (err) |
400 | smp_mb(); | 371 | goto out_err; |
401 | 372 | ||
402 | /* make the station visible */ | 373 | local->num_sta++; |
403 | sta_info_hash_add(local, sta); | 374 | local->sta_generation++; |
375 | smp_mb(); | ||
404 | 376 | ||
405 | list_add(&sta->list, &local->sta_list); | 377 | /* make the station visible */ |
378 | sta_info_hash_add(local, sta); | ||
406 | 379 | ||
407 | set_sta_flag(sta, WLAN_STA_INSERTED); | 380 | list_add(&sta->list, &local->sta_list); |
408 | } else { | ||
409 | sta->dummy = false; | ||
410 | } | ||
411 | 381 | ||
412 | if (!sta->dummy) { | 382 | set_sta_flag(sta, WLAN_STA_INSERTED); |
413 | struct station_info sinfo; | ||
414 | 383 | ||
415 | ieee80211_sta_debugfs_add(sta); | 384 | ieee80211_sta_debugfs_add(sta); |
416 | rate_control_add_sta_debugfs(sta); | 385 | rate_control_add_sta_debugfs(sta); |
417 | 386 | ||
418 | memset(&sinfo, 0, sizeof(sinfo)); | 387 | memset(&sinfo, 0, sizeof(sinfo)); |
419 | sinfo.filled = 0; | 388 | sinfo.filled = 0; |
420 | sinfo.generation = local->sta_generation; | 389 | sinfo.generation = local->sta_generation; |
421 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); | 390 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); |
422 | } | ||
423 | 391 | ||
424 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 392 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
425 | wiphy_debug(local->hw.wiphy, "Inserted %sSTA %pM\n", | 393 | wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr); |
426 | sta->dummy ? "dummy " : "", sta->sta.addr); | ||
427 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 394 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
428 | 395 | ||
429 | /* move reference to rcu-protected */ | 396 | /* move reference to rcu-protected */ |
@@ -475,25 +442,6 @@ int sta_info_insert(struct sta_info *sta) | |||
475 | return err; | 442 | return err; |
476 | } | 443 | } |
477 | 444 | ||
478 | /* Caller must hold sta->local->sta_mtx */ | ||
479 | int sta_info_reinsert(struct sta_info *sta) | ||
480 | { | ||
481 | struct ieee80211_local *local = sta->local; | ||
482 | int err = 0; | ||
483 | |||
484 | err = sta_info_insert_check(sta); | ||
485 | if (err) { | ||
486 | mutex_unlock(&local->sta_mtx); | ||
487 | return err; | ||
488 | } | ||
489 | |||
490 | might_sleep(); | ||
491 | |||
492 | err = sta_info_insert_finish(sta); | ||
493 | rcu_read_unlock(); | ||
494 | return err; | ||
495 | } | ||
496 | |||
497 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) | 445 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) |
498 | { | 446 | { |
499 | /* | 447 | /* |
@@ -757,20 +705,17 @@ int __must_check __sta_info_destroy(struct sta_info *sta) | |||
757 | RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); | 705 | RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); |
758 | 706 | ||
759 | while (sta->sta_state > IEEE80211_STA_NONE) { | 707 | while (sta->sta_state > IEEE80211_STA_NONE) { |
760 | int err = sta_info_move_state(sta, sta->sta_state - 1); | 708 | ret = sta_info_move_state(sta, sta->sta_state - 1); |
761 | if (err) { | 709 | if (ret) { |
762 | WARN_ON_ONCE(1); | 710 | WARN_ON_ONCE(1); |
763 | break; | 711 | break; |
764 | } | 712 | } |
765 | } | 713 | } |
766 | 714 | ||
767 | if (sta->uploaded) { | 715 | if (sta->uploaded) { |
768 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 716 | ret = drv_sta_state(local, sdata, sta, IEEE80211_STA_NONE, |
769 | sdata = container_of(sdata->bss, | 717 | IEEE80211_STA_NOTEXIST); |
770 | struct ieee80211_sub_if_data, | 718 | WARN_ON_ONCE(ret != 0); |
771 | u.ap); | ||
772 | drv_sta_remove(local, sdata, &sta->sta); | ||
773 | sdata = sta->sdata; | ||
774 | } | 719 | } |
775 | 720 | ||
776 | /* | 721 | /* |
@@ -843,7 +788,7 @@ int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr) | |||
843 | int ret; | 788 | int ret; |
844 | 789 | ||
845 | mutex_lock(&sdata->local->sta_mtx); | 790 | mutex_lock(&sdata->local->sta_mtx); |
846 | sta = sta_info_get_rx(sdata, addr); | 791 | sta = sta_info_get(sdata, addr); |
847 | ret = __sta_info_destroy(sta); | 792 | ret = __sta_info_destroy(sta); |
848 | mutex_unlock(&sdata->local->sta_mtx); | 793 | mutex_unlock(&sdata->local->sta_mtx); |
849 | 794 | ||
@@ -857,7 +802,7 @@ int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, | |||
857 | int ret; | 802 | int ret; |
858 | 803 | ||
859 | mutex_lock(&sdata->local->sta_mtx); | 804 | mutex_lock(&sdata->local->sta_mtx); |
860 | sta = sta_info_get_bss_rx(sdata, addr); | 805 | sta = sta_info_get_bss(sdata, addr); |
861 | ret = __sta_info_destroy(sta); | 806 | ret = __sta_info_destroy(sta); |
862 | mutex_unlock(&sdata->local->sta_mtx); | 807 | mutex_unlock(&sdata->local->sta_mtx); |
863 | 808 | ||
@@ -1408,20 +1353,60 @@ int sta_info_move_state(struct sta_info *sta, | |||
1408 | if (sta->sta_state == new_state) | 1353 | if (sta->sta_state == new_state) |
1409 | return 0; | 1354 | return 0; |
1410 | 1355 | ||
1356 | /* check allowed transitions first */ | ||
1357 | |||
1358 | switch (new_state) { | ||
1359 | case IEEE80211_STA_NONE: | ||
1360 | if (sta->sta_state != IEEE80211_STA_AUTH) | ||
1361 | return -EINVAL; | ||
1362 | break; | ||
1363 | case IEEE80211_STA_AUTH: | ||
1364 | if (sta->sta_state != IEEE80211_STA_NONE && | ||
1365 | sta->sta_state != IEEE80211_STA_ASSOC) | ||
1366 | return -EINVAL; | ||
1367 | break; | ||
1368 | case IEEE80211_STA_ASSOC: | ||
1369 | if (sta->sta_state != IEEE80211_STA_AUTH && | ||
1370 | sta->sta_state != IEEE80211_STA_AUTHORIZED) | ||
1371 | return -EINVAL; | ||
1372 | break; | ||
1373 | case IEEE80211_STA_AUTHORIZED: | ||
1374 | if (sta->sta_state != IEEE80211_STA_ASSOC) | ||
1375 | return -EINVAL; | ||
1376 | break; | ||
1377 | default: | ||
1378 | WARN(1, "invalid state %d", new_state); | ||
1379 | return -EINVAL; | ||
1380 | } | ||
1381 | |||
1382 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
1383 | printk(KERN_DEBUG "%s: moving STA %pM to state %d\n", | ||
1384 | sta->sdata->name, sta->sta.addr, new_state); | ||
1385 | #endif | ||
1386 | |||
1387 | /* | ||
1388 | * notify the driver before the actual changes so it can | ||
1389 | * fail the transition | ||
1390 | */ | ||
1391 | if (test_sta_flag(sta, WLAN_STA_INSERTED)) { | ||
1392 | int err = drv_sta_state(sta->local, sta->sdata, sta, | ||
1393 | sta->sta_state, new_state); | ||
1394 | if (err) | ||
1395 | return err; | ||
1396 | } | ||
1397 | |||
1398 | /* reflect the change in all state variables */ | ||
1399 | |||
1411 | switch (new_state) { | 1400 | switch (new_state) { |
1412 | case IEEE80211_STA_NONE: | 1401 | case IEEE80211_STA_NONE: |
1413 | if (sta->sta_state == IEEE80211_STA_AUTH) | 1402 | if (sta->sta_state == IEEE80211_STA_AUTH) |
1414 | clear_bit(WLAN_STA_AUTH, &sta->_flags); | 1403 | clear_bit(WLAN_STA_AUTH, &sta->_flags); |
1415 | else | ||
1416 | return -EINVAL; | ||
1417 | break; | 1404 | break; |
1418 | case IEEE80211_STA_AUTH: | 1405 | case IEEE80211_STA_AUTH: |
1419 | if (sta->sta_state == IEEE80211_STA_NONE) | 1406 | if (sta->sta_state == IEEE80211_STA_NONE) |
1420 | set_bit(WLAN_STA_AUTH, &sta->_flags); | 1407 | set_bit(WLAN_STA_AUTH, &sta->_flags); |
1421 | else if (sta->sta_state == IEEE80211_STA_ASSOC) | 1408 | else if (sta->sta_state == IEEE80211_STA_ASSOC) |
1422 | clear_bit(WLAN_STA_ASSOC, &sta->_flags); | 1409 | clear_bit(WLAN_STA_ASSOC, &sta->_flags); |
1423 | else | ||
1424 | return -EINVAL; | ||
1425 | break; | 1410 | break; |
1426 | case IEEE80211_STA_ASSOC: | 1411 | case IEEE80211_STA_ASSOC: |
1427 | if (sta->sta_state == IEEE80211_STA_AUTH) { | 1412 | if (sta->sta_state == IEEE80211_STA_AUTH) { |
@@ -1430,24 +1415,19 @@ int sta_info_move_state(struct sta_info *sta, | |||
1430 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP) | 1415 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP) |
1431 | atomic_dec(&sta->sdata->u.ap.num_sta_authorized); | 1416 | atomic_dec(&sta->sdata->u.ap.num_sta_authorized); |
1432 | clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); | 1417 | clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); |
1433 | } else | 1418 | } |
1434 | return -EINVAL; | ||
1435 | break; | 1419 | break; |
1436 | case IEEE80211_STA_AUTHORIZED: | 1420 | case IEEE80211_STA_AUTHORIZED: |
1437 | if (sta->sta_state == IEEE80211_STA_ASSOC) { | 1421 | if (sta->sta_state == IEEE80211_STA_ASSOC) { |
1438 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP) | 1422 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP) |
1439 | atomic_inc(&sta->sdata->u.ap.num_sta_authorized); | 1423 | atomic_inc(&sta->sdata->u.ap.num_sta_authorized); |
1440 | set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); | 1424 | set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); |
1441 | } else | 1425 | } |
1442 | return -EINVAL; | ||
1443 | break; | 1426 | break; |
1444 | default: | 1427 | default: |
1445 | WARN(1, "invalid state %d", new_state); | 1428 | break; |
1446 | return -EINVAL; | ||
1447 | } | 1429 | } |
1448 | 1430 | ||
1449 | printk(KERN_DEBUG "%s: moving STA %pM to state %d\n", | ||
1450 | sta->sdata->name, sta->sta.addr, new_state); | ||
1451 | sta->sta_state = new_state; | 1431 | sta->sta_state = new_state; |
1452 | 1432 | ||
1453 | return 0; | 1433 | return 0; |