mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts: Documentation/feature-removal-schedule.txt drivers/net/wireless/ipw2x00/ipw2200.c
This commit is contained in:
commit
e9a68707d7
146 changed files with 4232 additions and 4192 deletions
|
|
@ -56,7 +56,7 @@ static void ieee80211_free_tid_rx(struct rcu_head *h)
|
|||
}
|
||||
|
||||
void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||
u16 initiator, u16 reason)
|
||||
u16 initiator, u16 reason, bool tx)
|
||||
{
|
||||
struct ieee80211_local *local = sta->local;
|
||||
struct tid_ampdu_rx *tid_rx;
|
||||
|
|
@ -81,7 +81,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
|||
"aggregation for tid %d\n", tid);
|
||||
|
||||
/* check if this is a self generated aggregation halt */
|
||||
if (initiator == WLAN_BACK_RECIPIENT)
|
||||
if (initiator == WLAN_BACK_RECIPIENT && tx)
|
||||
ieee80211_send_delba(sta->sdata, sta->sta.addr,
|
||||
tid, 0, reason);
|
||||
|
||||
|
|
@ -92,10 +92,10 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
|||
}
|
||||
|
||||
void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||
u16 initiator, u16 reason)
|
||||
u16 initiator, u16 reason, bool tx)
|
||||
{
|
||||
mutex_lock(&sta->ampdu_mlme.mtx);
|
||||
___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason);
|
||||
___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason, tx);
|
||||
mutex_unlock(&sta->ampdu_mlme.mtx);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,8 @@ static void kfree_tid_tx(struct rcu_head *rcu_head)
|
|||
}
|
||||
|
||||
int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
enum ieee80211_back_parties initiator)
|
||||
enum ieee80211_back_parties initiator,
|
||||
bool tx)
|
||||
{
|
||||
struct ieee80211_local *local = sta->local;
|
||||
struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
|
||||
|
|
@ -175,6 +176,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
|||
|
||||
set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
|
||||
|
||||
del_timer_sync(&tid_tx->addba_resp_timer);
|
||||
|
||||
/*
|
||||
* After this packets are no longer handed right through
|
||||
* to the driver but are put onto tid_tx->pending instead,
|
||||
|
|
@ -183,6 +186,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
|||
clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
|
||||
|
||||
tid_tx->stop_initiator = initiator;
|
||||
tid_tx->tx_stop = tx;
|
||||
|
||||
ret = drv_ampdu_action(local, sta->sdata,
|
||||
IEEE80211_AMPDU_TX_STOP,
|
||||
|
|
@ -575,13 +579,14 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
|
|||
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
|
||||
|
||||
int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
enum ieee80211_back_parties initiator)
|
||||
enum ieee80211_back_parties initiator,
|
||||
bool tx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&sta->ampdu_mlme.mtx);
|
||||
|
||||
ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator);
|
||||
ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator, tx);
|
||||
|
||||
mutex_unlock(&sta->ampdu_mlme.mtx);
|
||||
|
||||
|
|
@ -670,7 +675,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
|
|||
goto unlock_sta;
|
||||
}
|
||||
|
||||
if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR)
|
||||
if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR && tid_tx->tx_stop)
|
||||
ieee80211_send_delba(sta->sdata, ra, tid,
|
||||
WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
|
||||
|
||||
|
|
@ -770,7 +775,8 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
|
|||
|
||||
sta->ampdu_mlme.addba_req_num[tid] = 0;
|
||||
} else {
|
||||
___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
|
||||
___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
|
||||
true);
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
|
|||
|
|
@ -68,14 +68,42 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
|
|||
params && params->use_4addr >= 0)
|
||||
sdata->u.mgd.use_4addr = params->use_4addr;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags)
|
||||
sdata->u.mntr_flags = *flags;
|
||||
if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) {
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
||||
if (ieee80211_sdata_running(sdata)) {
|
||||
/*
|
||||
* Prohibit MONITOR_FLAG_COOK_FRAMES to be
|
||||
* changed while the interface is up.
|
||||
* Else we would need to add a lot of cruft
|
||||
* to update everything:
|
||||
* cooked_mntrs, monitor and all fif_* counters
|
||||
* reconfigure hardware
|
||||
*/
|
||||
if ((*flags & MONITOR_FLAG_COOK_FRAMES) !=
|
||||
(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
|
||||
return -EBUSY;
|
||||
|
||||
ieee80211_adjust_monitor_flags(sdata, -1);
|
||||
sdata->u.mntr_flags = *flags;
|
||||
ieee80211_adjust_monitor_flags(sdata, 1);
|
||||
|
||||
ieee80211_configure_filter(local);
|
||||
} else {
|
||||
/*
|
||||
* Because the interface is down, ieee80211_do_stop
|
||||
* and ieee80211_do_open take care of "everything"
|
||||
* mentioned in the comment above.
|
||||
*/
|
||||
sdata->u.mntr_flags = *flags;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 key_idx, const u8 *mac_addr,
|
||||
u8 key_idx, bool pairwise, const u8 *mac_addr,
|
||||
struct key_params *params)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
|
@ -103,6 +131,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
|||
if (IS_ERR(key))
|
||||
return PTR_ERR(key);
|
||||
|
||||
if (pairwise)
|
||||
key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
|
||||
|
||||
mutex_lock(&sdata->local->sta_mtx);
|
||||
|
||||
if (mac_addr) {
|
||||
|
|
@ -125,7 +156,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
|
|||
}
|
||||
|
||||
static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 key_idx, const u8 *mac_addr)
|
||||
u8 key_idx, bool pairwise, const u8 *mac_addr)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct sta_info *sta;
|
||||
|
|
@ -142,10 +173,17 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
|
|||
if (!sta)
|
||||
goto out_unlock;
|
||||
|
||||
if (sta->key) {
|
||||
ieee80211_key_free(sdata->local, sta->key);
|
||||
WARN_ON(sta->key);
|
||||
ret = 0;
|
||||
if (pairwise) {
|
||||
if (sta->ptk) {
|
||||
ieee80211_key_free(sdata->local, sta->ptk);
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
if (sta->gtk[key_idx]) {
|
||||
ieee80211_key_free(sdata->local,
|
||||
sta->gtk[key_idx]);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
goto out_unlock;
|
||||
|
|
@ -167,7 +205,8 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
|
|||
}
|
||||
|
||||
static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 key_idx, const u8 *mac_addr, void *cookie,
|
||||
u8 key_idx, bool pairwise, const u8 *mac_addr,
|
||||
void *cookie,
|
||||
void (*callback)(void *cookie,
|
||||
struct key_params *params))
|
||||
{
|
||||
|
|
@ -175,7 +214,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
|||
struct sta_info *sta = NULL;
|
||||
u8 seq[6] = {0};
|
||||
struct key_params params;
|
||||
struct ieee80211_key *key;
|
||||
struct ieee80211_key *key = NULL;
|
||||
u32 iv32;
|
||||
u16 iv16;
|
||||
int err = -ENOENT;
|
||||
|
|
@ -189,7 +228,10 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
|||
if (!sta)
|
||||
goto out;
|
||||
|
||||
key = sta->key;
|
||||
if (pairwise)
|
||||
key = sta->ptk;
|
||||
else if (key_idx < NUM_DEFAULT_KEYS)
|
||||
key = sta->gtk[key_idx];
|
||||
} else
|
||||
key = sdata->keys[key_idx];
|
||||
|
||||
|
|
@ -285,6 +327,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
|
|||
STATION_INFO_TX_BYTES |
|
||||
STATION_INFO_RX_PACKETS |
|
||||
STATION_INFO_TX_PACKETS |
|
||||
STATION_INFO_TX_RETRIES |
|
||||
STATION_INFO_TX_FAILED |
|
||||
STATION_INFO_TX_BITRATE;
|
||||
|
||||
sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
|
||||
|
|
@ -292,6 +336,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
|
|||
sinfo->tx_bytes = sta->tx_bytes;
|
||||
sinfo->rx_packets = sta->rx_packets;
|
||||
sinfo->tx_packets = sta->tx_packets;
|
||||
sinfo->tx_retries = sta->tx_retry_count;
|
||||
sinfo->tx_failed = sta->tx_retry_failed;
|
||||
|
||||
if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ||
|
||||
(sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) {
|
||||
|
|
@ -1317,7 +1363,7 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm)
|
|||
}
|
||||
|
||||
static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
|
||||
u8 *addr)
|
||||
const u8 *addr)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
|
|
@ -1366,7 +1412,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
|
|||
if (!sdata->u.mgd.associated ||
|
||||
sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
|
||||
mutex_lock(&sdata->local->iflist_mtx);
|
||||
ieee80211_recalc_smps(sdata->local, sdata);
|
||||
ieee80211_recalc_smps(sdata->local);
|
||||
mutex_unlock(&sdata->local->iflist_mtx);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1521,7 +1567,11 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
|
|||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
if (!ieee80211_is_action(mgmt->frame_control) ||
|
||||
mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)
|
||||
break;
|
||||
rcu_read_lock();
|
||||
sta = sta_info_get(sdata, mgmt->da);
|
||||
|
|
@ -1530,6 +1580,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
|
|||
return -ENOLINK;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
|
|
|||
|
|
@ -196,7 +196,8 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu
|
|||
else
|
||||
ret = ieee80211_stop_tx_ba_session(&sta->sta, tid);
|
||||
} else {
|
||||
__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, 3);
|
||||
__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
|
||||
3, true);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,16 +101,16 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
|
|||
ht_cap->mcs.rx_mask[32/8] |= 1;
|
||||
}
|
||||
|
||||
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta)
|
||||
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx)
|
||||
{
|
||||
int i;
|
||||
|
||||
cancel_work_sync(&sta->ampdu_mlme.work);
|
||||
|
||||
for (i = 0; i < STA_TID_NUM; i++) {
|
||||
__ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR);
|
||||
__ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR, tx);
|
||||
__ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
|
||||
WLAN_REASON_QSTA_LEAVE_QBSS);
|
||||
WLAN_REASON_QSTA_LEAVE_QBSS, tx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -135,7 +135,7 @@ void ieee80211_ba_session_work(struct work_struct *work)
|
|||
if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired))
|
||||
___ieee80211_stop_rx_ba_session(
|
||||
sta, tid, WLAN_BACK_RECIPIENT,
|
||||
WLAN_REASON_QSTA_TIMEOUT);
|
||||
WLAN_REASON_QSTA_TIMEOUT, true);
|
||||
|
||||
tid_tx = sta->ampdu_mlme.tid_tx[tid];
|
||||
if (!tid_tx)
|
||||
|
|
@ -146,7 +146,8 @@ void ieee80211_ba_session_work(struct work_struct *work)
|
|||
else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP,
|
||||
&tid_tx->state))
|
||||
___ieee80211_stop_tx_ba_session(sta, tid,
|
||||
WLAN_BACK_INITIATOR);
|
||||
WLAN_BACK_INITIATOR,
|
||||
true);
|
||||
}
|
||||
mutex_unlock(&sta->ampdu_mlme.mtx);
|
||||
}
|
||||
|
|
@ -214,9 +215,11 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
|
|||
#endif /* CONFIG_MAC80211_HT_DEBUG */
|
||||
|
||||
if (initiator == WLAN_BACK_INITIATOR)
|
||||
__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0);
|
||||
__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0,
|
||||
true);
|
||||
else
|
||||
__ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT);
|
||||
__ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
|
||||
true);
|
||||
}
|
||||
|
||||
int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
|
|||
|
|
@ -173,6 +173,19 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
memcpy(skb_put(skb, ifibss->ie_len),
|
||||
ifibss->ie, ifibss->ie_len);
|
||||
|
||||
if (local->hw.queues >= 4) {
|
||||
pos = skb_put(skb, 9);
|
||||
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
|
||||
*pos++ = 7; /* len */
|
||||
*pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
|
||||
*pos++ = 0x50;
|
||||
*pos++ = 0xf2;
|
||||
*pos++ = 2; /* WME */
|
||||
*pos++ = 0; /* WME info */
|
||||
*pos++ = 1; /* WME ver */
|
||||
*pos++ = 0; /* U-APSD no in use */
|
||||
}
|
||||
|
||||
rcu_assign_pointer(ifibss->presp, skb);
|
||||
|
||||
sdata->vif.bss_conf.beacon_int = beacon_int;
|
||||
|
|
@ -266,37 +279,45 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
|
||||
return;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates &&
|
||||
if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
|
||||
memcmp(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) {
|
||||
supp_rates = ieee80211_sta_get_rates(local, elems, band);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = sta_info_get(sdata, mgmt->sa);
|
||||
if (sta) {
|
||||
u32 prev_rates;
|
||||
|
||||
prev_rates = sta->sta.supp_rates[band];
|
||||
/* make sure mandatory rates are always added */
|
||||
sta->sta.supp_rates[band] = supp_rates |
|
||||
ieee80211_mandatory_rates(local, band);
|
||||
if (elems->supp_rates) {
|
||||
supp_rates = ieee80211_sta_get_rates(local, elems,
|
||||
band);
|
||||
if (sta) {
|
||||
u32 prev_rates;
|
||||
|
||||
if (sta->sta.supp_rates[band] != prev_rates) {
|
||||
prev_rates = sta->sta.supp_rates[band];
|
||||
/* make sure mandatory rates are always added */
|
||||
sta->sta.supp_rates[band] = supp_rates |
|
||||
ieee80211_mandatory_rates(local, band);
|
||||
|
||||
if (sta->sta.supp_rates[band] != prev_rates) {
|
||||
#ifdef CONFIG_MAC80211_IBSS_DEBUG
|
||||
printk(KERN_DEBUG "%s: updated supp_rates set "
|
||||
"for %pM based on beacon/probe_response "
|
||||
"(0x%x -> 0x%x)\n",
|
||||
sdata->name, sta->sta.addr,
|
||||
prev_rates, sta->sta.supp_rates[band]);
|
||||
printk(KERN_DEBUG
|
||||
"%s: updated supp_rates set "
|
||||
"for %pM based on beacon"
|
||||
"/probe_resp (0x%x -> 0x%x)\n",
|
||||
sdata->name, sta->sta.addr,
|
||||
prev_rates,
|
||||
sta->sta.supp_rates[band]);
|
||||
#endif
|
||||
rate_control_rate_init(sta);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
} else {
|
||||
rcu_read_unlock();
|
||||
ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
|
||||
supp_rates, GFP_KERNEL);
|
||||
rate_control_rate_init(sta);
|
||||
}
|
||||
} else
|
||||
sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
|
||||
mgmt->sa, supp_rates,
|
||||
GFP_ATOMIC);
|
||||
}
|
||||
|
||||
if (sta && elems->wmm_info)
|
||||
set_sta_flags(sta, WLAN_STA_WME);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
|
||||
|
|
|
|||
|
|
@ -369,6 +369,7 @@ struct ieee80211_if_managed {
|
|||
|
||||
unsigned int flags;
|
||||
|
||||
bool beacon_crc_valid;
|
||||
u32 beacon_crc;
|
||||
|
||||
enum {
|
||||
|
|
@ -548,8 +549,6 @@ struct ieee80211_sub_if_data {
|
|||
struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
|
||||
unsigned int fragment_next;
|
||||
|
||||
#define NUM_DEFAULT_KEYS 4
|
||||
#define NUM_DEFAULT_MGMT_KEYS 2
|
||||
struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
|
||||
struct ieee80211_key *default_key;
|
||||
struct ieee80211_key *default_mgmt_key;
|
||||
|
|
@ -1132,6 +1131,8 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
|
|||
void ieee80211_remove_interfaces(struct ieee80211_local *local);
|
||||
u32 __ieee80211_recalc_idle(struct ieee80211_local *local);
|
||||
void ieee80211_recalc_idle(struct ieee80211_local *local);
|
||||
void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
|
||||
const int offset);
|
||||
|
||||
static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
|
|
@ -1172,10 +1173,10 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
|
|||
void ieee80211_request_smps_work(struct work_struct *work);
|
||||
|
||||
void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||
u16 initiator, u16 reason);
|
||||
u16 initiator, u16 reason, bool stop);
|
||||
void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||
u16 initiator, u16 reason);
|
||||
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta);
|
||||
u16 initiator, u16 reason, bool stop);
|
||||
void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx);
|
||||
void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta,
|
||||
struct ieee80211_mgmt *mgmt, size_t len);
|
||||
|
|
@ -1189,9 +1190,11 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
|
|||
size_t len);
|
||||
|
||||
int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
enum ieee80211_back_parties initiator);
|
||||
enum ieee80211_back_parties initiator,
|
||||
bool tx);
|
||||
int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
enum ieee80211_back_parties initiator);
|
||||
enum ieee80211_back_parties initiator,
|
||||
bool tx);
|
||||
void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid);
|
||||
void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid);
|
||||
void ieee80211_ba_session_work(struct work_struct *work);
|
||||
|
|
@ -1294,8 +1297,7 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
|
|||
enum ieee80211_band band);
|
||||
int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_smps_mode smps_mode);
|
||||
void ieee80211_recalc_smps(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *forsdata);
|
||||
void ieee80211_recalc_smps(struct ieee80211_local *local);
|
||||
|
||||
size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
|
||||
const u8 *ids, int n_ids, size_t offset);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "led.h"
|
||||
#include "driver-ops.h"
|
||||
#include "wme.h"
|
||||
#include "rate.h"
|
||||
|
||||
/**
|
||||
* DOC: Interface list locking
|
||||
|
|
@ -148,6 +149,26 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
|
||||
const int offset)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
u32 flags = sdata->u.mntr_flags;
|
||||
|
||||
#define ADJUST(_f, _s) do { \
|
||||
if (flags & MONITOR_FLAG_##_f) \
|
||||
local->fif_##_s += offset; \
|
||||
} while (0)
|
||||
|
||||
ADJUST(FCSFAIL, fcsfail);
|
||||
ADJUST(PLCPFAIL, plcpfail);
|
||||
ADJUST(CONTROL, control);
|
||||
ADJUST(CONTROL, pspoll);
|
||||
ADJUST(OTHER_BSS, other_bss);
|
||||
|
||||
#undef ADJUST
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: Be very careful when changing this function, it must NOT return
|
||||
* an error on interface type changes that have been pre-checked, so most
|
||||
|
|
@ -240,17 +261,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
|
|||
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
|
||||
}
|
||||
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
|
||||
local->fif_fcsfail++;
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
|
||||
local->fif_plcpfail++;
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) {
|
||||
local->fif_control++;
|
||||
local->fif_pspoll++;
|
||||
}
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
|
||||
local->fif_other_bss++;
|
||||
|
||||
ieee80211_adjust_monitor_flags(sdata, 1);
|
||||
ieee80211_configure_filter(local);
|
||||
|
||||
netif_carrier_on(dev);
|
||||
|
|
@ -301,6 +312,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
|
|||
/* STA has been freed */
|
||||
goto err_del_interface;
|
||||
}
|
||||
|
||||
rate_control_rate_init(sta);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -477,17 +490,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
|||
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
|
||||
}
|
||||
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
|
||||
local->fif_fcsfail--;
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
|
||||
local->fif_plcpfail--;
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) {
|
||||
local->fif_pspoll--;
|
||||
local->fif_control--;
|
||||
}
|
||||
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
|
||||
local->fif_other_bss--;
|
||||
|
||||
ieee80211_adjust_monitor_flags(sdata, -1);
|
||||
ieee80211_configure_filter(local);
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
|
|
@ -793,7 +796,8 @@ static void ieee80211_iface_work(struct work_struct *work)
|
|||
|
||||
__ieee80211_stop_rx_ba_session(
|
||||
sta, tid, WLAN_BACK_RECIPIENT,
|
||||
WLAN_REASON_QSTA_REQUIRE_SETUP);
|
||||
WLAN_REASON_QSTA_REQUIRE_SETUP,
|
||||
true);
|
||||
}
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
} else switch (sdata->vif.type) {
|
||||
|
|
|
|||
|
|
@ -68,15 +68,21 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
|
|||
|
||||
might_sleep();
|
||||
|
||||
if (!key->local->ops->set_key) {
|
||||
ret = -EOPNOTSUPP;
|
||||
if (!key->local->ops->set_key)
|
||||
goto out_unsupported;
|
||||
}
|
||||
|
||||
assert_key_lock(key->local);
|
||||
|
||||
sta = get_sta_for_key(key);
|
||||
|
||||
/*
|
||||
* If this is a per-STA GTK, check if it
|
||||
* is supported; if not, return.
|
||||
*/
|
||||
if (sta && !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE) &&
|
||||
!(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK))
|
||||
goto out_unsupported;
|
||||
|
||||
sdata = key->sdata;
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
sdata = container_of(sdata->bss,
|
||||
|
|
@ -85,31 +91,28 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
|
|||
|
||||
ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
|
||||
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
|
||||
if (ret != -ENOSPC && ret != -EOPNOTSUPP)
|
||||
wiphy_err(key->local->hw.wiphy,
|
||||
"failed to set key (%d, %pM) to hardware (%d)\n",
|
||||
key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
|
||||
|
||||
out_unsupported:
|
||||
if (ret) {
|
||||
switch (key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
/* all of these we can do in software */
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
out_unsupported:
|
||||
switch (key->conf.cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
/* all of these we can do in software */
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
|
||||
|
|
@ -147,6 +150,26 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
|
|||
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
|
||||
}
|
||||
|
||||
void ieee80211_key_removed(struct ieee80211_key_conf *key_conf)
|
||||
{
|
||||
struct ieee80211_key *key;
|
||||
|
||||
key = container_of(key_conf, struct ieee80211_key, conf);
|
||||
|
||||
might_sleep();
|
||||
assert_key_lock(key->local);
|
||||
|
||||
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
|
||||
|
||||
/*
|
||||
* Flush TX path to avoid attempts to use this key
|
||||
* after this function returns. Until then, drivers
|
||||
* must be prepared to handle the key.
|
||||
*/
|
||||
synchronize_rcu();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ieee80211_key_removed);
|
||||
|
||||
static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
|
||||
int idx)
|
||||
{
|
||||
|
|
@ -202,6 +225,7 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta,
|
||||
bool pairwise,
|
||||
struct ieee80211_key *old,
|
||||
struct ieee80211_key *new)
|
||||
{
|
||||
|
|
@ -210,8 +234,14 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
|
|||
if (new)
|
||||
list_add(&new->list, &sdata->key_list);
|
||||
|
||||
if (sta) {
|
||||
rcu_assign_pointer(sta->key, new);
|
||||
if (sta && pairwise) {
|
||||
rcu_assign_pointer(sta->ptk, new);
|
||||
} else if (sta) {
|
||||
if (old)
|
||||
idx = old->conf.keyidx;
|
||||
else
|
||||
idx = new->conf.keyidx;
|
||||
rcu_assign_pointer(sta->gtk[idx], new);
|
||||
} else {
|
||||
WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
|
||||
|
||||
|
|
@ -355,6 +385,7 @@ int ieee80211_key_link(struct ieee80211_key *key,
|
|||
{
|
||||
struct ieee80211_key *old_key;
|
||||
int idx, ret;
|
||||
bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
|
||||
|
||||
BUG_ON(!sdata);
|
||||
BUG_ON(!key);
|
||||
|
|
@ -371,13 +402,6 @@ int ieee80211_key_link(struct ieee80211_key *key,
|
|||
*/
|
||||
if (test_sta_flags(sta, WLAN_STA_WME))
|
||||
key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
|
||||
|
||||
/*
|
||||
* This key is for a specific sta interface,
|
||||
* inform the driver that it should try to store
|
||||
* this key as pairwise key.
|
||||
*/
|
||||
key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
|
||||
} else {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
|
||||
struct sta_info *ap;
|
||||
|
|
@ -399,12 +423,14 @@ int ieee80211_key_link(struct ieee80211_key *key,
|
|||
|
||||
mutex_lock(&sdata->local->key_mtx);
|
||||
|
||||
if (sta)
|
||||
old_key = sta->key;
|
||||
if (sta && pairwise)
|
||||
old_key = sta->ptk;
|
||||
else if (sta)
|
||||
old_key = sta->gtk[idx];
|
||||
else
|
||||
old_key = sdata->keys[idx];
|
||||
|
||||
__ieee80211_key_replace(sdata, sta, old_key, key);
|
||||
__ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
|
||||
__ieee80211_key_destroy(old_key);
|
||||
|
||||
ieee80211_debugfs_key_add(key);
|
||||
|
|
@ -423,7 +449,8 @@ static void __ieee80211_key_free(struct ieee80211_key *key)
|
|||
*/
|
||||
if (key->sdata)
|
||||
__ieee80211_key_replace(key->sdata, key->sta,
|
||||
key, NULL);
|
||||
key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
|
||||
key, NULL);
|
||||
__ieee80211_key_destroy(key);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@
|
|||
#include <linux/rcupdate.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#define NUM_DEFAULT_KEYS 4
|
||||
#define NUM_DEFAULT_MGMT_KEYS 2
|
||||
|
||||
#define WEP_IV_LEN 4
|
||||
#define WEP_ICV_LEN 4
|
||||
#define ALG_TKIP_KEY_LEN 32
|
||||
|
|
|
|||
|
|
@ -201,6 +201,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
|||
sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
sdata->vif.bss_conf.bssid = sdata->vif.addr;
|
||||
else if (sdata->vif.type == NL80211_IFTYPE_WDS)
|
||||
sdata->vif.bss_conf.bssid = NULL;
|
||||
else if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||
sdata->vif.bss_conf.bssid = zero;
|
||||
} else {
|
||||
|
|
@ -211,6 +213,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
|||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
break;
|
||||
default:
|
||||
|
|
@ -295,7 +298,16 @@ static void ieee80211_restart_work(struct work_struct *work)
|
|||
struct ieee80211_local *local =
|
||||
container_of(work, struct ieee80211_local, restart_work);
|
||||
|
||||
/* wait for scan work complete */
|
||||
flush_workqueue(local->workqueue);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
|
||||
"%s called with hardware scan in progress\n", __func__);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
rtnl_lock();
|
||||
ieee80211_scan_cancel(local);
|
||||
ieee80211_reconfig(local);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
|
@ -306,15 +318,6 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
|
|||
|
||||
trace_api_restart_hw(local);
|
||||
|
||||
/* wait for scan work complete */
|
||||
flush_workqueue(local->workqueue);
|
||||
|
||||
WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
|
||||
"%s called with hardware scan in progress\n", __func__);
|
||||
|
||||
if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)))
|
||||
ieee80211_scan_cancel(local);
|
||||
|
||||
/* use this reason, ieee80211_reconfig will unblock it */
|
||||
ieee80211_stop_queues_by_reason(hw,
|
||||
IEEE80211_QUEUE_STOP_REASON_SUSPEND);
|
||||
|
|
@ -329,7 +332,7 @@ static void ieee80211_recalc_smps_work(struct work_struct *work)
|
|||
container_of(work, struct ieee80211_local, recalc_smps);
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
ieee80211_recalc_smps(local, NULL);
|
||||
ieee80211_recalc_smps(local);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
}
|
||||
|
||||
|
|
@ -533,6 +536,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
|
|||
/* set up some defaults */
|
||||
local->hw.queues = 1;
|
||||
local->hw.max_rates = 1;
|
||||
local->hw.max_report_rates = 0;
|
||||
local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
|
||||
local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
|
||||
local->user_power_level = -1;
|
||||
|
|
@ -608,6 +612,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
|
|||
WLAN_CIPHER_SUITE_AES_CMAC
|
||||
};
|
||||
|
||||
if (hw->max_report_rates == 0)
|
||||
hw->max_report_rates = hw->max_rates;
|
||||
|
||||
/*
|
||||
* generic code guarantees at least one band,
|
||||
* set this very early because much code assumes
|
||||
|
|
|
|||
|
|
@ -913,7 +913,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
ieee80211_recalc_smps(local, sdata);
|
||||
ieee80211_recalc_smps(local);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
netif_tx_start_all_queues(sdata->dev);
|
||||
|
|
@ -921,7 +921,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||
bool remove_sta)
|
||||
bool remove_sta, bool tx)
|
||||
{
|
||||
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
|
@ -960,7 +960,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
sta = sta_info_get(sdata, bssid);
|
||||
if (sta) {
|
||||
set_sta_flags(sta, WLAN_STA_BLOCK_BA);
|
||||
ieee80211_sta_tear_down_BA_sessions(sta);
|
||||
ieee80211_sta_tear_down_BA_sessions(sta, tx);
|
||||
}
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
|
||||
|
|
@ -1124,7 +1124,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
|
|||
|
||||
printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid);
|
||||
|
||||
ieee80211_set_disassoc(sdata, true);
|
||||
ieee80211_set_disassoc(sdata, true, true);
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
|
|
@ -1197,7 +1197,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
|
|||
printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
|
||||
sdata->name, bssid, reason_code);
|
||||
|
||||
ieee80211_set_disassoc(sdata, true);
|
||||
ieee80211_set_disassoc(sdata, true, false);
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
|
|
@ -1229,7 +1229,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
|
||||
sdata->name, mgmt->sa, reason_code);
|
||||
|
||||
ieee80211_set_disassoc(sdata, true);
|
||||
ieee80211_set_disassoc(sdata, true, false);
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
ieee80211_recalc_idle(sdata->local);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
|
|
@ -1291,7 +1291,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
|
|||
|
||||
rates = 0;
|
||||
basic_rates = 0;
|
||||
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
|
||||
sband = local->hw.wiphy->bands[wk->chan->band];
|
||||
|
||||
for (i = 0; i < elems.supp_rates_len; i++) {
|
||||
int rate = (elems.supp_rates[i] & 0x7f) * 5;
|
||||
|
|
@ -1327,11 +1327,11 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
|
|||
}
|
||||
}
|
||||
|
||||
sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
|
||||
sta->sta.supp_rates[wk->chan->band] = rates;
|
||||
sdata->vif.bss_conf.basic_rates = basic_rates;
|
||||
|
||||
/* cf. IEEE 802.11 9.2.12 */
|
||||
if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
|
||||
if (wk->chan->band == IEEE80211_BAND_2GHZ &&
|
||||
have_higher_than_11mbit)
|
||||
sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
|
||||
else
|
||||
|
|
@ -1639,7 +1639,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len,
|
||||
ifmgd->aid);
|
||||
|
||||
if (ncrc != ifmgd->beacon_crc) {
|
||||
if (ncrc != ifmgd->beacon_crc || !ifmgd->beacon_crc_valid) {
|
||||
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
|
||||
true);
|
||||
|
||||
|
|
@ -1670,9 +1670,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
}
|
||||
|
||||
if (ncrc == ifmgd->beacon_crc)
|
||||
if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
|
||||
return;
|
||||
ifmgd->beacon_crc = ncrc;
|
||||
ifmgd->beacon_crc_valid = true;
|
||||
|
||||
if (elems.erp_info && elems.erp_info_len >= 1) {
|
||||
erp_valid = true;
|
||||
|
|
@ -1879,7 +1880,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
|
|||
printk(KERN_DEBUG "No probe response from AP %pM"
|
||||
" after %dms, disconnecting.\n",
|
||||
bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ);
|
||||
ieee80211_set_disassoc(sdata, true);
|
||||
ieee80211_set_disassoc(sdata, true, true);
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
|
|
@ -2203,7 +2204,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
}
|
||||
|
||||
/* Trying to reassociate - clear previous association state */
|
||||
ieee80211_set_disassoc(sdata, true);
|
||||
ieee80211_set_disassoc(sdata, true, false);
|
||||
}
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
|
||||
|
|
@ -2214,6 +2215,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
|||
ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
|
||||
ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
|
||||
|
||||
ifmgd->beacon_crc_valid = false;
|
||||
|
||||
for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
|
||||
if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
|
||||
req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
|
||||
|
|
@ -2315,7 +2318,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
memcpy(bssid, req->bss->bssid, ETH_ALEN);
|
||||
if (ifmgd->associated == req->bss) {
|
||||
ieee80211_set_disassoc(sdata, false);
|
||||
ieee80211_set_disassoc(sdata, false, true);
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
assoc_bss = true;
|
||||
} else {
|
||||
|
|
@ -2398,7 +2401,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
sdata->name, req->bss->bssid, req->reason_code);
|
||||
|
||||
memcpy(bssid, req->bss->bssid, ETH_ALEN);
|
||||
ieee80211_set_disassoc(sdata, false);
|
||||
ieee80211_set_disassoc(sdata, false, true);
|
||||
|
||||
mutex_unlock(&ifmgd->mtx);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
|
|||
struct ieee80211_sub_if_data *sdata;
|
||||
struct sta_info *sta;
|
||||
|
||||
if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)))
|
||||
ieee80211_scan_cancel(local);
|
||||
ieee80211_scan_cancel(local);
|
||||
|
||||
ieee80211_stop_queues_by_reason(hw,
|
||||
IEEE80211_QUEUE_STOP_REASON_SUSPEND);
|
||||
|
|
@ -46,7 +45,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
|
|||
list_for_each_entry(sta, &local->sta_list, list) {
|
||||
if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
|
||||
set_sta_flags(sta, WLAN_STA_BLOCK_BA);
|
||||
ieee80211_sta_tear_down_BA_sessions(sta);
|
||||
ieee80211_sta_tear_down_BA_sessions(sta, true);
|
||||
}
|
||||
|
||||
if (sta->uploaded) {
|
||||
|
|
|
|||
|
|
@ -819,6 +819,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
|
|||
if (unlikely((ieee80211_is_data(hdr->frame_control) ||
|
||||
ieee80211_is_pspoll(hdr->frame_control)) &&
|
||||
rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
|
||||
rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
|
||||
(!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) {
|
||||
if ((!ieee80211_has_fromds(hdr->frame_control) &&
|
||||
!ieee80211_has_tods(hdr->frame_control) &&
|
||||
|
|
@ -845,7 +846,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
|||
int keyidx;
|
||||
int hdrlen;
|
||||
ieee80211_rx_result result = RX_DROP_UNUSABLE;
|
||||
struct ieee80211_key *stakey = NULL;
|
||||
struct ieee80211_key *sta_ptk = NULL;
|
||||
int mmie_keyidx = -1;
|
||||
__le16 fc;
|
||||
|
||||
|
|
@ -887,15 +888,15 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
|||
rx->key = NULL;
|
||||
|
||||
if (rx->sta)
|
||||
stakey = rcu_dereference(rx->sta->key);
|
||||
sta_ptk = rcu_dereference(rx->sta->ptk);
|
||||
|
||||
fc = hdr->frame_control;
|
||||
|
||||
if (!ieee80211_has_protected(fc))
|
||||
mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
|
||||
|
||||
if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
|
||||
rx->key = stakey;
|
||||
if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) {
|
||||
rx->key = sta_ptk;
|
||||
if ((status->flag & RX_FLAG_DECRYPTED) &&
|
||||
(status->flag & RX_FLAG_IV_STRIPPED))
|
||||
return RX_CONTINUE;
|
||||
|
|
@ -911,7 +912,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
|||
if (mmie_keyidx < NUM_DEFAULT_KEYS ||
|
||||
mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
|
||||
return RX_DROP_MONITOR; /* unexpected BIP keyidx */
|
||||
rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
|
||||
if (rx->sta)
|
||||
rx->key = rcu_dereference(rx->sta->gtk[mmie_keyidx]);
|
||||
if (!rx->key)
|
||||
rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
|
||||
} else if (!ieee80211_has_protected(fc)) {
|
||||
/*
|
||||
* The frame was not protected, so skip decryption. However, we
|
||||
|
|
@ -954,17 +958,25 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
|
|||
skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
|
||||
keyidx = keyid >> 6;
|
||||
|
||||
rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
|
||||
/* check per-station GTK first, if multicast packet */
|
||||
if (is_multicast_ether_addr(hdr->addr1) && rx->sta)
|
||||
rx->key = rcu_dereference(rx->sta->gtk[keyidx]);
|
||||
|
||||
/*
|
||||
* RSNA-protected unicast frames should always be sent with
|
||||
* pairwise or station-to-station keys, but for WEP we allow
|
||||
* using a key index as well.
|
||||
*/
|
||||
if (rx->key && rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 &&
|
||||
rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 &&
|
||||
!is_multicast_ether_addr(hdr->addr1))
|
||||
rx->key = NULL;
|
||||
/* if not found, try default key */
|
||||
if (!rx->key) {
|
||||
rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
|
||||
|
||||
/*
|
||||
* RSNA-protected unicast frames should always be
|
||||
* sent with pairwise or station-to-station keys,
|
||||
* but for WEP we allow using a key index as well.
|
||||
*/
|
||||
if (rx->key &&
|
||||
rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP40 &&
|
||||
rx->key->conf.cipher != WLAN_CIPHER_SUITE_WEP104 &&
|
||||
!is_multicast_ether_addr(hdr->addr1))
|
||||
rx->key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (rx->key) {
|
||||
|
|
|
|||
|
|
@ -249,12 +249,12 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
||||
static bool __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
|
||||
bool was_hw_scan)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
bool was_hw_scan;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
/*
|
||||
* It's ok to abort a not-yet-running scan (that
|
||||
|
|
@ -265,17 +265,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
|||
if (WARN_ON(!local->scanning && !aborted))
|
||||
aborted = true;
|
||||
|
||||
if (WARN_ON(!local->scan_req)) {
|
||||
mutex_unlock(&local->mtx);
|
||||
return;
|
||||
}
|
||||
if (WARN_ON(!local->scan_req))
|
||||
return false;
|
||||
|
||||
was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
|
||||
if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
|
||||
ieee80211_queue_delayed_work(&local->hw,
|
||||
&local->scan_work, 0);
|
||||
mutex_unlock(&local->mtx);
|
||||
return;
|
||||
int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req);
|
||||
if (rc == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
kfree(local->hw_scan_req);
|
||||
|
|
@ -289,23 +285,25 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
|||
local->scanning = 0;
|
||||
local->scan_channel = NULL;
|
||||
|
||||
/* we only have to protect scan_req and hw/sw scan */
|
||||
mutex_unlock(&local->mtx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __ieee80211_scan_completed_finish(struct ieee80211_hw *hw,
|
||||
bool was_hw_scan)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
|
||||
if (was_hw_scan)
|
||||
goto done;
|
||||
if (!was_hw_scan) {
|
||||
ieee80211_configure_filter(local);
|
||||
drv_sw_scan_complete(local);
|
||||
ieee80211_offchannel_return(local, true);
|
||||
}
|
||||
|
||||
ieee80211_configure_filter(local);
|
||||
|
||||
drv_sw_scan_complete(local);
|
||||
|
||||
ieee80211_offchannel_return(local, true);
|
||||
|
||||
done:
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
ieee80211_mlme_notify_scan_completed(local);
|
||||
ieee80211_ibss_notify_scan_completed(local);
|
||||
ieee80211_mesh_notify_scan_completed(local);
|
||||
|
|
@ -366,6 +364,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
int rc;
|
||||
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
if (local->scan_req)
|
||||
return -EBUSY;
|
||||
|
||||
|
|
@ -447,8 +447,8 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
|
|||
return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
|
||||
}
|
||||
|
||||
static int ieee80211_scan_state_decision(struct ieee80211_local *local,
|
||||
unsigned long *next_delay)
|
||||
static void ieee80211_scan_state_decision(struct ieee80211_local *local,
|
||||
unsigned long *next_delay)
|
||||
{
|
||||
bool associated = false;
|
||||
bool tx_empty = true;
|
||||
|
|
@ -458,12 +458,6 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
|
|||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_channel *next_chan;
|
||||
|
||||
/* if no more bands/channels left, complete scan and advance to the idle state */
|
||||
if (local->scan_channel_idx >= local->scan_req->n_channels) {
|
||||
__ieee80211_scan_completed(&local->hw, false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* check if at least one STA interface is associated,
|
||||
* check if at least one STA interface has pending tx frames
|
||||
|
|
@ -535,7 +529,6 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
|
|||
}
|
||||
|
||||
*next_delay = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
|
||||
|
|
@ -651,28 +644,17 @@ void ieee80211_scan_work(struct work_struct *work)
|
|||
container_of(work, struct ieee80211_local, scan_work.work);
|
||||
struct ieee80211_sub_if_data *sdata = local->scan_sdata;
|
||||
unsigned long next_delay = 0;
|
||||
|
||||
if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) {
|
||||
bool aborted;
|
||||
|
||||
aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning);
|
||||
__ieee80211_scan_completed(&local->hw, aborted);
|
||||
return;
|
||||
}
|
||||
bool aborted, hw_scan, finish;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
if (!sdata || !local->scan_req) {
|
||||
mutex_unlock(&local->mtx);
|
||||
return;
|
||||
|
||||
if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) {
|
||||
aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning);
|
||||
goto out_complete;
|
||||
}
|
||||
|
||||
if (local->hw_scan_req) {
|
||||
int rc = drv_hw_scan(local, sdata, local->hw_scan_req);
|
||||
mutex_unlock(&local->mtx);
|
||||
if (rc)
|
||||
__ieee80211_scan_completed(&local->hw, true);
|
||||
return;
|
||||
}
|
||||
if (!sdata || !local->scan_req)
|
||||
goto out;
|
||||
|
||||
if (local->scan_req && !local->scanning) {
|
||||
struct cfg80211_scan_request *req = local->scan_req;
|
||||
|
|
@ -682,21 +664,21 @@ void ieee80211_scan_work(struct work_struct *work)
|
|||
local->scan_sdata = NULL;
|
||||
|
||||
rc = __ieee80211_start_scan(sdata, req);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
if (rc)
|
||||
__ieee80211_scan_completed(&local->hw, true);
|
||||
return;
|
||||
if (rc) {
|
||||
/* need to complete scan in cfg80211 */
|
||||
local->scan_req = req;
|
||||
aborted = true;
|
||||
goto out_complete;
|
||||
} else
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
/*
|
||||
* Avoid re-scheduling when the sdata is going away.
|
||||
*/
|
||||
if (!ieee80211_sdata_running(sdata)) {
|
||||
__ieee80211_scan_completed(&local->hw, true);
|
||||
return;
|
||||
aborted = true;
|
||||
goto out_complete;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -706,8 +688,12 @@ void ieee80211_scan_work(struct work_struct *work)
|
|||
do {
|
||||
switch (local->next_scan_state) {
|
||||
case SCAN_DECISION:
|
||||
if (ieee80211_scan_state_decision(local, &next_delay))
|
||||
return;
|
||||
/* if no more bands/channels left, complete scan */
|
||||
if (local->scan_channel_idx >= local->scan_req->n_channels) {
|
||||
aborted = false;
|
||||
goto out_complete;
|
||||
}
|
||||
ieee80211_scan_state_decision(local, &next_delay);
|
||||
break;
|
||||
case SCAN_SET_CHANNEL:
|
||||
ieee80211_scan_state_set_channel(local, &next_delay);
|
||||
|
|
@ -725,6 +711,19 @@ void ieee80211_scan_work(struct work_struct *work)
|
|||
} while (next_delay == 0);
|
||||
|
||||
ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay);
|
||||
mutex_unlock(&local->mtx);
|
||||
return;
|
||||
|
||||
out_complete:
|
||||
hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
|
||||
finish = __ieee80211_scan_completed(&local->hw, aborted, hw_scan);
|
||||
mutex_unlock(&local->mtx);
|
||||
if (finish)
|
||||
__ieee80211_scan_completed_finish(&local->hw, hw_scan);
|
||||
return;
|
||||
|
||||
out:
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
|
||||
|
|
@ -786,21 +785,40 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only call this function when a scan can't be queued -- under RTNL.
|
||||
*/
|
||||
void ieee80211_scan_cancel(struct ieee80211_local *local)
|
||||
{
|
||||
bool abortscan;
|
||||
|
||||
cancel_delayed_work_sync(&local->scan_work);
|
||||
bool finish = false;
|
||||
|
||||
/*
|
||||
* Only call this function when a scan can't be
|
||||
* queued -- mostly at suspend under RTNL.
|
||||
* We are only canceling software scan, or deferred scan that was not
|
||||
* yet really started (see __ieee80211_start_scan ).
|
||||
*
|
||||
* Regarding hardware scan:
|
||||
* - we can not call __ieee80211_scan_completed() as when
|
||||
* SCAN_HW_SCANNING bit is set this function change
|
||||
* local->hw_scan_req to operate on 5G band, what race with
|
||||
* driver which can use local->hw_scan_req
|
||||
*
|
||||
* - we can not cancel scan_work since driver can schedule it
|
||||
* by ieee80211_scan_completed(..., true) to finish scan
|
||||
*
|
||||
* Hence low lever driver is responsible for canceling HW scan.
|
||||
*/
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
|
||||
(!local->scanning && local->scan_req);
|
||||
abortscan = local->scan_req && !test_bit(SCAN_HW_SCANNING, &local->scanning);
|
||||
if (abortscan)
|
||||
finish = __ieee80211_scan_completed(&local->hw, true, false);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
if (abortscan)
|
||||
__ieee80211_scan_completed(&local->hw, true);
|
||||
if (abortscan) {
|
||||
/* The scan is canceled, but stop work from being pending */
|
||||
cancel_delayed_work_sync(&local->scan_work);
|
||||
}
|
||||
if (finish)
|
||||
__ieee80211_scan_completed_finish(&local->hw, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -616,7 +616,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
|
|||
struct ieee80211_sub_if_data *sdata;
|
||||
struct sk_buff *skb;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
might_sleep();
|
||||
|
||||
|
|
@ -633,7 +633,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
|
|||
* will be sufficient.
|
||||
*/
|
||||
set_sta_flags(sta, WLAN_STA_BLOCK_BA);
|
||||
ieee80211_sta_tear_down_BA_sessions(sta);
|
||||
ieee80211_sta_tear_down_BA_sessions(sta, true);
|
||||
|
||||
spin_lock_irqsave(&local->sta_lock, flags);
|
||||
ret = sta_info_hash_del(local, sta);
|
||||
|
|
@ -644,10 +644,10 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (sta->key) {
|
||||
ieee80211_key_free(local, sta->key);
|
||||
WARN_ON(sta->key);
|
||||
}
|
||||
for (i = 0; i < NUM_DEFAULT_KEYS; i++)
|
||||
ieee80211_key_free(local, sta->gtk[i]);
|
||||
if (sta->ptk)
|
||||
ieee80211_key_free(local, sta->ptk);
|
||||
|
||||
sta->dead = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ enum ieee80211_sta_info_flags {
|
|||
* @dialog_token: dialog token for aggregation session
|
||||
* @state: session state (see above)
|
||||
* @stop_initiator: initiator of a session stop
|
||||
* @tx_stop: TX DelBA frame when stopping
|
||||
*
|
||||
* This structure is protected by RCU and the per-station
|
||||
* spinlock. Assignments to the array holding it must hold
|
||||
|
|
@ -95,6 +96,7 @@ struct tid_ampdu_tx {
|
|||
unsigned long state;
|
||||
u8 dialog_token;
|
||||
u8 stop_initiator;
|
||||
bool tx_stop;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -197,7 +199,8 @@ enum plink_state {
|
|||
* @hnext: hash table linked list pointer
|
||||
* @local: pointer to the global information
|
||||
* @sdata: virtual interface this station belongs to
|
||||
* @key: peer key negotiated with this station, if any
|
||||
* @ptk: peer key negotiated with this station, if any
|
||||
* @gtk: group keys negotiated with this station, if any
|
||||
* @rate_ctrl: rate control algorithm reference
|
||||
* @rate_ctrl_priv: rate control private per-STA pointer
|
||||
* @last_tx_rate: rate used for last transmit, to report to userspace as
|
||||
|
|
@ -252,7 +255,8 @@ struct sta_info {
|
|||
struct sta_info *hnext;
|
||||
struct ieee80211_local *local;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_key *key;
|
||||
struct ieee80211_key *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
|
||||
struct ieee80211_key *ptk;
|
||||
struct rate_control_ref *rate_ctrl;
|
||||
void *rate_ctrl_priv;
|
||||
spinlock_t lock;
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
|
||||
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||
/* the HW cannot have attempted that rate */
|
||||
if (i >= hw->max_rates) {
|
||||
if (i >= hw->max_report_rates) {
|
||||
info->status.rates[i].idx = -1;
|
||||
info->status.rates[i].count = 0;
|
||||
} else if (info->status.rates[i].idx >= 0) {
|
||||
|
|
@ -377,7 +377,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
skb2 = skb_clone(skb, GFP_ATOMIC);
|
||||
if (skb2) {
|
||||
skb2->dev = prev_dev;
|
||||
netif_receive_skb(skb2);
|
||||
netif_rx(skb2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -386,7 +386,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||
}
|
||||
if (prev_dev) {
|
||||
skb->dev = prev_dev;
|
||||
netif_receive_skb(skb);
|
||||
netif_rx(skb);
|
||||
skb = NULL;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
|
|
|||
|
|
@ -273,6 +273,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
|
|||
*/
|
||||
return TX_DROP;
|
||||
|
||||
if (tx->sdata->vif.type == NL80211_IFTYPE_WDS)
|
||||
return TX_CONTINUE;
|
||||
|
||||
if (tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
|
||||
return TX_CONTINUE;
|
||||
|
||||
|
|
@ -529,7 +532,7 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
|
|||
|
||||
if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
|
||||
tx->key = NULL;
|
||||
else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
|
||||
else if (tx->sta && (key = rcu_dereference(tx->sta->ptk)))
|
||||
tx->key = key;
|
||||
else if (ieee80211_is_mgmt(hdr->frame_control) &&
|
||||
is_multicast_ether_addr(hdr->addr1) &&
|
||||
|
|
|
|||
|
|
@ -1221,7 +1221,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
|||
mutex_lock(&local->sta_mtx);
|
||||
|
||||
list_for_each_entry(sta, &local->sta_list, list) {
|
||||
ieee80211_sta_tear_down_BA_sessions(sta);
|
||||
ieee80211_sta_tear_down_BA_sessions(sta, true);
|
||||
clear_sta_flags(sta, WLAN_STA_BLOCK_BA);
|
||||
}
|
||||
|
||||
|
|
@ -1297,16 +1297,12 @@ static int check_mgd_smps(struct ieee80211_if_managed *ifmgd,
|
|||
}
|
||||
|
||||
/* must hold iflist_mtx */
|
||||
void ieee80211_recalc_smps(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *forsdata)
|
||||
void ieee80211_recalc_smps(struct ieee80211_local *local)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF;
|
||||
int count = 0;
|
||||
|
||||
if (forsdata)
|
||||
lockdep_assert_held(&forsdata->u.mgd.mtx);
|
||||
|
||||
lockdep_assert_held(&local->iflist_mtx);
|
||||
|
||||
/*
|
||||
|
|
@ -1324,18 +1320,8 @@ void ieee80211_recalc_smps(struct ieee80211_local *local,
|
|||
continue;
|
||||
if (sdata->vif.type != NL80211_IFTYPE_STATION)
|
||||
goto set;
|
||||
if (sdata != forsdata) {
|
||||
/*
|
||||
* This nested is ok -- we are holding the iflist_mtx
|
||||
* so can't get here twice or so. But it's required
|
||||
* since normally we acquire it first and then the
|
||||
* iflist_mtx.
|
||||
*/
|
||||
mutex_lock_nested(&sdata->u.mgd.mtx, SINGLE_DEPTH_NESTING);
|
||||
count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
|
||||
mutex_unlock(&sdata->u.mgd.mtx);
|
||||
} else
|
||||
count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
|
||||
|
||||
count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
|
||||
|
||||
if (count > 1) {
|
||||
smps_mode = IEEE80211_SMPS_OFF;
|
||||
|
|
|
|||
Loading…
Reference in a new issue