diff options
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 @@ #include <linux/wireless.h> #include <linux/random.h> #include <linux/etherdevice.h> +#include <linux/rtnetlink.h> #include <net/iw_handler.h> #include <asm/types.h> @@ -845,6 +846,8 @@ static void ieee80211_associated(struct net_device *dev, ifsta->state = IEEE80211_ASSOCIATED; + rcu_read_lock(); + sta = sta_info_get(local, ifsta->bssid); if (!sta) { printk(KERN_DEBUG "%s: No STA entry for own AP %s\n", @@ -860,7 +863,7 @@ static void ieee80211_associated(struct net_device *dev, "range\n", dev->name, print_mac(mac, ifsta->bssid)); disassoc = 1; - sta_info_free(sta); + sta_info_unlink(&sta); } else ieee80211_send_probe_req(dev, ifsta->bssid, local->scan_ssid, @@ -876,8 +879,17 @@ static void ieee80211_associated(struct net_device *dev, ifsta->ssid_len); } } - sta_info_put(sta); } + + rcu_read_unlock(); + + if (disassoc && sta) { + synchronize_rcu(); + rtnl_lock(); + sta_info_destroy(sta); + rtnl_unlock(); + } + if (disassoc) { ifsta->state = IEEE80211_DISABLED; ieee80211_set_associated(dev, ifsta, 0); @@ -1103,9 +1115,13 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, int ret = -EOPNOTSUPP; DECLARE_MAC_BUF(mac); + rcu_read_lock(); + sta = sta_info_get(local, mgmt->sa); - if (!sta) + if (!sta) { + rcu_read_unlock(); return; + } /* extract session parameters from addba request frame */ dialog_token = mgmt->u.action.u.addba_req.dialog_token; @@ -1197,9 +1213,9 @@ end: spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); end_no_lock: - ieee80211_send_addba_resp(sta->dev, sta->addr, tid, dialog_token, - status, 1, buf_size, timeout); - sta_info_put(sta); + ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid, + dialog_token, status, 1, buf_size, timeout); + rcu_read_unlock(); } 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, u16 tid; u8 *state; + rcu_read_lock(); + sta = sta_info_get(local, mgmt->sa); - if (!sta) + if (!sta) { + rcu_read_unlock(); return; + } capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; @@ -1230,7 +1250,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - sta_info_put(sta); + rcu_read_unlock(); return; } @@ -1244,7 +1264,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" "%d\n", *state); - sta_info_put(sta); + rcu_read_unlock(); return; } @@ -1271,7 +1291,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, ieee80211_stop_tx_ba_session(hw, sta->addr, tid, WLAN_BACK_INITIATOR); } - sta_info_put(sta); + rcu_read_unlock(); } 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, struct sta_info *sta; int ret, i; + rcu_read_lock(); + sta = sta_info_get(local, ra); - if (!sta) + if (!sta) { + rcu_read_unlock(); return; + } /* check if TID is in operational state */ spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); if (sta->ampdu_mlme.tid_rx[tid].state != HT_AGG_STATE_OPERATIONAL) { spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); - sta_info_put(sta); + rcu_read_unlock(); return; } 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, kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf); sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE; - sta_info_put(sta); + rcu_read_unlock(); } @@ -1387,9 +1411,13 @@ static void ieee80211_sta_process_delba(struct net_device *dev, u16 initiator; DECLARE_MAC_BUF(mac); + rcu_read_lock(); + sta = sta_info_get(local, mgmt->sa); - if (!sta) + if (!sta) { + rcu_read_unlock(); return; + } params = le16_to_cpu(mgmt->u.action.u.delba.params); tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; @@ -1414,7 +1442,7 @@ static void ieee80211_sta_process_delba(struct net_device *dev, ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, WLAN_BACK_RECIPIENT); } - sta_info_put(sta); + rcu_read_unlock(); } /* @@ -1437,9 +1465,13 @@ void sta_addba_resp_timer_expired(unsigned long data) struct sta_info *sta; u8 *state; + rcu_read_lock(); + sta = sta_info_get(local, temp_sta->addr); - if (!sta) + if (!sta) { + rcu_read_unlock(); return; + } state = &sta->ampdu_mlme.tid_tx[tid].state; /* check if the TID waits for addBA response */ @@ -1461,7 +1493,7 @@ void sta_addba_resp_timer_expired(unsigned long data) WLAN_BACK_INITIATOR); timer_expired_exit: - sta_info_put(sta); + rcu_read_unlock(); } /* @@ -1481,8 +1513,8 @@ void sta_rx_agg_session_timer_expired(unsigned long data) timer_to_tid[0]); printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); - ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, (u16)*ptid, - WLAN_BACK_TIMER, + ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr, + (u16)*ptid, WLAN_BACK_TIMER, WLAN_REASON_QSTA_TIMEOUT); } @@ -1791,14 +1823,18 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (ifsta->assocresp_ies) memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); + rcu_read_lock(); + /* Add STA entry for the AP */ sta = sta_info_get(local, ifsta->bssid); if (!sta) { struct ieee80211_sta_bss *bss; - sta = sta_info_add(local, dev, ifsta->bssid, GFP_KERNEL); + + sta = sta_info_add(sdata, ifsta->bssid); if (IS_ERR(sta)) { printk(KERN_DEBUG "%s: failed to add STA entry for the" " AP (error %ld)\n", dev->name, PTR_ERR(sta)); + rcu_read_unlock(); return; } 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, } } - sta->dev = dev; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | WLAN_STA_AUTHORIZED; @@ -1883,7 +1918,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, bss_conf->aid = aid; ieee80211_set_associated(dev, ifsta, 1); - sta_info_put(sta); + rcu_read_unlock(); ieee80211_associated(dev, ifsta); } @@ -2329,6 +2364,8 @@ static void ieee80211_rx_bss_info(struct net_device *dev, mesh_peer_accepts_plinks(&elems, dev)); } + rcu_read_lock(); + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && (sta = sta_info_get(local, mgmt->sa))) { @@ -2354,9 +2391,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev, (unsigned long long) supp_rates, (unsigned long long) sta->supp_rates[rx_status->band]); } - sta_info_put(sta); } + rcu_read_unlock(); + if (elems.ds_params && elems.ds_params_len == 1) freq = ieee80211_channel_to_frequency(elems.ds_params[0]); else @@ -2550,8 +2588,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev, "local TSF - IBSS merge with BSSID %s\n", dev->name, print_mac(mac, mgmt->bssid)); ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss); + rcu_read_lock(); ieee80211_ibss_add_sta(dev, NULL, mgmt->bssid, mgmt->sa); + rcu_read_unlock(); } } @@ -2893,17 +2933,20 @@ static int ieee80211_sta_active_ibss(struct net_device *dev) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); int active = 0; struct sta_info *sta; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - read_lock_bh(&local->sta_lock); - list_for_each_entry(sta, &local->sta_list, list) { - if (sta->dev == dev && + rcu_read_lock(); + + list_for_each_entry_rcu(sta, &local->sta_list, list) { + if (sta->sdata == sdata && time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, jiffies)) { active++; break; } } - read_unlock_bh(&local->sta_lock); + + rcu_read_unlock(); return active; } @@ -2915,22 +2958,25 @@ static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time) struct sta_info *sta, *tmp; LIST_HEAD(tmp_list); DECLARE_MAC_BUF(mac); + unsigned long flags; - write_lock_bh(&local->sta_lock); + spin_lock_irqsave(&local->sta_lock, flags); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) if (time_after(jiffies, sta->last_rx + exp_time)) { printk(KERN_DEBUG "%s: expiring inactive STA %s\n", dev->name, print_mac(mac, sta->addr)); - __sta_info_get(sta); - sta_info_remove(sta); - list_add(&sta->list, &tmp_list); + sta_info_unlink(&sta); + if (sta) + list_add(&sta->list, &tmp_list); } - write_unlock_bh(&local->sta_lock); + spin_unlock_irqrestore(&local->sta_lock, flags); - list_for_each_entry_safe(sta, tmp, &tmp_list, list) { - sta_info_free(sta); - sta_info_put(sta); - } + synchronize_rcu(); + + rtnl_lock(); + list_for_each_entry_safe(sta, tmp, &tmp_list, list) + sta_info_destroy(sta); + rtnl_unlock(); } @@ -3977,6 +4023,7 @@ int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len) } +/* must be called under RCU read lock */ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, struct sk_buff *skb, u8 *bssid, u8 *addr) @@ -3999,7 +4046,7 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); - sta = sta_info_add(local, dev, addr, GFP_ATOMIC); + sta = sta_info_add(sdata, addr); if (IS_ERR(sta)) return NULL; @@ -4010,7 +4057,7 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, rate_control_rate_init(sta, local); - return sta; /* caller will call sta_info_put() */ + return sta; } |