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/ieee80211_sta.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/ieee80211_sta.c')
-rw-r--r-- | net/mac80211/ieee80211_sta.c | 123 |
1 files changed, 85 insertions, 38 deletions
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 9f933aeca719..a3e96eb59eb0 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/wireless.h> | 24 | #include <linux/wireless.h> |
25 | #include <linux/random.h> | 25 | #include <linux/random.h> |
26 | #include <linux/etherdevice.h> | 26 | #include <linux/etherdevice.h> |
27 | #include <linux/rtnetlink.h> | ||
27 | #include <net/iw_handler.h> | 28 | #include <net/iw_handler.h> |
28 | #include <asm/types.h> | 29 | #include <asm/types.h> |
29 | 30 | ||
@@ -845,6 +846,8 @@ static void ieee80211_associated(struct net_device *dev, | |||
845 | 846 | ||
846 | ifsta->state = IEEE80211_ASSOCIATED; | 847 | ifsta->state = IEEE80211_ASSOCIATED; |
847 | 848 | ||
849 | rcu_read_lock(); | ||
850 | |||
848 | sta = sta_info_get(local, ifsta->bssid); | 851 | sta = sta_info_get(local, ifsta->bssid); |
849 | if (!sta) { | 852 | if (!sta) { |
850 | printk(KERN_DEBUG "%s: No STA entry for own AP %s\n", | 853 | printk(KERN_DEBUG "%s: No STA entry for own AP %s\n", |
@@ -860,7 +863,7 @@ static void ieee80211_associated(struct net_device *dev, | |||
860 | "range\n", | 863 | "range\n", |
861 | dev->name, print_mac(mac, ifsta->bssid)); | 864 | dev->name, print_mac(mac, ifsta->bssid)); |
862 | disassoc = 1; | 865 | disassoc = 1; |
863 | sta_info_free(sta); | 866 | sta_info_unlink(&sta); |
864 | } else | 867 | } else |
865 | ieee80211_send_probe_req(dev, ifsta->bssid, | 868 | ieee80211_send_probe_req(dev, ifsta->bssid, |
866 | local->scan_ssid, | 869 | local->scan_ssid, |
@@ -876,8 +879,17 @@ static void ieee80211_associated(struct net_device *dev, | |||
876 | ifsta->ssid_len); | 879 | ifsta->ssid_len); |
877 | } | 880 | } |
878 | } | 881 | } |
879 | sta_info_put(sta); | ||
880 | } | 882 | } |
883 | |||
884 | rcu_read_unlock(); | ||
885 | |||
886 | if (disassoc && sta) { | ||
887 | synchronize_rcu(); | ||
888 | rtnl_lock(); | ||
889 | sta_info_destroy(sta); | ||
890 | rtnl_unlock(); | ||
891 | } | ||
892 | |||
881 | if (disassoc) { | 893 | if (disassoc) { |
882 | ifsta->state = IEEE80211_DISABLED; | 894 | ifsta->state = IEEE80211_DISABLED; |
883 | ieee80211_set_associated(dev, ifsta, 0); | 895 | ieee80211_set_associated(dev, ifsta, 0); |
@@ -1103,9 +1115,13 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, | |||
1103 | int ret = -EOPNOTSUPP; | 1115 | int ret = -EOPNOTSUPP; |
1104 | DECLARE_MAC_BUF(mac); | 1116 | DECLARE_MAC_BUF(mac); |
1105 | 1117 | ||
1118 | rcu_read_lock(); | ||
1119 | |||
1106 | sta = sta_info_get(local, mgmt->sa); | 1120 | sta = sta_info_get(local, mgmt->sa); |
1107 | if (!sta) | 1121 | if (!sta) { |
1122 | rcu_read_unlock(); | ||
1108 | return; | 1123 | return; |
1124 | } | ||
1109 | 1125 | ||
1110 | /* extract session parameters from addba request frame */ | 1126 | /* extract session parameters from addba request frame */ |
1111 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; | 1127 | dialog_token = mgmt->u.action.u.addba_req.dialog_token; |
@@ -1197,9 +1213,9 @@ end: | |||
1197 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); | 1213 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); |
1198 | 1214 | ||
1199 | end_no_lock: | 1215 | end_no_lock: |
1200 | ieee80211_send_addba_resp(sta->dev, sta->addr, tid, dialog_token, | 1216 | ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid, |
1201 | status, 1, buf_size, timeout); | 1217 | dialog_token, status, 1, buf_size, timeout); |
1202 | sta_info_put(sta); | 1218 | rcu_read_unlock(); |
1203 | } | 1219 | } |
1204 | 1220 | ||
1205 | static void ieee80211_sta_process_addba_resp(struct net_device *dev, | 1221 | static void ieee80211_sta_process_addba_resp(struct net_device *dev, |
@@ -1213,9 +1229,13 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, | |||
1213 | u16 tid; | 1229 | u16 tid; |
1214 | u8 *state; | 1230 | u8 *state; |
1215 | 1231 | ||
1232 | rcu_read_lock(); | ||
1233 | |||
1216 | sta = sta_info_get(local, mgmt->sa); | 1234 | sta = sta_info_get(local, mgmt->sa); |
1217 | if (!sta) | 1235 | if (!sta) { |
1236 | rcu_read_unlock(); | ||
1218 | return; | 1237 | return; |
1238 | } | ||
1219 | 1239 | ||
1220 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); | 1240 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); |
1221 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; | 1241 | tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; |
@@ -1230,7 +1250,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, | |||
1230 | #ifdef CONFIG_MAC80211_HT_DEBUG | 1250 | #ifdef CONFIG_MAC80211_HT_DEBUG |
1231 | printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); | 1251 | printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); |
1232 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 1252 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
1233 | sta_info_put(sta); | 1253 | rcu_read_unlock(); |
1234 | return; | 1254 | return; |
1235 | } | 1255 | } |
1236 | 1256 | ||
@@ -1244,7 +1264,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, | |||
1244 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); | 1264 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); |
1245 | printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" | 1265 | printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" |
1246 | "%d\n", *state); | 1266 | "%d\n", *state); |
1247 | sta_info_put(sta); | 1267 | rcu_read_unlock(); |
1248 | return; | 1268 | return; |
1249 | } | 1269 | } |
1250 | 1270 | ||
@@ -1271,7 +1291,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, | |||
1271 | ieee80211_stop_tx_ba_session(hw, sta->addr, tid, | 1291 | ieee80211_stop_tx_ba_session(hw, sta->addr, tid, |
1272 | WLAN_BACK_INITIATOR); | 1292 | WLAN_BACK_INITIATOR); |
1273 | } | 1293 | } |
1274 | sta_info_put(sta); | 1294 | rcu_read_unlock(); |
1275 | } | 1295 | } |
1276 | 1296 | ||
1277 | void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, | 1297 | void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, |
@@ -1326,16 +1346,20 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, | |||
1326 | struct sta_info *sta; | 1346 | struct sta_info *sta; |
1327 | int ret, i; | 1347 | int ret, i; |
1328 | 1348 | ||
1349 | rcu_read_lock(); | ||
1350 | |||
1329 | sta = sta_info_get(local, ra); | 1351 | sta = sta_info_get(local, ra); |
1330 | if (!sta) | 1352 | if (!sta) { |
1353 | rcu_read_unlock(); | ||
1331 | return; | 1354 | return; |
1355 | } | ||
1332 | 1356 | ||
1333 | /* check if TID is in operational state */ | 1357 | /* check if TID is in operational state */ |
1334 | spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); | 1358 | spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); |
1335 | if (sta->ampdu_mlme.tid_rx[tid].state | 1359 | if (sta->ampdu_mlme.tid_rx[tid].state |
1336 | != HT_AGG_STATE_OPERATIONAL) { | 1360 | != HT_AGG_STATE_OPERATIONAL) { |
1337 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); | 1361 | spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); |
1338 | sta_info_put(sta); | 1362 | rcu_read_unlock(); |
1339 | return; | 1363 | return; |
1340 | } | 1364 | } |
1341 | sta->ampdu_mlme.tid_rx[tid].state = | 1365 | sta->ampdu_mlme.tid_rx[tid].state = |
@@ -1374,7 +1398,7 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, | |||
1374 | kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf); | 1398 | kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf); |
1375 | 1399 | ||
1376 | sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE; | 1400 | sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE; |
1377 | sta_info_put(sta); | 1401 | rcu_read_unlock(); |
1378 | } | 1402 | } |
1379 | 1403 | ||
1380 | 1404 | ||
@@ -1387,9 +1411,13 @@ static void ieee80211_sta_process_delba(struct net_device *dev, | |||
1387 | u16 initiator; | 1411 | u16 initiator; |
1388 | DECLARE_MAC_BUF(mac); | 1412 | DECLARE_MAC_BUF(mac); |
1389 | 1413 | ||
1414 | rcu_read_lock(); | ||
1415 | |||
1390 | sta = sta_info_get(local, mgmt->sa); | 1416 | sta = sta_info_get(local, mgmt->sa); |
1391 | if (!sta) | 1417 | if (!sta) { |
1418 | rcu_read_unlock(); | ||
1392 | return; | 1419 | return; |
1420 | } | ||
1393 | 1421 | ||
1394 | params = le16_to_cpu(mgmt->u.action.u.delba.params); | 1422 | params = le16_to_cpu(mgmt->u.action.u.delba.params); |
1395 | tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; | 1423 | tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; |
@@ -1414,7 +1442,7 @@ static void ieee80211_sta_process_delba(struct net_device *dev, | |||
1414 | ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, | 1442 | ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, |
1415 | WLAN_BACK_RECIPIENT); | 1443 | WLAN_BACK_RECIPIENT); |
1416 | } | 1444 | } |
1417 | sta_info_put(sta); | 1445 | rcu_read_unlock(); |
1418 | } | 1446 | } |
1419 | 1447 | ||
1420 | /* | 1448 | /* |
@@ -1437,9 +1465,13 @@ void sta_addba_resp_timer_expired(unsigned long data) | |||
1437 | struct sta_info *sta; | 1465 | struct sta_info *sta; |
1438 | u8 *state; | 1466 | u8 *state; |
1439 | 1467 | ||
1468 | rcu_read_lock(); | ||
1469 | |||
1440 | sta = sta_info_get(local, temp_sta->addr); | 1470 | sta = sta_info_get(local, temp_sta->addr); |
1441 | if (!sta) | 1471 | if (!sta) { |
1472 | rcu_read_unlock(); | ||
1442 | return; | 1473 | return; |
1474 | } | ||
1443 | 1475 | ||
1444 | state = &sta->ampdu_mlme.tid_tx[tid].state; | 1476 | state = &sta->ampdu_mlme.tid_tx[tid].state; |
1445 | /* check if the TID waits for addBA response */ | 1477 | /* check if the TID waits for addBA response */ |
@@ -1461,7 +1493,7 @@ void sta_addba_resp_timer_expired(unsigned long data) | |||
1461 | WLAN_BACK_INITIATOR); | 1493 | WLAN_BACK_INITIATOR); |
1462 | 1494 | ||
1463 | timer_expired_exit: | 1495 | timer_expired_exit: |
1464 | sta_info_put(sta); | 1496 | rcu_read_unlock(); |
1465 | } | 1497 | } |
1466 | 1498 | ||
1467 | /* | 1499 | /* |
@@ -1481,8 +1513,8 @@ void sta_rx_agg_session_timer_expired(unsigned long data) | |||
1481 | timer_to_tid[0]); | 1513 | timer_to_tid[0]); |
1482 | 1514 | ||
1483 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); | 1515 | printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); |
1484 | ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, (u16)*ptid, | 1516 | ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr, |
1485 | WLAN_BACK_TIMER, | 1517 | (u16)*ptid, WLAN_BACK_TIMER, |
1486 | WLAN_REASON_QSTA_TIMEOUT); | 1518 | WLAN_REASON_QSTA_TIMEOUT); |
1487 | } | 1519 | } |
1488 | 1520 | ||
@@ -1791,14 +1823,18 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1791 | if (ifsta->assocresp_ies) | 1823 | if (ifsta->assocresp_ies) |
1792 | memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); | 1824 | memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); |
1793 | 1825 | ||
1826 | rcu_read_lock(); | ||
1827 | |||
1794 | /* Add STA entry for the AP */ | 1828 | /* Add STA entry for the AP */ |
1795 | sta = sta_info_get(local, ifsta->bssid); | 1829 | sta = sta_info_get(local, ifsta->bssid); |
1796 | if (!sta) { | 1830 | if (!sta) { |
1797 | struct ieee80211_sta_bss *bss; | 1831 | struct ieee80211_sta_bss *bss; |
1798 | sta = sta_info_add(local, dev, ifsta->bssid, GFP_KERNEL); | 1832 | |
1833 | sta = sta_info_add(sdata, ifsta->bssid); | ||
1799 | if (IS_ERR(sta)) { | 1834 | if (IS_ERR(sta)) { |
1800 | printk(KERN_DEBUG "%s: failed to add STA entry for the" | 1835 | printk(KERN_DEBUG "%s: failed to add STA entry for the" |
1801 | " AP (error %ld)\n", dev->name, PTR_ERR(sta)); | 1836 | " AP (error %ld)\n", dev->name, PTR_ERR(sta)); |
1837 | rcu_read_unlock(); | ||
1802 | return; | 1838 | return; |
1803 | } | 1839 | } |
1804 | bss = ieee80211_rx_bss_get(dev, ifsta->bssid, | 1840 | bss = ieee80211_rx_bss_get(dev, ifsta->bssid, |
@@ -1812,7 +1848,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1812 | } | 1848 | } |
1813 | } | 1849 | } |
1814 | 1850 | ||
1815 | sta->dev = dev; | ||
1816 | sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | | 1851 | sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | |
1817 | WLAN_STA_AUTHORIZED; | 1852 | WLAN_STA_AUTHORIZED; |
1818 | 1853 | ||
@@ -1883,7 +1918,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1883 | bss_conf->aid = aid; | 1918 | bss_conf->aid = aid; |
1884 | ieee80211_set_associated(dev, ifsta, 1); | 1919 | ieee80211_set_associated(dev, ifsta, 1); |
1885 | 1920 | ||
1886 | sta_info_put(sta); | 1921 | rcu_read_unlock(); |
1887 | 1922 | ||
1888 | ieee80211_associated(dev, ifsta); | 1923 | ieee80211_associated(dev, ifsta); |
1889 | } | 1924 | } |
@@ -2329,6 +2364,8 @@ static void ieee80211_rx_bss_info(struct net_device *dev, | |||
2329 | mesh_peer_accepts_plinks(&elems, dev)); | 2364 | mesh_peer_accepts_plinks(&elems, dev)); |
2330 | } | 2365 | } |
2331 | 2366 | ||
2367 | rcu_read_lock(); | ||
2368 | |||
2332 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && | 2369 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && |
2333 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && | 2370 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && |
2334 | (sta = sta_info_get(local, mgmt->sa))) { | 2371 | (sta = sta_info_get(local, mgmt->sa))) { |
@@ -2354,9 +2391,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev, | |||
2354 | (unsigned long long) supp_rates, | 2391 | (unsigned long long) supp_rates, |
2355 | (unsigned long long) sta->supp_rates[rx_status->band]); | 2392 | (unsigned long long) sta->supp_rates[rx_status->band]); |
2356 | } | 2393 | } |
2357 | sta_info_put(sta); | ||
2358 | } | 2394 | } |
2359 | 2395 | ||
2396 | rcu_read_unlock(); | ||
2397 | |||
2360 | if (elems.ds_params && elems.ds_params_len == 1) | 2398 | if (elems.ds_params && elems.ds_params_len == 1) |
2361 | freq = ieee80211_channel_to_frequency(elems.ds_params[0]); | 2399 | freq = ieee80211_channel_to_frequency(elems.ds_params[0]); |
2362 | else | 2400 | else |
@@ -2550,8 +2588,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev, | |||
2550 | "local TSF - IBSS merge with BSSID %s\n", | 2588 | "local TSF - IBSS merge with BSSID %s\n", |
2551 | dev->name, print_mac(mac, mgmt->bssid)); | 2589 | dev->name, print_mac(mac, mgmt->bssid)); |
2552 | ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss); | 2590 | ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss); |
2591 | rcu_read_lock(); | ||
2553 | ieee80211_ibss_add_sta(dev, NULL, | 2592 | ieee80211_ibss_add_sta(dev, NULL, |
2554 | mgmt->bssid, mgmt->sa); | 2593 | mgmt->bssid, mgmt->sa); |
2594 | rcu_read_unlock(); | ||
2555 | } | 2595 | } |
2556 | } | 2596 | } |
2557 | 2597 | ||
@@ -2893,17 +2933,20 @@ static int ieee80211_sta_active_ibss(struct net_device *dev) | |||
2893 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 2933 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
2894 | int active = 0; | 2934 | int active = 0; |
2895 | struct sta_info *sta; | 2935 | struct sta_info *sta; |
2936 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2896 | 2937 | ||
2897 | read_lock_bh(&local->sta_lock); | 2938 | rcu_read_lock(); |
2898 | list_for_each_entry(sta, &local->sta_list, list) { | 2939 | |
2899 | if (sta->dev == dev && | 2940 | list_for_each_entry_rcu(sta, &local->sta_list, list) { |
2941 | if (sta->sdata == sdata && | ||
2900 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | 2942 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, |
2901 | jiffies)) { | 2943 | jiffies)) { |
2902 | active++; | 2944 | active++; |
2903 | break; | 2945 | break; |
2904 | } | 2946 | } |
2905 | } | 2947 | } |
2906 | read_unlock_bh(&local->sta_lock); | 2948 | |
2949 | rcu_read_unlock(); | ||
2907 | 2950 | ||
2908 | return active; | 2951 | return active; |
2909 | } | 2952 | } |
@@ -2915,22 +2958,25 @@ static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time) | |||
2915 | struct sta_info *sta, *tmp; | 2958 | struct sta_info *sta, *tmp; |
2916 | LIST_HEAD(tmp_list); | 2959 | LIST_HEAD(tmp_list); |
2917 | DECLARE_MAC_BUF(mac); | 2960 | DECLARE_MAC_BUF(mac); |
2961 | unsigned long flags; | ||
2918 | 2962 | ||
2919 | write_lock_bh(&local->sta_lock); | 2963 | spin_lock_irqsave(&local->sta_lock, flags); |
2920 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) | 2964 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) |
2921 | if (time_after(jiffies, sta->last_rx + exp_time)) { | 2965 | if (time_after(jiffies, sta->last_rx + exp_time)) { |
2922 | printk(KERN_DEBUG "%s: expiring inactive STA %s\n", | 2966 | printk(KERN_DEBUG "%s: expiring inactive STA %s\n", |
2923 | dev->name, print_mac(mac, sta->addr)); | 2967 | dev->name, print_mac(mac, sta->addr)); |
2924 | __sta_info_get(sta); | 2968 | sta_info_unlink(&sta); |
2925 | sta_info_remove(sta); | 2969 | if (sta) |
2926 | list_add(&sta->list, &tmp_list); | 2970 | list_add(&sta->list, &tmp_list); |
2927 | } | 2971 | } |
2928 | write_unlock_bh(&local->sta_lock); | 2972 | spin_unlock_irqrestore(&local->sta_lock, flags); |
2929 | 2973 | ||
2930 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) { | 2974 | synchronize_rcu(); |
2931 | sta_info_free(sta); | 2975 | |
2932 | sta_info_put(sta); | 2976 | rtnl_lock(); |
2933 | } | 2977 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) |
2978 | sta_info_destroy(sta); | ||
2979 | rtnl_unlock(); | ||
2934 | } | 2980 | } |
2935 | 2981 | ||
2936 | 2982 | ||
@@ -3977,6 +4023,7 @@ int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len) | |||
3977 | } | 4023 | } |
3978 | 4024 | ||
3979 | 4025 | ||
4026 | /* must be called under RCU read lock */ | ||
3980 | struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, | 4027 | struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, |
3981 | struct sk_buff *skb, u8 *bssid, | 4028 | struct sk_buff *skb, u8 *bssid, |
3982 | u8 *addr) | 4029 | u8 *addr) |
@@ -3999,7 +4046,7 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, | |||
3999 | printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", | 4046 | printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", |
4000 | wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); | 4047 | wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); |
4001 | 4048 | ||
4002 | sta = sta_info_add(local, dev, addr, GFP_ATOMIC); | 4049 | sta = sta_info_add(sdata, addr); |
4003 | if (IS_ERR(sta)) | 4050 | if (IS_ERR(sta)) |
4004 | return NULL; | 4051 | return NULL; |
4005 | 4052 | ||
@@ -4010,7 +4057,7 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, | |||
4010 | 4057 | ||
4011 | rate_control_rate_init(sta, local); | 4058 | rate_control_rate_init(sta, local); |
4012 | 4059 | ||
4013 | return sta; /* caller will call sta_info_put() */ | 4060 | return sta; |
4014 | } | 4061 | } |
4015 | 4062 | ||
4016 | 4063 | ||