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>
This commit is contained in:
Johannes Berg
2008-02-25 16:27:46 +01:00
committed by John W. Linville
parent 5cf121c3cd
commit d0709a6518
25 changed files with 707 additions and 492 deletions
+18 -13
View File
@@ -471,10 +471,11 @@ static void rs_tx_status(void *priv_rate,
return;
}
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
if (!sta || !sta->rate_ctrl_priv) {
if (sta)
sta_info_put(sta);
rcu_read_unlock();
IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
return;
}
@@ -547,7 +548,7 @@ static void rs_tx_status(void *priv_rate,
spin_unlock_irqrestore(&rs_sta->lock, flags);
sta_info_put(sta);
rcu_read_unlock();
IWL_DEBUG_RATE("leave\n");
@@ -658,6 +659,8 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
IWL_DEBUG_RATE("enter\n");
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
/* Send management frames and broadcast/multicast data using lowest
@@ -668,8 +671,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
!sta || !sta->rate_ctrl_priv) {
IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
sel->rate = rate_lowest(local, band, sta);
if (sta)
sta_info_put(sta);
rcu_read_unlock();
return;
}
@@ -811,7 +813,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
else
sta->txrate_idx = sta->last_txrate_idx;
sta_info_put(sta);
rcu_read_unlock();
IWL_DEBUG_RATE("leave: %d\n", index);
@@ -843,13 +845,15 @@ int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
unsigned long now = jiffies;
u32 max_time = 0;
rcu_read_lock();
sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
if (!sta || !sta->rate_ctrl_priv) {
if (sta) {
sta_info_put(sta);
if (sta)
IWL_DEBUG_RATE("leave - no private rate data!\n");
} else
else
IWL_DEBUG_RATE("leave - no station!\n");
rcu_read_unlock();
return sprintf(buf, "station %d not found\n", sta_id);
}
@@ -890,7 +894,7 @@ int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
i = j;
}
spin_unlock_irqrestore(&rs_sta->lock, flags);
sta_info_put(sta);
rcu_read_unlock();
/* Display the average rate of all samples taken.
*
@@ -927,11 +931,12 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
return;
}
rcu_read_lock();
sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
if (!sta || !sta->rate_ctrl_priv) {
if (sta)
sta_info_put(sta);
IWL_DEBUG_RATE("leave - no private rate data!\n");
rcu_read_unlock();
return;
}
@@ -958,7 +963,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
break;
}
sta_info_put(sta);
rcu_read_unlock();
spin_unlock_irqrestore(&rs_sta->lock, flags);
rssi = priv->last_rx_rssi;
+15 -12
View File
@@ -847,12 +847,12 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
if (retries > 15)
retries = 15;
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
if (!sta || !sta->rate_ctrl_priv) {
if (sta)
sta_info_put(sta);
rcu_read_unlock();
return;
}
@@ -891,7 +891,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
if ((rs_index < 0) || (rs_index >= IWL_RATE_COUNT)) {
IWL_DEBUG_RATE("bad rate index at: %d rate 0x%X\n",
rs_index, tx_mcs.rate_n_flags);
sta_info_put(sta);
rcu_read_unlock();
return;
}
@@ -909,7 +909,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
IWL_DEBUG_RATE("initial rate does not match 0x%x 0x%x\n",
tx_mcs.rate_n_flags,
le32_to_cpu(table->rs_table[0].rate_n_flags));
sta_info_put(sta);
rcu_read_unlock();
return;
}
@@ -1025,7 +1025,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
/* See if there's a better rate or modulation mode to try. */
rs_rate_scale_perform(priv, dev, hdr, sta);
sta_info_put(sta);
rcu_read_unlock();
return;
}
@@ -2219,6 +2219,8 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
/* Send management frames and broadcast/multicast data using lowest
@@ -2227,8 +2229,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
!sta || !sta->rate_ctrl_priv) {
sel->rate = rate_lowest(local, sband, sta);
if (sta)
sta_info_put(sta);
rcu_read_unlock();
return;
}
@@ -2261,7 +2262,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
sel->rate = rate_lowest(local, sband, sta);
return;
}
sta_info_put(sta);
rcu_read_unlock();
sel->rate = &priv->ieee_rates[i];
}
@@ -2735,13 +2736,15 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
u32 max_time = 0;
u8 lq_type, antenna;
rcu_read_lock();
sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
if (!sta || !sta->rate_ctrl_priv) {
if (sta) {
sta_info_put(sta);
if (sta)
IWL_DEBUG_RATE("leave - no private rate data!\n");
} else
else
IWL_DEBUG_RATE("leave - no station!\n");
rcu_read_unlock();
return sprintf(buf, "station %d not found\n", sta_id);
}
@@ -2808,7 +2811,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
"active_search %d rate index %d\n", lq_type, antenna,
lq_sta->search_better_tbl, sta->last_txrate_idx);
sta_info_put(sta);
rcu_read_unlock();
return cnt;
}
+58 -56
View File
@@ -136,7 +136,6 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta = NULL;
enum ieee80211_key_alg alg;
int ret;
struct ieee80211_key *key;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -170,12 +169,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
ieee80211_key_link(key, sdata, sta);
ret = 0;
if (sta)
sta_info_put(sta);
return ret;
return 0;
}
static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
@@ -184,7 +178,6 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
int ret;
struct ieee80211_key *key;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -195,21 +188,18 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
ret = 0;
if (sta->key) {
key = sta->key;
ieee80211_key_free(key);
ieee80211_key_free(sta->key);
WARN_ON(sta->key);
} else
ret = -ENOENT;
sta_info_put(sta);
return ret;
}
if (!sdata->keys[key_idx])
return -ENOENT;
key = sdata->keys[key_idx];
ieee80211_key_free(key);
ieee80211_key_free(sdata->keys[key_idx]);
WARN_ON(sdata->keys[key_idx]);
return 0;
@@ -292,8 +282,6 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
err = 0;
out:
if (sta)
sta_info_put(sta);
return err;
}
@@ -311,7 +299,7 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
struct ieee80211_sub_if_data *sdata = sta->sdata;
sinfo->filled = STATION_INFO_INACTIVE_TIME |
STATION_INFO_RX_BYTES |
@@ -340,16 +328,20 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
int ret = -ENOENT;
rcu_read_lock();
sta = sta_info_get_by_idx(local, idx, dev);
if (!sta)
return -ENOENT;
if (sta) {
ret = 0;
memcpy(mac, sta->addr, ETH_ALEN);
sta_set_sinfo(sta, sinfo);
}
memcpy(mac, sta->addr, ETH_ALEN);
sta_set_sinfo(sta, sinfo);
sta_info_put(sta);
rcu_read_unlock();
return 0;
return ret;
}
static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
@@ -357,16 +349,21 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
int ret = -ENOENT;
sta = sta_info_get(local, mac);
if (!sta)
return -ENOENT;
rcu_read_lock();
/* XXX: verify sta->dev == dev */
sta_set_sinfo(sta, sinfo);
sta_info_put(sta);
return 0;
sta = sta_info_get(local, mac);
if (sta) {
ret = 0;
sta_set_sinfo(sta, sinfo);
}
rcu_read_unlock();
return ret;
}
/*
@@ -559,8 +556,8 @@ static void ieee80211_send_layer2_update(struct sta_info *sta)
msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */
skb->dev = sta->dev;
skb->protocol = eth_type_trans(skb, sta->dev);
skb->dev = sta->sdata->dev;
skb->protocol = eth_type_trans(skb, sta->sdata->dev);
memset(skb->cb, 0, sizeof(skb->cb));
netif_rx(skb);
}
@@ -572,7 +569,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
u32 rates;
int i, j;
struct ieee80211_supported_band *sband;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
struct ieee80211_sub_if_data *sdata = sta->sdata;
if (params->station_flags & STATION_FLAG_CHANGED) {
sta->flags &= ~WLAN_STA_AUTHORIZED;
@@ -644,14 +641,13 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (ieee80211_vif_is_mesh(&sdata->vif))
sta = mesh_plink_add(mac, DEFAULT_RATES, dev);
sta = mesh_plink_add(mac, DEFAULT_RATES, sdata);
else
sta = sta_info_add(local, dev, mac, GFP_KERNEL);
sta = sta_info_add(sdata, mac);
if (IS_ERR(sta))
return PTR_ERR(sta);
sta->dev = sdata->dev;
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
sdata->vif.type == IEEE80211_IF_TYPE_AP)
ieee80211_send_layer2_update(sta);
@@ -662,15 +658,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
rate_control_rate_init(sta, local);
sta_info_put(sta);
return 0;
}
static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
u8 *mac)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
if (mac) {
@@ -679,10 +674,14 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
if (!sta)
return -ENOENT;
sta_info_free(sta);
sta_info_put(sta);
sta_info_unlink(&sta);
if (sta) {
synchronize_rcu();
sta_info_destroy(sta);
}
} else
sta_info_flush(local, dev);
sta_info_flush(local, sdata);
return 0;
}
@@ -701,21 +700,19 @@ static int ieee80211_change_station(struct wiphy *wiphy,
if (!sta)
return -ENOENT;
if (params->vlan && params->vlan != sta->dev) {
if (params->vlan && params->vlan != sta->sdata->dev) {
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
vlansdata->vif.type != IEEE80211_IF_TYPE_AP)
return -EINVAL;
sta->dev = params->vlan;
sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
ieee80211_send_layer2_update(sta);
}
sta_apply_parameters(local, sta, params);
sta_info_put(sta);
return 0;
}
@@ -735,23 +732,26 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
return -ENOTSUPP;
rcu_read_lock();
sta = sta_info_get(local, next_hop);
if (!sta)
if (!sta) {
rcu_read_unlock();
return -ENOENT;
}
err = mesh_path_add(dst, dev);
if (err)
if (err) {
rcu_read_unlock();
return err;
}
rcu_read_lock();
mpath = mesh_path_lookup(dst, dev);
if (!mpath) {
rcu_read_unlock();
sta_info_put(sta);
return -ENXIO;
}
mesh_path_fix_nexthop(mpath, sta);
sta_info_put(sta);
rcu_read_unlock();
return 0;
}
@@ -760,7 +760,7 @@ static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
u8 *dst)
{
if (dst)
return mesh_path_del(dst, dev);
return mesh_path_del(dst, dev, false);
mesh_path_flush(dev);
return 0;
@@ -781,20 +781,22 @@ static int ieee80211_change_mpath(struct wiphy *wiphy,
if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
return -ENOTSUPP;
sta = sta_info_get(local, next_hop);
if (!sta)
return -ENOENT;
rcu_read_lock();
sta = sta_info_get(local, next_hop);
if (!sta) {
rcu_read_unlock();
return -ENOENT;
}
mpath = mesh_path_lookup(dst, dev);
if (!mpath) {
rcu_read_unlock();
sta_info_put(sta);
return -ENOENT;
}
mesh_path_fix_nexthop(mpath, sta);
sta_info_put(sta);
rcu_read_unlock();
return 0;
}
+2 -2
View File
@@ -51,7 +51,7 @@ static const struct file_operations sta_ ##name## _ops = { \
STA_OPS(name)
STA_FILE(aid, aid, D);
STA_FILE(dev, dev->name, S);
STA_FILE(dev, sdata->dev->name, S);
STA_FILE(rx_packets, rx_packets, LU);
STA_FILE(tx_packets, tx_packets, LU);
STA_FILE(rx_bytes, rx_bytes, LU);
@@ -200,7 +200,7 @@ static ssize_t sta_agg_status_write(struct file *file,
const char __user *user_buf, size_t count, loff_t *ppos)
{
struct sta_info *sta = file->private_data;
struct net_device *dev = sta->dev;
struct net_device *dev = sta->sdata->dev;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hw *hw = &local->hw;
u8 *da = sta->addr;
+2
View File
@@ -1,6 +1,8 @@
#ifndef __MAC80211_DEBUGFS_STA_H
#define __MAC80211_DEBUGFS_STA_H
#include "sta_info.h"
#ifdef CONFIG_MAC80211_DEBUGFS
void ieee80211_sta_debugfs_add(struct sta_info *sta);
void ieee80211_sta_debugfs_remove(struct sta_info *sta);
+52 -26
View File
@@ -375,15 +375,19 @@ static int ieee80211_stop(struct net_device *dev)
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
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)
for (i = 0; i < STA_TID_NUM; i++)
ieee80211_sta_stop_rx_ba_session(sta->dev,
ieee80211_sta_stop_rx_ba_session(sdata->dev,
sta->addr, i,
WLAN_BACK_RECIPIENT,
WLAN_REASON_QSTA_LEAVE_QBSS);
}
rcu_read_unlock();
netif_stop_queue(dev);
/*
@@ -449,7 +453,7 @@ static int ieee80211_stop(struct net_device *dev)
netif_tx_unlock_bh(local->mdev);
break;
case IEEE80211_IF_TYPE_MESH_POINT:
sta_info_flush(local, dev);
sta_info_flush(local, sdata);
/* fall through */
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
@@ -522,9 +526,12 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
print_mac(mac, ra), tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
rcu_read_lock();
sta = sta_info_get(local, ra);
if (!sta) {
printk(KERN_DEBUG "Could not find the station\n");
rcu_read_unlock();
return -ENOENT;
}
@@ -564,7 +571,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
spin_unlock_bh(&local->mdev->queue_lock);
goto start_ba_exit;
}
sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
sdata = sta->sdata;
/* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
* call back right away, it must see that the flow has begun */
@@ -601,7 +608,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
sta->ampdu_mlme.dialog_token_allocator;
sta->ampdu_mlme.tid_tx[tid].ssn = start_seq_num;
ieee80211_send_addba_request(sta->dev, ra, tid,
ieee80211_send_addba_request(sta->sdata->dev, ra, tid,
sta->ampdu_mlme.tid_tx[tid].dialog_token,
sta->ampdu_mlme.tid_tx[tid].ssn,
0x40, 5000);
@@ -614,7 +621,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
start_ba_exit:
spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
sta_info_put(sta);
rcu_read_unlock();
return ret;
}
EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
@@ -637,9 +644,12 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
print_mac(mac, ra), tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
rcu_read_lock();
sta = sta_info_get(local, ra);
if (!sta)
if (!sta) {
rcu_read_unlock();
return -ENOENT;
}
/* check if the TID is in aggregation */
state = &sta->ampdu_mlme.tid_tx[tid].state;
@@ -673,7 +683,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
stop_BA_exit:
spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
sta_info_put(sta);
rcu_read_unlock();
return ret;
}
EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
@@ -691,8 +701,10 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
return;
}
rcu_read_lock();
sta = sta_info_get(local, ra);
if (!sta) {
rcu_read_unlock();
printk(KERN_DEBUG "Could not find station: %s\n",
print_mac(mac, ra));
return;
@@ -705,7 +717,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
*state);
spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
sta_info_put(sta);
rcu_read_unlock();
return;
}
@@ -718,7 +730,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
}
spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
sta_info_put(sta);
rcu_read_unlock();
}
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
@@ -739,10 +751,12 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
printk(KERN_DEBUG "Stop a BA session requested on DA %s tid %d\n",
print_mac(mac, ra), tid);
rcu_read_lock();
sta = sta_info_get(local, ra);
if (!sta) {
printk(KERN_DEBUG "Could not find station: %s\n",
print_mac(mac, ra));
rcu_read_unlock();
return;
}
state = &sta->ampdu_mlme.tid_tx[tid].state;
@@ -750,13 +764,13 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
sta_info_put(sta);
spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
rcu_read_unlock();
return;
}
if (*state & HT_AGG_STATE_INITIATOR_MSK)
ieee80211_send_delba(sta->dev, ra, tid,
ieee80211_send_delba(sta->sdata->dev, ra, tid,
WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
agg_queue = sta->tid_to_tx_q[tid];
@@ -777,7 +791,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0;
spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
sta_info_put(sta);
rcu_read_unlock();
}
EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
@@ -887,32 +901,41 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
struct sta_info *sta;
DECLARE_MAC_BUF(mac);
might_sleep();
if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0)
return 0;
rcu_read_lock();
/* Create STA entry for the new peer */
sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL);
if (IS_ERR(sta))
sta = sta_info_add(sdata, remote_addr);
if (IS_ERR(sta)) {
rcu_read_unlock();
return PTR_ERR(sta);
}
sta->flags |= WLAN_STA_AUTHORIZED;
sta_info_put(sta);
/* Remove STA entry for the old peer */
sta = sta_info_get(local, sdata->u.wds.remote_addr);
if (sta) {
sta_info_free(sta);
sta_info_put(sta);
} else {
if (sta)
sta_info_unlink(&sta);
else
printk(KERN_DEBUG "%s: could not find STA entry for WDS link "
"peer %s\n",
dev->name, print_mac(mac, sdata->u.wds.remote_addr));
}
/* Update WDS link data */
memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN);
rcu_read_unlock();
if (sta) {
synchronize_rcu();
sta_info_destroy(sta);
}
return 0;
}
@@ -1330,6 +1353,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
return;
}
rcu_read_lock();
if (status->excessive_retries) {
struct sta_info *sta;
sta = sta_info_get(local, hdr->addr1);
@@ -1343,10 +1368,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
status->flags |= IEEE80211_TX_STATUS_TX_FILTERED;
ieee80211_handle_filtered_frame(local, sta,
skb, status);
sta_info_put(sta);
rcu_read_unlock();
return;
}
sta_info_put(sta);
}
}
@@ -1356,12 +1380,14 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
if (sta) {
ieee80211_handle_filtered_frame(local, sta, skb,
status);
sta_info_put(sta);
rcu_read_unlock();
return;
}
} else
rate_control_tx_status(local->mdev, skb, status);
rcu_read_unlock();
ieee80211_led_tx(local, 0);
/* SNMP counters
+10 -3
View File
@@ -574,6 +574,7 @@ struct ieee80211_local {
unsigned int filter_flags; /* FIF_* */
struct iw_statistics wstats;
u8 wstats_flags;
bool tim_in_locked_section; /* see ieee80211_beacon_get() */
int tx_headroom; /* required headroom for hardware/radiotap */
enum {
@@ -591,9 +592,15 @@ struct ieee80211_local {
struct sk_buff_head skb_queue;
struct sk_buff_head skb_queue_unreliable;
/* Station data structures */
rwlock_t sta_lock; /* protects STA data structures */
int num_sta; /* number of stations in sta_list */
/* Station data */
/*
* The lock only protects the list, hash, timer and counter
* against manipulation, reads are done in RCU. Additionally,
* the lock protects each BSS's TIM bitmap and a few items
* in a STA info structure.
*/
spinlock_t sta_lock;
unsigned long num_sta;
struct list_head sta_list;
struct sta_info *sta_hash[STA_HASH_SIZE];
struct timer_list sta_cleanup;
+8 -3
View File
@@ -240,16 +240,21 @@ void ieee80211_if_reinit(struct net_device *dev)
break;
}
case IEEE80211_IF_TYPE_WDS:
rcu_read_lock();
sta = sta_info_get(local, sdata->u.wds.remote_addr);
if (sta) {
sta_info_free(sta);
sta_info_put(sta);
sta_info_unlink(&sta);
} else {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
printk(KERN_DEBUG "%s: Someone had deleted my STA "
"entry for the WDS link\n", dev->name);
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
}
rcu_read_unlock();
if (sta) {
synchronize_rcu();
sta_info_destroy(sta);
}
break;
case IEEE80211_IF_TYPE_MESH_POINT:
case IEEE80211_IF_TYPE_STA:
@@ -275,7 +280,7 @@ void ieee80211_if_reinit(struct net_device *dev)
}
/* remove all STAs that are bound to this virtual interface */
sta_info_flush(local, dev);
sta_info_flush(local, sdata);
memset(&sdata->u, 0, sizeof(sdata->u));
ieee80211_if_sdata_init(sdata);
+15 -27
View File
@@ -33,8 +33,7 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
size_t key_len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
int ret;
struct sta_info *sta = NULL;
struct sta_info *sta;
struct ieee80211_key *key;
struct ieee80211_sub_if_data *sdata;
@@ -51,24 +50,23 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
key = sdata->keys[idx];
} else {
sta = sta_info_get(local, sta_addr);
if (!sta) {
ret = -ENOENT;
key = NULL;
goto err_out;
}
if (!sta)
return -ENOENT;
key = sta->key;
}
if (!key)
ret = -ENOENT;
else
ret = 0;
return -ENOENT;
ieee80211_key_free(key);
return 0;
} else {
key = ieee80211_key_alloc(alg, idx, key_len, _key);
if (!key)
return -ENOMEM;
sta = NULL;
if (!is_broadcast_ether_addr(sta_addr)) {
set_tx_key = 0;
/*
@@ -78,14 +76,14 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
* work around this.
*/
if (idx != 0 && alg != ALG_WEP) {
ret = -EINVAL;
goto err_out;
ieee80211_key_free(key);
return -EINVAL;
}
sta = sta_info_get(local, sta_addr);
if (!sta) {
ret = -ENOENT;
goto err_out;
ieee80211_key_free(key);
return -ENOENT;
}
}
@@ -93,18 +91,9 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
if (set_tx_key || (!sta && !sdata->default_key && key))
ieee80211_set_default_key(sdata, idx);
/* don't free key later */
key = NULL;
ret = 0;
}
err_out:
if (sta)
sta_info_put(sta);
ieee80211_key_free(key);
return ret;
return 0;
}
static int ieee80211_ioctl_siwgenie(struct net_device *dev,
@@ -625,7 +614,7 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev,
else
rate->value = 0;
rate->value *= 100000;
sta_info_put(sta);
return 0;
}
@@ -1000,7 +989,6 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
wstats->qual.qual = sta->last_signal;
wstats->qual.noise = sta->last_noise;
wstats->qual.updated = local->wstats_flags;
sta_info_put(sta);
}
return wstats;
}
+5 -3
View File
@@ -170,9 +170,12 @@ void rate_control_get_rate(struct net_device *dev,
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct rate_control_ref *ref = local->rate_ctrl;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct sta_info *sta = sta_info_get(local, hdr->addr1);
struct sta_info *sta;
int i;
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
memset(sel, 0, sizeof(struct rate_selection));
ref->ops->get_rate(ref->priv, dev, sband, skb, sel);
@@ -190,8 +193,7 @@ void rate_control_get_rate(struct net_device *dev,
}
}
if (sta)
sta_info_put(sta);
rcu_read_unlock();
}
struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
+1
View File
@@ -14,6 +14,7 @@
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/types.h>
#include <linux/kref.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
#include "sta_info.h"
+85 -38
View File
@@ -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;
}
+7 -1
View File
@@ -240,14 +240,17 @@ void ieee80211_key_link(struct ieee80211_key *key,
if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
struct sta_info *ap;
rcu_read_lock();
/* same here, the AP could be using QoS */
ap = sta_info_get(key->local, key->sdata->u.sta.bssid);
if (ap) {
if (ap->flags & WLAN_STA_WME)
key->conf.flags |=
IEEE80211_KEY_FLAG_WMM_STA;
sta_info_put(ap);
}
rcu_read_unlock();
}
}
@@ -290,6 +293,9 @@ void ieee80211_key_free(struct ieee80211_key *key)
__ieee80211_key_replace(key->sdata, key->sta,
key, NULL);
/*
* Do NOT remove this without looking at sta_info_destroy()
*/
synchronize_rcu();
/*
+2 -3
View File
@@ -83,11 +83,10 @@ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie,
/**
* mesh_accept_plinks_update: update accepting_plink in local mesh beacons
*
* @dev: mesh interface in which mesh beacons are going to be updated
* @sdata: mesh interface in which mesh beacons are going to be updated
*/
void mesh_accept_plinks_update(struct net_device *dev)
void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
bool free_plinks;
/* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0,
+9 -7
View File
@@ -65,9 +65,10 @@ enum mesh_path_flags {
* @state_lock: mesh pat state lock
*
*
* The combination of dst and dev is unique in the mesh path table. A reference
* to the next_hop sta will be kept and in case this sta is removed, the
* mesh_path structure must be also removed or substitued in a rcu safe way
* The combination of dst and dev is unique in the mesh path table. Since the
* next_hop STA is only protected by RCU as well, deleting the STA must also
* remove/substitute the mesh_path structure and wait until that is no longer
* reachable before destroying the STA completely.
*/
struct mesh_path {
u8 dst[ETH_ALEN];
@@ -230,8 +231,9 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev,
bool add);
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie,
struct net_device *dev);
void mesh_accept_plinks_update(struct net_device *dev);
struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev);
void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates,
struct ieee80211_sub_if_data *sdata);
void mesh_plink_broken(struct sta_info *sta);
void mesh_plink_deactivate(struct sta_info *sta);
int mesh_plink_open(struct sta_info *sta);
@@ -254,7 +256,7 @@ void mesh_path_flush_pending(struct mesh_path *mpath);
void mesh_path_tx_pending(struct mesh_path *mpath);
int mesh_pathtbl_init(void);
void mesh_pathtbl_unregister(void);
int mesh_path_del(u8 *addr, struct net_device *dev);
int mesh_path_del(u8 *addr, struct net_device *dev, bool force);
void mesh_path_timer(unsigned long data);
void mesh_path_flush_by_nexthop(struct sta_info *sta);
void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev);
@@ -270,7 +272,7 @@ static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata)
static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata)
{
return (min(mesh_plink_free_count(sdata),
return (min_t(long, mesh_plink_free_count(sdata),
MESH_MAX_PLINKS - sdata->local->num_sta)) > 0;
}
+1 -5
View File
@@ -294,7 +294,6 @@ static u32 hwmp_route_info_get(struct net_device *dev,
orig_metric = PREP_IE_METRIC(hwmp_ie);
break;
default:
sta_info_put(sta);
rcu_read_unlock();
return 0;
}
@@ -330,7 +329,6 @@ static u32 hwmp_route_info_get(struct net_device *dev,
mpath = mesh_path_lookup(orig_addr, dev);
if (!mpath) {
rcu_read_unlock();
sta_info_put(sta);
return 0;
}
spin_lock_bh(&mpath->state_lock);
@@ -372,7 +370,6 @@ static u32 hwmp_route_info_get(struct net_device *dev,
mpath = mesh_path_lookup(ta, dev);
if (!mpath) {
rcu_read_unlock();
sta_info_put(sta);
return 0;
}
spin_lock_bh(&mpath->state_lock);
@@ -391,7 +388,6 @@ static u32 hwmp_route_info_get(struct net_device *dev,
spin_unlock_bh(&mpath->state_lock);
}
sta_info_put(sta);
rcu_read_unlock();
return process ? new_metric : 0;
@@ -861,5 +857,5 @@ void mesh_path_timer(unsigned long data)
endmpathtimer:
rcu_read_unlock();
if (delete)
mesh_path_del(mpath->dst, mpath->dev);
mesh_path_del(mpath->dst, mpath->dev, false);
}
+14 -16
View File
@@ -55,10 +55,7 @@ static DEFINE_RWLOCK(pathtbl_resize_lock);
*/
void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
{
__sta_info_get(sta);
if (mpath->next_hop)
sta_info_put(mpath->next_hop);
mpath->next_hop = sta;
rcu_assign_pointer(mpath->next_hop, sta);
}
@@ -236,7 +233,7 @@ void mesh_plink_broken(struct sta_info *sta)
struct mesh_path *mpath;
struct mpath_node *node;
struct hlist_node *p;
struct net_device *dev = sta->dev;
struct net_device *dev = sta->sdata->dev;
int i;
rcu_read_lock();
@@ -266,9 +263,9 @@ EXPORT_SYMBOL(mesh_plink_broken);
*
* RCU notes: this function is called when a mesh plink transitions from ESTAB
* to any other state, since ESTAB state is the only one that allows path
* creation. This will happen before the sta can be freed (since we hold
* a reference to it) so any reader in a rcu read block will be protected
* against the plink dissapearing.
* creation. This will happen before the sta can be freed (because
* sta_info_destroy() calls this) so any reader in a rcu read block will be
* protected against the plink disappearing.
*/
void mesh_path_flush_by_nexthop(struct sta_info *sta)
{
@@ -280,7 +277,7 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
for_each_mesh_entry(mesh_paths, p, node, i) {
mpath = node->mpath;
if (mpath->next_hop == sta)
mesh_path_del(mpath->dst, mpath->dev);
mesh_path_del(mpath->dst, mpath->dev, true);
}
}
@@ -294,7 +291,7 @@ void mesh_path_flush(struct net_device *dev)
for_each_mesh_entry(mesh_paths, p, node, i) {
mpath = node->mpath;
if (mpath->dev == dev)
mesh_path_del(mpath->dst, mpath->dev);
mesh_path_del(mpath->dst, mpath->dev, false);
}
}
@@ -303,8 +300,8 @@ static void mesh_path_node_reclaim(struct rcu_head *rp)
struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
struct ieee80211_sub_if_data *sdata =
IEEE80211_DEV_TO_SUB_IF(node->mpath->dev);
if (node->mpath->next_hop)
sta_info_put(node->mpath->next_hop);
rcu_assign_pointer(node->mpath->next_hop, NULL);
atomic_dec(&sdata->u.sta.mpaths);
kfree(node->mpath);
kfree(node);
@@ -319,9 +316,10 @@ static void mesh_path_node_reclaim(struct rcu_head *rp)
* Returns: 0 if succesful
*
* State: if the path is being resolved, the deletion will be postponed until
* the path resolution completes or times out.
* the path resolution completes or times out, unless the force parameter
* is given.
*/
int mesh_path_del(u8 *addr, struct net_device *dev)
int mesh_path_del(u8 *addr, struct net_device *dev, bool force)
{
struct mesh_path *mpath;
struct mpath_node *node;
@@ -340,7 +338,7 @@ int mesh_path_del(u8 *addr, struct net_device *dev)
if (mpath->dev == dev &&
memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
spin_lock_bh(&mpath->state_lock);
if (mpath->flags & MESH_PATH_RESOLVING) {
if (!force && mpath->flags & MESH_PATH_RESOLVING) {
mpath->flags |= MESH_PATH_DELETE;
} else {
mpath->flags |= MESH_PATH_RESOLVING;
@@ -510,7 +508,7 @@ void mesh_path_expire(struct net_device *dev)
time_after(jiffies,
mpath->exp_time + MESH_PATH_EXPIRE)) {
spin_unlock_bh(&mpath->state_lock);
mesh_path_del(mpath->dst, mpath->dev);
mesh_path_del(mpath->dst, mpath->dev, false);
} else
spin_unlock_bh(&mpath->state_lock);
}
+52 -49
View File
@@ -65,14 +65,14 @@ static inline
void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
{
atomic_inc(&sdata->u.sta.mshstats.estab_plinks);
mesh_accept_plinks_update(sdata->dev);
mesh_accept_plinks_update(sdata);
}
static inline
void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
{
atomic_dec(&sdata->u.sta.mshstats.estab_plinks);
mesh_accept_plinks_update(sdata->dev);
mesh_accept_plinks_update(sdata);
}
/**
@@ -99,12 +99,13 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta)
*
* Returns: non-NULL on success, ERR_PTR() on error.
*/
struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev)
struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates,
struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
if (memcmp(hw_addr, dev->dev_addr, ETH_ALEN) == 0)
if (compare_ether_addr(hw_addr, sdata->dev->dev_addr) == 0)
/* never add ourselves as neighbours */
return ERR_PTR(-EINVAL);
@@ -114,7 +115,7 @@ struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev)
if (local->num_sta >= MESH_MAX_PLINKS)
return ERR_PTR(-ENOSPC);
sta = sta_info_add(local, dev, hw_addr, GFP_KERNEL);
sta = sta_info_add(sdata, hw_addr);
if (IS_ERR(sta))
return sta;
@@ -125,7 +126,7 @@ struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev)
sta->supp_rates[local->hw.conf.channel->band] = rates;
rate_control_rate_init(sta, local);
mesh_accept_plinks_update(dev);
mesh_accept_plinks_update(sdata);
return sta;
}
@@ -141,7 +142,8 @@ struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev)
*/
static void __mesh_plink_deactivate(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
struct ieee80211_sub_if_data *sdata = sta->sdata;
if (sta->plink_state == ESTAB)
mesh_plink_dec_estab_count(sdata);
sta->plink_state = BLOCKED;
@@ -246,11 +248,15 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev,
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
rcu_read_lock();
sta = sta_info_get(local, hw_addr);
if (!sta) {
sta = mesh_plink_add(hw_addr, rates, dev);
if (IS_ERR(sta))
sta = mesh_plink_add(hw_addr, rates, sdata);
if (IS_ERR(sta)) {
rcu_read_unlock();
return;
}
}
sta->last_rx = jiffies;
@@ -260,7 +266,7 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev,
sdata->u.sta.mshcfg.auto_open_plinks)
mesh_plink_open(sta);
sta_info_put(sta);
rcu_read_unlock();
}
static void mesh_plink_timer(unsigned long data)
@@ -273,6 +279,11 @@ static void mesh_plink_timer(unsigned long data)
DECLARE_MAC_BUF(mac);
#endif
/*
* This STA is valid because sta_info_destroy() will
* del_timer_sync() this timer after having made sure
* it cannot be readded (by deleting the plink.)
*/
sta = (struct sta_info *) data;
spin_lock_bh(&sta->plink_lock);
@@ -286,8 +297,8 @@ static void mesh_plink_timer(unsigned long data)
reason = 0;
llid = sta->llid;
plid = sta->plid;
dev = sta->dev;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
sdata = sta->sdata;
dev = sdata->dev;
switch (sta->plink_state) {
case OPN_RCVD:
@@ -302,8 +313,7 @@ static void mesh_plink_timer(unsigned long data)
sta->plink_timeout = sta->plink_timeout +
rand % sta->plink_timeout;
++sta->plink_retries;
if (!mod_plink_timer(sta, sta->plink_timeout))
__sta_info_get(sta);
mod_plink_timer(sta, sta->plink_timeout);
spin_unlock_bh(&sta->plink_lock);
mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
0, 0);
@@ -316,16 +326,14 @@ static void mesh_plink_timer(unsigned long data)
if (!reason)
reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT);
sta->plink_state = HOLDING;
if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)))
__sta_info_get(sta);
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
spin_unlock_bh(&sta->plink_lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid,
reason);
break;
case HOLDING:
/* holding timer */
if (del_timer(&sta->plink_timer))
sta_info_put(sta);
del_timer(&sta->plink_timer);
mesh_plink_fsm_restart(sta);
spin_unlock_bh(&sta->plink_lock);
break;
@@ -333,8 +341,6 @@ static void mesh_plink_timer(unsigned long data)
spin_unlock_bh(&sta->plink_lock);
break;
}
sta_info_put(sta);
}
static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
@@ -343,14 +349,13 @@ static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
sta->plink_timer.data = (unsigned long) sta;
sta->plink_timer.function = mesh_plink_timer;
sta->plink_timeout = timeout;
__sta_info_get(sta);
add_timer(&sta->plink_timer);
}
int mesh_plink_open(struct sta_info *sta)
{
__le16 llid;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
struct ieee80211_sub_if_data *sdata = sta->sdata;
#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
DECLARE_MAC_BUF(mac);
#endif
@@ -360,7 +365,6 @@ int mesh_plink_open(struct sta_info *sta)
sta->llid = llid;
if (sta->plink_state != LISTEN) {
spin_unlock_bh(&sta->plink_lock);
sta_info_put(sta);
return -EBUSY;
}
sta->plink_state = OPN_SNT;
@@ -369,7 +373,8 @@ int mesh_plink_open(struct sta_info *sta)
mpl_dbg("Mesh plink: starting establishment with %s\n",
print_mac(mac, sta->addr));
return mesh_plink_frame_tx(sta->dev, PLINK_OPEN, sta->addr, llid, 0, 0);
return mesh_plink_frame_tx(sdata->dev, PLINK_OPEN,
sta->addr, llid, 0, 0);
}
void mesh_plink_block(struct sta_info *sta)
@@ -386,7 +391,7 @@ void mesh_plink_block(struct sta_info *sta)
int mesh_plink_close(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
struct ieee80211_sub_if_data *sdata = sta->sdata;
int llid, plid, reason;
#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
DECLARE_MAC_BUF(mac);
@@ -401,13 +406,11 @@ int mesh_plink_close(struct sta_info *sta)
if (sta->plink_state == LISTEN || sta->plink_state == BLOCKED) {
mesh_plink_fsm_restart(sta);
spin_unlock_bh(&sta->plink_lock);
sta_info_put(sta);
return 0;
} else if (sta->plink_state == ESTAB) {
__mesh_plink_deactivate(sta);
/* The timer should not be running */
if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)))
__sta_info_get(sta);
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
} else if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)))
sta->ignore_plink_timer = true;
@@ -415,15 +418,16 @@ int mesh_plink_close(struct sta_info *sta)
llid = sta->llid;
plid = sta->plid;
spin_unlock_bh(&sta->plink_lock);
mesh_plink_frame_tx(sta->dev, PLINK_CLOSE, sta->addr, llid, plid,
reason);
mesh_plink_frame_tx(sta->sdata->dev, PLINK_CLOSE, sta->addr, llid,
plid, reason);
return 0;
}
void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
size_t len, struct ieee80211_rx_status *rx_status)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
struct ieee802_11_elems elems;
struct sta_info *sta;
enum plink_event event;
@@ -435,7 +439,6 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
DECLARE_MAC_BUF(mac);
#endif
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (is_multicast_ether_addr(mgmt->da)) {
mpl_dbg("Mesh plink: ignore frame from multicast address");
@@ -474,14 +477,17 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7))
memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2);
rcu_read_lock();
sta = sta_info_get(local, mgmt->sa);
if (!sta && ftype != PLINK_OPEN) {
mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
rcu_read_unlock();
return;
}
if (sta && sta->plink_state == BLOCKED) {
sta_info_put(sta);
rcu_read_unlock();
return;
}
@@ -505,13 +511,15 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
u64 rates;
if (!mesh_plink_free_count(sdata)) {
mpl_dbg("Mesh plink error: no more free plinks\n");
rcu_read_unlock();
return;
}
rates = ieee80211_sta_get_rates(local, &elems, rx_status->band);
sta = mesh_plink_add(mgmt->sa, rates, dev);
sta = mesh_plink_add(mgmt->sa, rates, sdata);
if (IS_ERR(sta)) {
mpl_dbg("Mesh plink error: plink table full\n");
rcu_read_unlock();
return;
}
event = OPN_ACPT;
@@ -521,14 +529,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
switch (ftype) {
case PLINK_OPEN:
if (!mesh_plink_free_count(sdata) ||
(sta->plid && sta->plid != plid))
(sta->plid && sta->plid != plid))
event = OPN_IGNR;
else
event = OPN_ACPT;
break;
case PLINK_CONFIRM:
if (!mesh_plink_free_count(sdata) ||
(sta->llid != llid || sta->plid != plid))
(sta->llid != llid || sta->plid != plid))
event = CNF_IGNR;
else
event = CNF_ACPT;
@@ -555,7 +563,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
default:
mpl_dbg("Mesh plink: unknown frame subtype\n");
spin_unlock_bh(&sta->plink_lock);
sta_info_put(sta);
rcu_read_unlock();
return;
}
}
@@ -659,8 +667,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
plid, 0);
break;
case CNF_ACPT:
if (del_timer(&sta->plink_timer))
sta_info_put(sta);
del_timer(&sta->plink_timer);
sta->plink_state = ESTAB;
mesh_plink_inc_estab_count(sdata);
spin_unlock_bh(&sta->plink_lock);
@@ -693,8 +700,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
plid, reason);
break;
case OPN_ACPT:
if (del_timer(&sta->plink_timer))
sta_info_put(sta);
del_timer(&sta->plink_timer);
sta->plink_state = ESTAB;
mesh_plink_inc_estab_count(sdata);
spin_unlock_bh(&sta->plink_lock);
@@ -717,9 +723,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
__mesh_plink_deactivate(sta);
sta->plink_state = HOLDING;
llid = sta->llid;
if (!mod_plink_timer(sta,
dot11MeshHoldingTimeout(sdata)))
__sta_info_get(sta);
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
spin_unlock_bh(&sta->plink_lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason);
@@ -738,10 +742,8 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
case HOLDING:
switch (event) {
case CLS_ACPT:
if (del_timer(&sta->plink_timer)) {
if (del_timer(&sta->plink_timer))
sta->ignore_plink_timer = 1;
sta_info_put(sta);
}
mesh_plink_fsm_restart(sta);
spin_unlock_bh(&sta->plink_lock);
break;
@@ -766,5 +768,6 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
spin_unlock_bh(&sta->plink_lock);
break;
}
sta_info_put(sta);
rcu_read_unlock();
}
+14 -11
View File
@@ -77,7 +77,7 @@ static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
int cur_sorted, new_sorted, probe, tmp, n_bitrates, band;
int cur = sta->txrate_idx;
sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
sdata = sta->sdata;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
band = sband->band;
n_bitrates = sband->n_bitrates;
@@ -149,7 +149,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
struct sta_info *sta)
{
#ifdef CONFIG_MAC80211_MESH
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
struct ieee80211_sub_if_data *sdata = sta->sdata;
#endif
struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv;
struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
@@ -249,23 +249,25 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
unsigned long period;
struct ieee80211_supported_band *sband;
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
if (!sta)
return;
goto unlock;
/* Don't update the state if we're not controlling the rate. */
sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
sdata = sta->sdata;
if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
sta->txrate_idx = sdata->bss->max_ratectrl_rateidx;
return;
goto unlock;
}
/* Ignore all frames that were sent with a different rate than the rate
* we currently advise mac80211 to use. */
if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx])
goto ignore;
goto unlock;
spinfo = sta->rate_ctrl_priv;
spinfo->tx_num_xmit++;
@@ -303,8 +305,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
if (time_after(jiffies, spinfo->last_sample + period))
rate_control_pid_sample(pinfo, local, sta);
ignore:
sta_info_put(sta);
unlock:
rcu_read_unlock();
}
static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
@@ -319,6 +321,8 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
int rateidx;
u16 fc;
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
/* Send management frames and broadcast/multicast data using lowest
@@ -327,8 +331,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
is_multicast_ether_addr(hdr->addr1) || !sta) {
sel->rate = rate_lowest(local, sband, sta);
if (sta)
sta_info_put(sta);
rcu_read_unlock();
return;
}
@@ -344,7 +347,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
sta->last_txrate_idx = rateidx;
sta_info_put(sta);
rcu_read_unlock();
sel->rate = &sband->bitrates[rateidx];
+11 -7
View File
@@ -40,7 +40,7 @@ static void rate_control_rate_inc(struct ieee80211_local *local,
int i = sta->txrate_idx;
int maxrate;
sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
sdata = sta->sdata;
if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
/* forced unicast rate - do not change STA rate */
return;
@@ -70,7 +70,7 @@ static void rate_control_rate_dec(struct ieee80211_local *local,
struct ieee80211_supported_band *sband;
int i = sta->txrate_idx;
sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
sdata = sta->sdata;
if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
/* forced unicast rate - do not change STA rate */
return;
@@ -118,10 +118,12 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
struct sta_info *sta;
struct sta_rate_control *srctrl;
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
if (!sta)
return;
goto unlock;
srctrl = sta->rate_ctrl_priv;
srctrl->tx_num_xmit++;
@@ -191,7 +193,8 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
}
}
sta_info_put(sta);
unlock:
rcu_read_unlock();
}
@@ -208,6 +211,8 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev,
int rateidx;
u16 fc;
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
/* Send management frames and broadcast/multicast data using lowest
@@ -216,8 +221,7 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev,
if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
is_multicast_ether_addr(hdr->addr1) || !sta) {
sel->rate = rate_lowest(local, sband, sta);
if (sta)
sta_info_put(sta);
rcu_read_unlock();
return;
}
@@ -233,7 +237,7 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev,
sta->last_txrate_idx = rateidx;
sta_info_put(sta);
rcu_read_unlock();
sel->rate = &sband->bitrates[rateidx];
}

Some files were not shown because too many files have changed in this diff Show More