aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ieee80211_sta.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-02-25 10:27:46 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-03-06 15:30:46 -0500
commitd0709a65181beb787ef3f58cfe45536a2bb254c8 (patch)
tree29e5f36583b0e0a3f11b291347e57672eab41dad /net/mac80211/ieee80211_sta.c
parent5cf121c3cdb955583bf0c5d28c992b7968a4aa1a (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.c123
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
1199end_no_lock: 1215end_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
1205static void ieee80211_sta_process_addba_resp(struct net_device *dev, 1221static 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
1277void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, 1297void 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
1463timer_expired_exit: 1495timer_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 */
3980struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, 4027struct 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